@mycadet/assistant 0.12.11 → 0.13.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/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
- package/node_modules/@mycadet/gateway-client/src/gateway-ipc-contracts.ts +0 -20
- package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +2 -2
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +2 -2
- package/openapi.yaml +2 -708
- package/package.json +2 -3
- package/scripts/sync-web-search-catalog.ts +1 -2
- package/src/__tests__/cloud-profile-guard.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +6 -38
- package/src/__tests__/conversation-queue.test.ts +45 -6
- package/src/__tests__/db-readiness-http-gate.test.ts +0 -6
- package/src/__tests__/persist-onboarding-artifacts.test.ts +0 -1
- package/src/__tests__/persona-resolver.test.ts +0 -51
- package/src/__tests__/provider-cloud-proxy-integration.test.ts +2 -110
- package/src/__tests__/run-due-schedules.test.ts +0 -4
- package/src/__tests__/schedule-store.test.ts +0 -12
- package/src/__tests__/stt-stream-session.test.ts +4 -4
- package/src/__tests__/telephony-tts-guard.test.ts +2 -50
- package/src/__tests__/voice-config-update.test.ts +12 -167
- package/src/__tests__/web-search-catalog-parity.test.ts +0 -2
- package/src/__tests__/workspace-migration-130-speech-mode-to-provider.test.ts +9 -7
- package/src/__tests__/workspace-migration-132-web-search-mode-to-provider.test.ts +6 -6
- package/src/calls/__tests__/voice-session-bridge.test.ts +1 -4
- package/src/calls/resolve-call-tts-provider.ts +6 -25
- package/src/calls/telephony-credential-preflight.ts +0 -10
- package/src/calls/telephony-tts-capability.ts +1 -17
- package/src/cli/commands/tts.ts +1 -2
- package/src/cli/index.help.ts +0 -2
- package/src/cli/program.ts +0 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +4 -42
- package/src/config/schemas/__tests__/stt.test.ts +10 -14
- package/src/config/schemas/services.ts +5 -6
- package/src/config/schemas/stt.ts +1 -3
- package/src/config/schemas/tts.ts +1 -30
- package/src/daemon/daemon-readiness.ts +4 -29
- package/src/daemon/lifecycle.ts +0 -31
- package/src/daemon/providers-setup.ts +0 -8
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -1
- package/src/heartbeat/heartbeat-service.ts +1 -66
- package/src/ipc/__tests__/db-readiness-ipc-gate.test.ts +1 -9
- package/src/live-voice/__tests__/live-voice-credential-preflight.test.ts +0 -44
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +4 -6
- package/src/live-voice/__tests__/live-voice-stt.test.ts +1 -1
- package/src/live-voice/live-voice-credential-preflight.ts +9 -33
- package/src/live-voice/live-voice-session.ts +10 -6
- package/src/live-voice/live-voice-tts.ts +1 -8
- package/src/plugins/defaults/memory/worker.ts +3 -3
- package/src/prompts/persona-resolver.ts +0 -35
- package/src/providers/__tests__/search-provider-catalog.test.ts +5 -8
- package/src/providers/__tests__/voice-error-copy.test.ts +9 -10
- package/src/providers/search-provider-catalog.ts +7 -39
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +3 -47
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +6 -372
- package/src/providers/speech-to-text/provider-catalog.ts +2 -73
- package/src/providers/speech-to-text/resolve.ts +3 -120
- package/src/runtime/http-router-types.ts +1 -3
- package/src/runtime/http-server.ts +1 -1
- package/src/runtime/routes/__tests__/tts-routes.test.ts +2 -6
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +7 -7
- package/src/runtime/routes/index.ts +0 -4
- package/src/runtime/routes/live-voice-routes.test.ts +4 -11
- package/src/runtime/routes/live-voice-routes.ts +8 -11
- package/src/runtime/routes/secret-routes.ts +0 -6
- package/src/runtime/routes/tts-routes.ts +0 -38
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1 -7
- package/src/schedule/__tests__/worker-mcp-readiness.test.ts +0 -4
- package/src/schedule/schedule-store.ts +0 -7
- package/src/schedule/scheduler.ts +0 -5
- package/src/schedule/worker.ts +1 -1
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +2 -10
- package/src/stt/daemon-batch-transcriber.ts +4 -38
- package/src/stt/types.ts +1 -9
- package/src/tools/network/__tests__/web-search.test.ts +3 -250
- package/src/tools/network/web-search.ts +4 -165
- package/src/tts/__tests__/provider-resolution.test.ts +0 -5
- package/src/tts/provider-catalog.ts +0 -4
- package/src/tts/types.ts +0 -1
- package/src/__tests__/cloud-speech-defaults.test.ts +0 -330
- package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1708
- package/src/__tests__/migration-export-http.test.ts +0 -557
- package/src/__tests__/migration-export-streaming.test.ts +0 -350
- package/src/__tests__/migration-export-to-gcs.test.ts +0 -706
- package/src/__tests__/migration-import-commit-http.test.ts +0 -1176
- package/src/__tests__/migration-import-from-gcs.test.ts +0 -534
- package/src/__tests__/migration-import-from-path.test.ts +0 -324
- package/src/__tests__/migration-import-from-url.test.ts +0 -588
- package/src/__tests__/migration-import-preflight-http.test.ts +0 -739
- package/src/__tests__/migration-jobs-status.test.ts +0 -139
- package/src/__tests__/migration-parity-persistence.test.ts +0 -1891
- package/src/__tests__/migration-transport.test.ts +0 -1089
- package/src/__tests__/migration-validate-http.test.ts +0 -634
- package/src/__tests__/migration-wizard.test.ts +0 -1395
- package/src/__tests__/rebind-secrets-screen.test.ts +0 -876
- package/src/__tests__/sanitize-config-for-transfer.test.ts +0 -259
- package/src/__tests__/transfer-progress-screen.test.ts +0 -1217
- package/src/__tests__/validation-results-screen.test.ts +0 -1130
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +0 -147
- package/src/background-wake/background-wake-routes.test.ts +0 -906
- package/src/background-wake/cloud-client.test.ts +0 -328
- package/src/background-wake/cloud-client.ts +0 -196
- package/src/background-wake/next-wake.test.ts +0 -335
- package/src/background-wake/next-wake.ts +0 -188
- package/src/background-wake/publisher.ts +0 -93
- package/src/background-wake/wake-intent-hooks.test.ts +0 -234
- package/src/cli/commands/__tests__/backup.test.ts +0 -363
- package/src/cli/commands/backup.help.ts +0 -180
- package/src/cli/commands/backup.ts +0 -398
- package/src/cloud/cloud-speech.test.ts +0 -335
- package/src/cloud/cloud-speech.ts +0 -300
- package/src/config/cloud-speech-defaults.ts +0 -300
- package/src/config/sanitize-for-transfer.ts +0 -111
- package/src/live-voice/__tests__/live-voice-cloud-speech-fallback.test.ts +0 -250
- package/src/providers/speech-to-text/__tests__/cadet-cloud-realtime.test.ts +0 -457
- package/src/providers/speech-to-text/__tests__/cadet-cloud.test.ts +0 -271
- package/src/providers/speech-to-text/__tests__/cadet-speech-relay-connection.test.ts +0 -126
- package/src/providers/speech-to-text/cadet-cloud-flux-realtime.ts +0 -309
- package/src/providers/speech-to-text/cadet-cloud-realtime.ts +0 -315
- package/src/providers/speech-to-text/cadet-cloud.ts +0 -108
- package/src/providers/speech-to-text/cadet-speech-relay-connection.ts +0 -176
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +0 -254
- package/src/runtime/migrations/__tests__/job-registry.test.ts +0 -346
- package/src/runtime/migrations/__tests__/origin-mode.test.ts +0 -62
- package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +0 -184
- package/src/runtime/migrations/__tests__/staged-import-path.test.ts +0 -110
- package/src/runtime/migrations/__tests__/v1-test-helpers.ts +0 -112
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +0 -285
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +0 -126
- package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +0 -253
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +0 -208
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +0 -485
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +0 -349
- package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +0 -196
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +0 -551
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +0 -428
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +0 -220
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +0 -1823
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +0 -598
- package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +0 -463
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -538
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +0 -515
- package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +0 -453
- package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +0 -319
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +0 -240
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +0 -473
- package/src/runtime/migrations/gcs-signed-url.ts +0 -190
- package/src/runtime/migrations/job-registry.ts +0 -297
- package/src/runtime/migrations/migration-transport.ts +0 -612
- package/src/runtime/migrations/migration-wizard.ts +0 -747
- package/src/runtime/migrations/origin-mode.ts +0 -42
- package/src/runtime/migrations/rebind-secrets-screen.ts +0 -412
- package/src/runtime/migrations/staged-import-path.ts +0 -116
- package/src/runtime/migrations/transfer-progress-screen.ts +0 -323
- package/src/runtime/migrations/validation-results-screen.ts +0 -469
- package/src/runtime/migrations/vbundle-builder.ts +0 -1382
- package/src/runtime/migrations/vbundle-import-analyzer.ts +0 -405
- package/src/runtime/migrations/vbundle-import-policy.ts +0 -241
- package/src/runtime/migrations/vbundle-importer.ts +0 -826
- package/src/runtime/migrations/vbundle-metadata-merge.ts +0 -113
- package/src/runtime/migrations/vbundle-streaming-importer.ts +0 -2844
- package/src/runtime/migrations/vbundle-streaming-validator.ts +0 -426
- package/src/runtime/migrations/vbundle-tar-stream.ts +0 -244
- package/src/runtime/migrations/vbundle-validator.ts +0 -724
- package/src/runtime/routes/__tests__/migration-cadet-metadata-reconcile.test.ts +0 -227
- package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +0 -54
- package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +0 -70
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +0 -257
- package/src/runtime/routes/background-wake-routes.ts +0 -387
- package/src/runtime/routes/migration-routes.ts +0 -2584
- package/src/tools/network/__tests__/cloud-search-proxy.test.ts +0 -282
- package/src/tools/network/cloud-search-proxy.ts +0 -211
- package/src/tts/__tests__/cadet-provider.test.ts +0 -253
- package/src/tts/providers/cadet-provider.ts +0 -244
- package/src/types/tar-stream.d.ts +0 -66
|
@@ -18,7 +18,6 @@ export const VALID_STT_PROVIDERS = [
|
|
|
18
18
|
"google-gemini",
|
|
19
19
|
"openai-whisper",
|
|
20
20
|
"xai",
|
|
21
|
-
"cadet",
|
|
22
21
|
] as const;
|
|
23
22
|
|
|
24
23
|
/**
|
|
@@ -183,8 +182,7 @@ export { STT_ROLE_REQUIREMENTS, STT_ROLES, type SttRole };
|
|
|
183
182
|
/**
|
|
184
183
|
* Canonical STT service configuration.
|
|
185
184
|
*
|
|
186
|
-
* `provider` is the only axis:
|
|
187
|
-
* billed to Cadet credits; any other provider uses the user's own API key.
|
|
185
|
+
* `provider` is the only axis: every provider uses the user's own API key.
|
|
188
186
|
*/
|
|
189
187
|
export const SttServiceSchema = z
|
|
190
188
|
.object({
|
|
@@ -271,31 +271,6 @@ export const TtsXaiProviderConfigSchema = z
|
|
|
271
271
|
|
|
272
272
|
export type TtsXaiProviderConfig = z.infer<typeof TtsXaiProviderConfigSchema>;
|
|
273
273
|
|
|
274
|
-
/**
|
|
275
|
-
* Cadet Cloud provider configuration under `services.tts.providers`.
|
|
276
|
-
*/
|
|
277
|
-
const TtsCadetProviderConfigSchema = z
|
|
278
|
-
.object({
|
|
279
|
-
model: z
|
|
280
|
-
.string()
|
|
281
|
-
.optional()
|
|
282
|
-
.describe(
|
|
283
|
-
"Managed TTS voice model (e.g. aura-2-thalia-en). Unset means the cloud's default voice. The cloud rejects voices it does not offer.",
|
|
284
|
-
),
|
|
285
|
-
languageVoices: languageVoicesSchema(
|
|
286
|
-
"cadet",
|
|
287
|
-
"values are managed TTS voice models (e.g. aura-2-thalia-en) and must " +
|
|
288
|
-
"be voices offered by the cloud rate card: an unpriced model is " +
|
|
289
|
-
"rejected by the relay (missing_price), the same contract as " +
|
|
290
|
-
"services.tts.providers.cadet.model.",
|
|
291
|
-
),
|
|
292
|
-
})
|
|
293
|
-
.describe("Cadet Cloud provider configuration under services.tts");
|
|
294
|
-
|
|
295
|
-
export type TtsCadetProviderConfig = z.infer<
|
|
296
|
-
typeof TtsCadetProviderConfigSchema
|
|
297
|
-
>;
|
|
298
|
-
|
|
299
274
|
const TtsProvidersSchema = z.object({
|
|
300
275
|
elevenlabs: TtsElevenLabsProviderConfigSchema.default(
|
|
301
276
|
TtsElevenLabsProviderConfigSchema.parse({}),
|
|
@@ -307,9 +282,6 @@ const TtsProvidersSchema = z.object({
|
|
|
307
282
|
TtsDeepgramProviderConfigSchema.parse({}),
|
|
308
283
|
),
|
|
309
284
|
xai: TtsXaiProviderConfigSchema.default(TtsXaiProviderConfigSchema.parse({})),
|
|
310
|
-
cadet: TtsCadetProviderConfigSchema.default(
|
|
311
|
-
TtsCadetProviderConfigSchema.parse({}),
|
|
312
|
-
),
|
|
313
285
|
});
|
|
314
286
|
export type TtsProviders = z.infer<typeof TtsProvidersSchema>;
|
|
315
287
|
|
|
@@ -344,8 +316,7 @@ for (const id of schemaKeys) {
|
|
|
344
316
|
/**
|
|
345
317
|
* Canonical TTS service configuration.
|
|
346
318
|
*
|
|
347
|
-
* `provider` is the only axis:
|
|
348
|
-
* billed to Cadet credits; any other provider uses the user's own API key.
|
|
319
|
+
* `provider` is the only axis: every provider uses the user's own API key.
|
|
349
320
|
*/
|
|
350
321
|
export const TtsServiceSchema = z
|
|
351
322
|
.object({
|
|
@@ -64,32 +64,13 @@ export const DB_MIGRATION_READINESS_EXEMPT_OPERATIONS: ReadonlySet<string> =
|
|
|
64
64
|
/**
|
|
65
65
|
* The migration-repair surface: operations additionally allowed while DB
|
|
66
66
|
* migrations are in the terminal FAILED state — and only then, never while
|
|
67
|
-
* they are still running.
|
|
68
|
-
*
|
|
69
|
-
* rollback/restore path), so gating them in that state would make recovery
|
|
70
|
-
* impossible. Contains both the HTTP endpoint form and the IPC operationId
|
|
67
|
+
* they are still running. Rollback repairs a failed migration without racing
|
|
68
|
+
* an active migration runner. Contains both the HTTP endpoint form and the IPC operationId
|
|
71
69
|
* form of each route. Bypasses only the migration gate — route policies
|
|
72
70
|
* (gateway-principal scopes, guardian auth) still apply.
|
|
73
71
|
*/
|
|
74
72
|
export const DB_MIGRATION_FAILED_STATE_EXEMPT_OPERATIONS: ReadonlySet<string> =
|
|
75
|
-
new Set([
|
|
76
|
-
"admin/rollback-migrations",
|
|
77
|
-
"admin_rollbackmigrations_post",
|
|
78
|
-
"migrations/import",
|
|
79
|
-
"migrations_import_post",
|
|
80
|
-
// Restore has three transports; all must stay repair-capable. The
|
|
81
|
-
// preflights are read-only analysis; the GCS import is the cloud
|
|
82
|
-
// platform's restore path and is job-based, so its job-status GET (a
|
|
83
|
-
// parameterized route, matched by prefix in isDbMigrationGateBypassed)
|
|
84
|
-
// must answer too.
|
|
85
|
-
"migrations/import-preflight",
|
|
86
|
-
"migrations_importpreflight_post",
|
|
87
|
-
"migrations/import-from-gcs",
|
|
88
|
-
"migrations_importfromgcs_post",
|
|
89
|
-
"migrations/preflight-from-gcs",
|
|
90
|
-
"migrations_preflightfromgcs_post",
|
|
91
|
-
"migrations_jobs_by_job_id_get",
|
|
92
|
-
]);
|
|
73
|
+
new Set(["admin/rollback-migrations", "admin_rollbackmigrations_post"]);
|
|
93
74
|
|
|
94
75
|
/**
|
|
95
76
|
* Whether an operation may proceed despite unready DB migrations: always for
|
|
@@ -103,13 +84,7 @@ export function isDbMigrationGateBypassed(operation: string): boolean {
|
|
|
103
84
|
if (dbMigrationReadiness.state !== "failed") {
|
|
104
85
|
return false;
|
|
105
86
|
}
|
|
106
|
-
|
|
107
|
-
// job-status route (migrations/jobs/:job_id) is matched by prefix; the
|
|
108
|
-
// IPC form is the exact operationId in the set above.
|
|
109
|
-
return (
|
|
110
|
-
DB_MIGRATION_FAILED_STATE_EXEMPT_OPERATIONS.has(operation) ||
|
|
111
|
-
operation.startsWith("migrations/jobs/")
|
|
112
|
-
);
|
|
87
|
+
return DB_MIGRATION_FAILED_STATE_EXEMPT_OPERATIONS.has(operation);
|
|
113
88
|
}
|
|
114
89
|
|
|
115
90
|
export function setDbReady(v: boolean): void {
|
package/src/daemon/lifecycle.ts
CHANGED
|
@@ -49,7 +49,6 @@ import {
|
|
|
49
49
|
startRuntimeHttpServerBackgroundSweeps,
|
|
50
50
|
} from "../runtime/http-server.js";
|
|
51
51
|
import { warmLocalGuardianPrincipalCache } from "../runtime/local-actor-identity.js";
|
|
52
|
-
import { recoverInterruptedImport } from "../runtime/migrations/vbundle-streaming-importer.js";
|
|
53
52
|
import { markCurrentProcessAsMainDaemon } from "../runtime/process-role.js";
|
|
54
53
|
import { publishConfigChanged } from "../runtime/sync/resource-sync-events.js";
|
|
55
54
|
import { reconcilePluginSchedules } from "../schedule/plugin-schedule-reconciler.js";
|
|
@@ -148,36 +147,6 @@ export async function runDaemon(): Promise<void> {
|
|
|
148
147
|
// after it.
|
|
149
148
|
recordDaemonBootTime(startupStartedAt);
|
|
150
149
|
|
|
151
|
-
// Recover from any streaming `.vbundle` import that was interrupted by a
|
|
152
|
-
// crash or SIGKILL. If the previous process died between
|
|
153
|
-
// `carryOverPreservedPaths` and the atomic workspace swap, the live
|
|
154
|
-
// workspace may be missing `data/db` / `data/qdrant` / etc. The marker
|
|
155
|
-
// at `<workspaceDir>.import-marker.json` (persisted before any rename
|
|
156
|
-
// runs) tells us where the orphaned preserved paths landed; the
|
|
157
|
-
// recovery helper moves them back into the live workspace and cleans
|
|
158
|
-
// up the temp tree. Running this BEFORE `initializeDb()` ensures the
|
|
159
|
-
// DB singleton opens against the fully-restored `assistant.db`.
|
|
160
|
-
try {
|
|
161
|
-
const recoveryResult = await recoverInterruptedImport(getWorkspaceDir());
|
|
162
|
-
if (!recoveryResult.ok) {
|
|
163
|
-
// Rollback is intentionally unresolved — backup/temp/marker are
|
|
164
|
-
// preserved on disk so an operator (or a later retry) can finish
|
|
165
|
-
// the recovery. Log loudly so ops sees it, but don't block start-up:
|
|
166
|
-
// the daemon still needs to come up for diagnostics. The next
|
|
167
|
-
// `streamCommitImport` will refuse to start a new import until the
|
|
168
|
-
// marker is resolved.
|
|
169
|
-
log.error(
|
|
170
|
-
{ failedCount: recoveryResult.failedCount },
|
|
171
|
-
"Interrupted-import recovery is INCOMPLETE; leftover .pre-import-* / .import-* scratch dirs remain in the workspace. Manual intervention may be required before the next import can run.",
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
} catch (err) {
|
|
175
|
-
log.warn(
|
|
176
|
-
{ err },
|
|
177
|
-
"recoverInterruptedImport threw during daemon startup; continuing",
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
150
|
// Load (or generate + persist) the auth signing key so tokens survive
|
|
182
151
|
// daemon restarts.
|
|
183
152
|
const signingKey = resolveSigningKey();
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ensureCloudIdentityIds } from "../config/cloud-identity.js";
|
|
2
|
-
import { maybeDefaultSpeechToCloud } from "../config/cloud-speech-defaults.js";
|
|
3
2
|
import type { AssistantConfig } from "../config/types.js";
|
|
4
3
|
import { getMcpServerManager } from "../mcp/manager.js";
|
|
5
4
|
import { startConfiguredMcpServers } from "../mcp/startup.js";
|
|
@@ -34,13 +33,6 @@ export async function initializeProvidersAndTools(
|
|
|
34
33
|
// overrides are normally only set by the secret-routes handlers at runtime.
|
|
35
34
|
await ensureCloudIdentityIds();
|
|
36
35
|
|
|
37
|
-
// Speech defaulting normally fires when the cloud credentials land
|
|
38
|
-
// (secret-routes); evaluating it once per boot also covers assistants whose
|
|
39
|
-
// connection predates that trigger, so voice works for every connected
|
|
40
|
-
// assistant with no configured speech credentials. Idempotent, and detached
|
|
41
|
-
// per the startup philosophy — must not block boot.
|
|
42
|
-
void maybeDefaultSpeechToCloud();
|
|
43
|
-
|
|
44
36
|
await initializeProviders(config);
|
|
45
37
|
// initializeTools() also loads workspace tool overrides from
|
|
46
38
|
// `<workspaceDir>/tools/` once core tools have settled, so they own
|
|
@@ -58,7 +58,6 @@ mock.module("../../prompts/persona-resolver.js", () => ({
|
|
|
58
58
|
resolveGuardianPersona: () => null,
|
|
59
59
|
resolveGuardianPersonaPath: () => null,
|
|
60
60
|
resolveGuardianPersonaStrict: () => null,
|
|
61
|
-
isGuardianPersonaCustomized: () => false,
|
|
62
61
|
resolveUserSlug: () => null,
|
|
63
62
|
resolveUserPersona: () => null,
|
|
64
63
|
resolveChannelPersona: () => null,
|
|
@@ -124,16 +124,6 @@ function recordReengagementTimestamp(): void {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
function refreshBackgroundWakeIntentSoon(reason: string): void {
|
|
128
|
-
void import("../background-wake/publisher.js")
|
|
129
|
-
.then(({ refreshBackgroundWakeIntent }) =>
|
|
130
|
-
refreshBackgroundWakeIntent(reason),
|
|
131
|
-
)
|
|
132
|
-
.catch((err) =>
|
|
133
|
-
log.warn({ err, reason }, "Failed to queue background wake refresh"),
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
127
|
export interface HeartbeatDeps {
|
|
138
128
|
/** Override for current hour (0-23), for testing. Used when no timezone is resolved. */
|
|
139
129
|
getCurrentHour?: () => number;
|
|
@@ -141,19 +131,6 @@ export interface HeartbeatDeps {
|
|
|
141
131
|
now?: () => Date;
|
|
142
132
|
}
|
|
143
133
|
|
|
144
|
-
export interface ManagedWakeHeartbeatRunOptions {
|
|
145
|
-
now?: number;
|
|
146
|
-
toleranceMs?: number;
|
|
147
|
-
assumeDue?: boolean;
|
|
148
|
-
scheduledFor?: number;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export interface ManagedWakeHeartbeatRunResult {
|
|
152
|
-
due: boolean;
|
|
153
|
-
completed: number;
|
|
154
|
-
skipped: number;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
134
|
export class HeartbeatService {
|
|
158
135
|
private static instance?: HeartbeatService;
|
|
159
136
|
|
|
@@ -236,47 +213,12 @@ export class HeartbeatService {
|
|
|
236
213
|
return countCompletedRunsToday() >= config.maxDailyRuns;
|
|
237
214
|
}
|
|
238
215
|
|
|
239
|
-
async runCloudWakeIfDue(
|
|
240
|
-
options: ManagedWakeHeartbeatRunOptions = {},
|
|
241
|
-
): Promise<ManagedWakeHeartbeatRunResult> {
|
|
242
|
-
const now = options.now ?? Date.now();
|
|
243
|
-
const toleranceMs = options.toleranceMs ?? 0;
|
|
244
|
-
const dueByLocalTimer =
|
|
245
|
-
this._nextRunAt != null && this._nextRunAt <= now + toleranceMs;
|
|
246
|
-
|
|
247
|
-
if (!dueByLocalTimer && options.assumeDue !== true) {
|
|
248
|
-
return { due: false, completed: 0, skipped: 0 };
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (!dueByLocalTimer) {
|
|
252
|
-
if (this._pendingRunId) {
|
|
253
|
-
supersedePendingRun(this._pendingRunId);
|
|
254
|
-
this._pendingRunId = null;
|
|
255
|
-
}
|
|
256
|
-
this._nextRunAt = options.scheduledFor ?? now;
|
|
257
|
-
this._pendingRunId = insertPendingHeartbeatRun(this._nextRunAt);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const completed = await this.runOnce({ force: false });
|
|
261
|
-
|
|
262
|
-
if (this.cronMode && !this.stopped) {
|
|
263
|
-
this.scheduleNextCronRun(getConfig().heartbeat);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
return {
|
|
267
|
-
due: true,
|
|
268
|
-
completed: completed ? 1 : 0,
|
|
269
|
-
skipped: completed ? 0 : 1,
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
|
|
273
216
|
start(): void {
|
|
274
217
|
this.stopped = false;
|
|
275
218
|
const config = getConfig().heartbeat;
|
|
276
219
|
if (!config.enabled) {
|
|
277
220
|
log.info("Heartbeat disabled by config");
|
|
278
221
|
this._nextRunAt = null;
|
|
279
|
-
refreshBackgroundWakeIntentSoon("heartbeat-disabled");
|
|
280
222
|
return;
|
|
281
223
|
}
|
|
282
224
|
if (this.timer) {
|
|
@@ -405,7 +347,6 @@ export class HeartbeatService {
|
|
|
405
347
|
{ nextRunAt: new Date(nextRunAt).toISOString(), delayMs },
|
|
406
348
|
"Heartbeat cron run scheduled",
|
|
407
349
|
);
|
|
408
|
-
refreshBackgroundWakeIntentSoon("heartbeat-cron-scheduled");
|
|
409
350
|
} catch (err) {
|
|
410
351
|
log.warn(
|
|
411
352
|
{ err },
|
|
@@ -432,7 +373,6 @@ export class HeartbeatService {
|
|
|
432
373
|
this._nextRunAt = null;
|
|
433
374
|
this.cronMode = false;
|
|
434
375
|
this.start();
|
|
435
|
-
refreshBackgroundWakeIntentSoon("heartbeat-reconfigured");
|
|
436
376
|
}
|
|
437
377
|
|
|
438
378
|
/**
|
|
@@ -449,7 +389,6 @@ export class HeartbeatService {
|
|
|
449
389
|
supersedePendingRun(this._pendingRunId);
|
|
450
390
|
this._pendingRunId = null;
|
|
451
391
|
}
|
|
452
|
-
refreshBackgroundWakeIntentSoon("heartbeat-counter-reset");
|
|
453
392
|
if (!this.timer) {
|
|
454
393
|
return;
|
|
455
394
|
}
|
|
@@ -519,7 +458,6 @@ export class HeartbeatService {
|
|
|
519
458
|
if (runId) {
|
|
520
459
|
skipHeartbeatRun(runId, "disabled");
|
|
521
460
|
}
|
|
522
|
-
refreshBackgroundWakeIntentSoon("heartbeat-disabled");
|
|
523
461
|
return false;
|
|
524
462
|
}
|
|
525
463
|
|
|
@@ -680,7 +618,6 @@ export class HeartbeatService {
|
|
|
680
618
|
if (!this.cronMode) {
|
|
681
619
|
this.scheduleNextRun(getConfig().heartbeat.intervalMs);
|
|
682
620
|
}
|
|
683
|
-
refreshBackgroundWakeIntentSoon("heartbeat-run-complete");
|
|
684
621
|
}
|
|
685
622
|
return true;
|
|
686
623
|
}
|
|
@@ -691,7 +628,6 @@ export class HeartbeatService {
|
|
|
691
628
|
}
|
|
692
629
|
this._nextRunAt = Date.now() + intervalMs;
|
|
693
630
|
this._pendingRunId = insertPendingHeartbeatRun(this._nextRunAt);
|
|
694
|
-
refreshBackgroundWakeIntentSoon("heartbeat-interval-scheduled");
|
|
695
631
|
}
|
|
696
632
|
|
|
697
633
|
/**
|
|
@@ -964,8 +900,7 @@ This is one of your first heartbeats. Your user hasn't heard from you yet and ma
|
|
|
964
900
|
}
|
|
965
901
|
|
|
966
902
|
/**
|
|
967
|
-
* Construct and start the heartbeat service singleton
|
|
968
|
-
* can wire it into the background-wake runtime. start() self-gates on
|
|
903
|
+
* Construct and start the heartbeat service singleton. start() self-gates on
|
|
969
904
|
* `heartbeat.enabled` and logs its own status.
|
|
970
905
|
*/
|
|
971
906
|
export function startHeartbeatService(): HeartbeatService {
|
|
@@ -97,23 +97,15 @@ describe("AssistantIpcServer DB migration readiness gate", () => {
|
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
test("migration-repair surface is allowed only in the failed state", () => {
|
|
100
|
-
// Rollback
|
|
100
|
+
// Rollback is the remedy for failed migrations — gating them in
|
|
101
101
|
// that state would make recovery impossible (the upgrade CLI's
|
|
102
102
|
// rollback/restore path). While migrations are merely RUNNING they stay
|
|
103
103
|
// gated: a rollback would race the in-flight migration runner.
|
|
104
104
|
setDbMigrating();
|
|
105
105
|
expect(gate("admin_rollbackmigrations_post")?.statusCode).toBe(503);
|
|
106
|
-
expect(gate("migrations_import_post")?.statusCode).toBe(503);
|
|
107
106
|
|
|
108
107
|
setDbMigrationFailed(new Error("boom"));
|
|
109
108
|
expect(gate("admin_rollbackmigrations_post")).toBeNull();
|
|
110
|
-
expect(gate("migrations_import_post")).toBeNull();
|
|
111
|
-
// All restore transports are repair-capable: preflights, the cloud
|
|
112
|
-
// platform's GCS path, and its job-status polling.
|
|
113
|
-
expect(gate("migrations_importpreflight_post")).toBeNull();
|
|
114
|
-
expect(gate("migrations_importfromgcs_post")).toBeNull();
|
|
115
|
-
expect(gate("migrations_preflightfromgcs_post")).toBeNull();
|
|
116
|
-
expect(gate("migrations_jobs_by_job_id_get")).toBeNull();
|
|
117
109
|
// Everything else stays gated in the failed state.
|
|
118
110
|
expect(gate("db_proxy")?.statusCode).toBe(503);
|
|
119
111
|
});
|
|
@@ -40,10 +40,6 @@ const realSttResolveModule = {
|
|
|
40
40
|
const realSecureKeysModule = {
|
|
41
41
|
...(await import("../../security/secure-keys.js")),
|
|
42
42
|
};
|
|
43
|
-
const realCloudSpeechModule = {
|
|
44
|
-
...(await import("../../cloud/cloud-speech.js")),
|
|
45
|
-
};
|
|
46
|
-
|
|
47
43
|
// -- Mutable stub state --------------------------------------------------------
|
|
48
44
|
|
|
49
45
|
import type { StreamingTranscriber } from "../../stt/types.js";
|
|
@@ -74,16 +70,6 @@ mock.module("../../security/secure-keys.js", () => ({
|
|
|
74
70
|
: realSecureKeysModule.getSecureKeyAsync(account),
|
|
75
71
|
}));
|
|
76
72
|
|
|
77
|
-
let managedAvailable = false;
|
|
78
|
-
|
|
79
|
-
mock.module("../../cloud/cloud-speech.js", () => ({
|
|
80
|
-
...realCloudSpeechModule,
|
|
81
|
-
managedSpeechAvailable: async () =>
|
|
82
|
-
preflightMocksActive
|
|
83
|
-
? managedAvailable
|
|
84
|
-
: realCloudSpeechModule.managedSpeechAvailable(),
|
|
85
|
-
}));
|
|
86
|
-
|
|
87
73
|
import { setConfig } from "../../__tests__/helpers/set-config.js";
|
|
88
74
|
import { getConfig } from "../../config/loader.js";
|
|
89
75
|
import {
|
|
@@ -135,7 +121,6 @@ beforeEach(() => {
|
|
|
135
121
|
sttProvider = "deepgram";
|
|
136
122
|
ttsProvider = "fish-audio";
|
|
137
123
|
ttsProviders = { "fish-audio": { referenceId: "ref-123" } };
|
|
138
|
-
managedAvailable = false;
|
|
139
124
|
});
|
|
140
125
|
|
|
141
126
|
function expectNotReady(
|
|
@@ -284,32 +269,3 @@ describe("resolveLiveVoiceCredentialReadiness", () => {
|
|
|
284
269
|
expect(readiness.userMessage.endsWith(".")).toBe(true);
|
|
285
270
|
});
|
|
286
271
|
});
|
|
287
|
-
|
|
288
|
-
describe("resolveLiveVoiceCredentialReadiness — managed (cadet) TTS", () => {
|
|
289
|
-
test("cadet TTS with a full platform connection → ready", async () => {
|
|
290
|
-
ttsProvider = "cadet";
|
|
291
|
-
ttsProviders = {};
|
|
292
|
-
managedAvailable = true;
|
|
293
|
-
|
|
294
|
-
const readiness = await runReadiness();
|
|
295
|
-
expect(readiness).toEqual({ status: "ready" });
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
test("cadet TTS without a cloud connection → connection copy, not API-key copy", async () => {
|
|
299
|
-
ttsProvider = "cadet";
|
|
300
|
-
ttsProviders = {};
|
|
301
|
-
managedAvailable = false;
|
|
302
|
-
|
|
303
|
-
const readiness = expectNotReady(await runReadiness());
|
|
304
|
-
expect(readiness.missing).toEqual([
|
|
305
|
-
{
|
|
306
|
-
kind: "tts",
|
|
307
|
-
providerId: "cadet",
|
|
308
|
-
reason:
|
|
309
|
-
'TTS provider "cadet" needs a Cadet Cloud connection for cloud speech',
|
|
310
|
-
},
|
|
311
|
-
]);
|
|
312
|
-
expect(readiness.userMessage).toContain("assistant cloud connect");
|
|
313
|
-
expect(readiness.userMessage).not.toContain("API key");
|
|
314
|
-
});
|
|
315
|
-
});
|
|
@@ -1170,8 +1170,6 @@ describe("LiveVoiceSession Flux end-of-turn", () => {
|
|
|
1170
1170
|
test.each([
|
|
1171
1171
|
{ providerId: "deepgram-flux" as const, flagOn: true },
|
|
1172
1172
|
{ providerId: "deepgram-flux" as const, flagOn: false },
|
|
1173
|
-
{ providerId: "cadet-flux" as const, flagOn: true },
|
|
1174
|
-
{ providerId: "cadet-flux" as const, flagOn: false },
|
|
1175
1173
|
])(
|
|
1176
1174
|
"only provider speech starts interrupt playback: %j",
|
|
1177
1175
|
async ({ providerId, flagOn }) => {
|
|
@@ -1518,7 +1516,7 @@ describe("LiveVoiceSession Flux end-of-turn during the STT dial", () => {
|
|
|
1518
1516
|
async (flagOn) => {
|
|
1519
1517
|
const gate = createDialGate();
|
|
1520
1518
|
const { frames, session } = createHarness({
|
|
1521
|
-
providerId: "
|
|
1519
|
+
providerId: "deepgram",
|
|
1522
1520
|
fluxConfig: flagOn ? FLUX_ON : FLUX_OFF,
|
|
1523
1521
|
silenceThresholdMs: 10_000,
|
|
1524
1522
|
resolveGate: gate.promise,
|
|
@@ -1539,9 +1537,9 @@ describe("LiveVoiceSession Flux end-of-turn during the STT dial", () => {
|
|
|
1539
1537
|
);
|
|
1540
1538
|
|
|
1541
1539
|
test.each([
|
|
1542
|
-
{ providerId: "
|
|
1540
|
+
{ providerId: "deepgram" as const, audio: LOUD_CHUNK, interrupts: false },
|
|
1543
1541
|
{
|
|
1544
|
-
providerId: "
|
|
1542
|
+
providerId: "deepgram" as const,
|
|
1545
1543
|
audio: SUSTAINED_LOUD_CHUNK,
|
|
1546
1544
|
interrupts: true,
|
|
1547
1545
|
},
|
|
@@ -1616,7 +1614,7 @@ describe("LiveVoiceSession Flux end-of-turn during the STT dial", () => {
|
|
|
1616
1614
|
// The first input is released but cannot dispatch until its final arrives.
|
|
1617
1615
|
await session.handleBinaryAudio(SUSTAINED_LOUD_CHUNK);
|
|
1618
1616
|
await sleep(PAST_SILENCE_BOUNDARY_MS);
|
|
1619
|
-
options.providerId = "
|
|
1617
|
+
options.providerId = "deepgram";
|
|
1620
1618
|
first.flushStopEvents();
|
|
1621
1619
|
await waitFor(() => countFrames(frames, "thinking") === 1);
|
|
1622
1620
|
expect(countFrames(frames, "turn_cancelled")).toBe(0);
|
|
@@ -1609,7 +1609,7 @@ describe("LiveVoiceSession STT", () => {
|
|
|
1609
1609
|
},
|
|
1610
1610
|
},
|
|
1611
1611
|
});
|
|
1612
|
-
const transcriber = new MockStreamingTranscriber("
|
|
1612
|
+
const transcriber = new MockStreamingTranscriber("deepgram");
|
|
1613
1613
|
const startVoiceTurn = speakingVoiceTurnStarter();
|
|
1614
1614
|
const { streamTtsAudio, ttsCalls } = recordingTtsStreamer();
|
|
1615
1615
|
const { context } = createContext();
|
|
@@ -11,24 +11,22 @@
|
|
|
11
11
|
* Mirrors `calls/telephony-credential-preflight.ts` for the phone-call
|
|
12
12
|
* transport.
|
|
13
13
|
*
|
|
14
|
-
* Both legs are checked against the
|
|
15
|
-
*
|
|
16
|
-
* synthesis paths resolve too — so a `ready` verdict earned on managed
|
|
17
|
-
* speech is a verdict the runtime can honour.
|
|
14
|
+
* Both legs are checked against the providers the transcriber and synthesis
|
|
15
|
+
* paths resolve, so a `ready` verdict is one the runtime can honour.
|
|
18
16
|
*/
|
|
19
17
|
|
|
20
18
|
import {
|
|
21
19
|
fishAudioReferenceIdConfigured,
|
|
22
20
|
ttsSecretResolves,
|
|
23
21
|
} from "../calls/telephony-tts-capability.js";
|
|
24
|
-
import {
|
|
25
|
-
import { resolveEffectiveSpeechProviders } from "../config/cloud-speech-defaults.js";
|
|
22
|
+
import { getConfig } from "../config/loader.js";
|
|
26
23
|
import { getProviderEntry } from "../providers/speech-to-text/provider-catalog.js";
|
|
27
24
|
import {
|
|
28
25
|
resolveStreamingTranscriber,
|
|
29
26
|
sttCredentialGapReason,
|
|
30
27
|
sttProviderKeyResolves,
|
|
31
28
|
} from "../providers/speech-to-text/resolve.js";
|
|
29
|
+
import { sttCatalogKeyForRole } from "../stt/roles.js";
|
|
32
30
|
import type { SttProviderId } from "../stt/types.js";
|
|
33
31
|
import type { TtsProviderCatalogEntry } from "../tts/provider-catalog.js";
|
|
34
32
|
import { getCatalogProvider, getTtsProvider } from "../tts/provider-catalog.js";
|
|
@@ -78,13 +76,12 @@ export type LiveVoiceCredentialReadiness =
|
|
|
78
76
|
export async function resolveLiveVoiceCredentialReadiness(): Promise<LiveVoiceCredentialReadiness> {
|
|
79
77
|
// Readiness must ask about the same provider the session will dial, so it
|
|
80
78
|
// reads the live-voice role rather than the global setting.
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
});
|
|
79
|
+
const config = getConfig();
|
|
80
|
+
const effectiveStt = sttCatalogKeyForRole(config.services.stt, "liveVoice");
|
|
84
81
|
const gaps = (
|
|
85
82
|
await Promise.all([
|
|
86
|
-
resolveSttGap(
|
|
87
|
-
resolveTtsGap(
|
|
83
|
+
resolveSttGap(effectiveStt),
|
|
84
|
+
resolveTtsGap(config.services.tts.provider),
|
|
88
85
|
])
|
|
89
86
|
).filter((gap) => gap !== null);
|
|
90
87
|
|
|
@@ -142,10 +139,7 @@ async function resolveSttGap(
|
|
|
142
139
|
providerId: entry.id,
|
|
143
140
|
reason: sttCredentialGapReason(entry.credentialProvider),
|
|
144
141
|
},
|
|
145
|
-
clause:
|
|
146
|
-
entry.credentialProvider === "cadet"
|
|
147
|
-
? `a Cadet Cloud connection for cloud speech (run 'assistant cloud connect')`
|
|
148
|
-
: `an API key for the speech-to-text provider "${entry.id}"`,
|
|
142
|
+
clause: `an API key for the speech-to-text provider "${entry.id}"`,
|
|
149
143
|
};
|
|
150
144
|
}
|
|
151
145
|
|
|
@@ -197,24 +191,6 @@ async function resolveTtsGap(
|
|
|
197
191
|
};
|
|
198
192
|
}
|
|
199
193
|
|
|
200
|
-
// Cloud speech authenticates via the cloud connection — full
|
|
201
|
-
// availability (API key + assistant ID) is the credential, so the
|
|
202
|
-
// stored-secret loop below would pass half-connected states that
|
|
203
|
-
// synthesis rejects.
|
|
204
|
-
if (entry.id === "cadet") {
|
|
205
|
-
if (!(await managedSpeechAvailable())) {
|
|
206
|
-
return {
|
|
207
|
-
gap: {
|
|
208
|
-
kind: "tts",
|
|
209
|
-
providerId: entry.id,
|
|
210
|
-
reason: `TTS provider "${entry.id}" needs a Cadet Cloud connection for cloud speech`,
|
|
211
|
-
},
|
|
212
|
-
clause: `a Cadet Cloud connection for cloud speech (run 'assistant cloud connect')`,
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
return null;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
194
|
for (const secret of entry.secretRequirements) {
|
|
219
195
|
if (!(await ttsSecretResolves(secret.credentialStoreKey))) {
|
|
220
196
|
return {
|
|
@@ -8262,14 +8262,18 @@ export async function defaultSpawnBackgroundContinuation(args: {
|
|
|
8262
8262
|
async function defaultResolveStreamingTranscriber(
|
|
8263
8263
|
options: ResolveStreamingTranscriberOptions,
|
|
8264
8264
|
): Promise<StreamingTranscriber | null> {
|
|
8265
|
-
const { resolveEffectiveSpeechProviders } =
|
|
8266
|
-
await import("../config/cloud-speech-defaults.js");
|
|
8267
8265
|
const { resolveStreamingTranscriber } =
|
|
8268
8266
|
await import("../providers/speech-to-text/resolve.js");
|
|
8269
|
-
const {
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
8267
|
+
const { sttCatalogKeyForRole } = await import("../stt/roles.js");
|
|
8268
|
+
const { getConfig } = await import("../config/loader.js");
|
|
8269
|
+
// The live-voice role's configured provider is the one that gets dialed —
|
|
8270
|
+
// the session resolves it here (rather than trusting a caller's override)
|
|
8271
|
+
// so readiness and transcription agree.
|
|
8272
|
+
const providerId = sttCatalogKeyForRole(
|
|
8273
|
+
getConfig().services.stt,
|
|
8274
|
+
"liveVoice",
|
|
8275
|
+
);
|
|
8276
|
+
return resolveStreamingTranscriber({ ...options, providerId });
|
|
8273
8277
|
}
|
|
8274
8278
|
|
|
8275
8279
|
async function defaultResolveLiveVoiceCredentialReadiness(): Promise<LiveVoiceCredentialReadiness> {
|
|
@@ -220,14 +220,7 @@ async function resolveLiveVoiceStreamingTtsProvider(
|
|
|
220
220
|
configOverride?: LiveVoiceTtsConfig,
|
|
221
221
|
): Promise<ResolvedStreamingTtsProvider> {
|
|
222
222
|
const config = configOverride ?? (await loadAssistantConfig());
|
|
223
|
-
const {
|
|
224
|
-
await import("../config/cloud-speech-defaults.js");
|
|
225
|
-
const { tts: effectiveProviderId } =
|
|
226
|
-
await resolveEffectiveSpeechProviders(config);
|
|
227
|
-
const { provider: providerId, providerConfig } = resolveTtsConfig(
|
|
228
|
-
config,
|
|
229
|
-
effectiveProviderId,
|
|
230
|
-
);
|
|
223
|
+
const { provider: providerId, providerConfig } = resolveTtsConfig(config);
|
|
231
224
|
|
|
232
225
|
let provider: TtsProvider;
|
|
233
226
|
try {
|
|
@@ -60,9 +60,9 @@ async function main(): Promise<void> {
|
|
|
60
60
|
// standalone process must do it itself so getCloudBaseUrl() resolves to
|
|
61
61
|
// the persisted platform environment instead of the CADET_ENVIRONMENT
|
|
62
62
|
// default. Retrospective and consolidation passes wake real agent
|
|
63
|
-
// conversations whose inference
|
|
64
|
-
//
|
|
65
|
-
//
|
|
63
|
+
// conversations whose inference requests go through the cloud proxy —
|
|
64
|
+
// without rehydration those requests hit the wrong platform and are
|
|
65
|
+
// rejected.
|
|
66
66
|
await ensureCloudIdentityIds();
|
|
67
67
|
|
|
68
68
|
// Jobs in this process wake real agent conversations, so it registers the
|
|
@@ -385,41 +385,6 @@ export function ensureGuardianPersonaFile(userFile: string): void {
|
|
|
385
385
|
log.debug({ path: filePath }, "Wrote guardian persona scaffold");
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
-
/**
|
|
389
|
-
* Return `true` when the persona file at `filePath` has been edited by
|
|
390
|
-
* the user (its stripped content differs from the bare scaffold
|
|
391
|
-
* template). Returns `false` when the file is missing, unreadable,
|
|
392
|
-
* empty after stripping, or byte-identical to the template after
|
|
393
|
-
* stripping comment lines.
|
|
394
|
-
*
|
|
395
|
-
* Used by the vbundle importer to decide whether a legacy
|
|
396
|
-
* `prompts/USER.md` entry may safely overwrite `users/<slug>.md`.
|
|
397
|
-
*/
|
|
398
|
-
export function isGuardianPersonaCustomized(filePath: string): boolean {
|
|
399
|
-
if (!existsSync(filePath)) {
|
|
400
|
-
return false;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
let content: string;
|
|
404
|
-
try {
|
|
405
|
-
content = readFileSync(filePath, "utf-8");
|
|
406
|
-
} catch (err) {
|
|
407
|
-
log.warn(
|
|
408
|
-
{ err, path: filePath },
|
|
409
|
-
"Failed to read persona file while checking customization",
|
|
410
|
-
);
|
|
411
|
-
return false;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
const stripped = stripCommentLines(content);
|
|
415
|
-
if (stripped.length === 0) {
|
|
416
|
-
return false;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
const templateStripped = stripCommentLines(GUARDIAN_PERSONA_TEMPLATE);
|
|
420
|
-
return stripped !== templateStripped;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
388
|
// ── Onboarding section writer ────────────────────────────────────
|
|
424
389
|
|
|
425
390
|
const ONBOARDING_HEADING = "## Onboarding Context";
|