@vellumai/assistant 0.5.6 → 0.5.7
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/.env.example +16 -2
- package/ARCHITECTURE.md +6 -75
- package/Dockerfile +1 -1
- package/README.md +0 -2
- package/bun.lock +0 -414
- package/docs/architecture/keychain-broker.md +45 -240
- package/docs/architecture/security.md +0 -17
- package/docs/credential-execution-service.md +2 -2
- package/node_modules/@vellumai/ces-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +119 -0
- package/node_modules/@vellumai/credential-storage/package.json +1 -0
- package/node_modules/@vellumai/egress-proxy/package.json +1 -0
- package/package.json +2 -3
- package/src/__tests__/actor-token-service.test.ts +0 -114
- package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
- package/src/__tests__/browser-skill-endstate.test.ts +6 -5
- package/src/__tests__/btw-routes.test.ts +0 -39
- package/src/__tests__/call-domain.test.ts +0 -128
- package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -5
- package/src/__tests__/channel-readiness-service.test.ts +1 -60
- package/src/__tests__/checker.test.ts +4 -2
- package/src/__tests__/cli-command-risk-guard.test.ts +112 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -1
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-skill-tools.test.ts +0 -54
- package/src/__tests__/conversation-title-service.test.ts +87 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +28 -14
- package/src/__tests__/credential-execution-managed-contract.test.ts +33 -18
- package/src/__tests__/credential-security-e2e.test.ts +0 -66
- package/src/__tests__/credential-security-invariants.test.ts +4 -45
- package/src/__tests__/credentials-cli.test.ts +78 -0
- package/src/__tests__/db-migration-rollback.test.ts +2015 -1
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +34 -143
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
- package/src/__tests__/guardian-routing-state.test.ts +0 -5
- package/src/__tests__/host-shell-tool.test.ts +6 -7
- package/src/__tests__/http-user-message-parity.test.ts +3 -103
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
- package/src/__tests__/intent-routing.test.ts +0 -13
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
- package/src/__tests__/keychain-broker-client.test.ts +161 -22
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
- package/src/__tests__/migration-export-http.test.ts +2 -2
- package/src/__tests__/migration-import-commit-http.test.ts +2 -2
- package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
- package/src/__tests__/migration-validate-http.test.ts +2 -2
- package/src/__tests__/non-member-access-request.test.ts +0 -5
- package/src/__tests__/notification-decision-fallback.test.ts +4 -0
- package/src/__tests__/notification-decision-identity.test.ts +4 -0
- package/src/__tests__/permission-types.test.ts +1 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
- package/src/__tests__/qdrant-manager.test.ts +28 -2
- package/src/__tests__/registry.test.ts +0 -6
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
- package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
- package/src/__tests__/secure-keys.test.ts +83 -263
- package/src/__tests__/shell-identity.test.ts +96 -6
- package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
- package/src/__tests__/skill-feature-flags.test.ts +46 -45
- package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
- package/src/__tests__/skill-load-inline-command.test.ts +8 -12
- package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
- package/src/__tests__/skill-load-tool.test.ts +0 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
- package/src/__tests__/skills.test.ts +0 -2
- package/src/__tests__/slack-inbound-verification.test.ts +0 -4
- package/src/__tests__/suggestion-routes.test.ts +1 -32
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
- package/src/__tests__/update-bulletin.test.ts +0 -2
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -6
- package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
- package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +218 -0
- package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
- package/src/calls/audio-store.test.ts +97 -0
- package/src/calls/audio-store.ts +205 -0
- package/src/calls/call-controller.ts +85 -7
- package/src/calls/call-domain.ts +3 -0
- package/src/calls/call-store.ts +10 -3
- package/src/calls/fish-audio-client.ts +117 -0
- package/src/calls/relay-server.ts +27 -0
- package/src/calls/twilio-routes.ts +2 -1
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-ingress-preflight.ts +0 -42
- package/src/calls/voice-quality.ts +26 -5
- package/src/calls/voice-session-bridge.ts +6 -12
- package/src/cli/commands/config.ts +1 -4
- package/src/cli/commands/credentials.ts +34 -4
- package/src/cli/commands/oauth/index.ts +7 -0
- package/src/cli/commands/oauth/platform.ts +179 -0
- package/src/cli/commands/platform.ts +3 -3
- package/src/config/assistant-feature-flags.ts +186 -5
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
- package/src/config/bundled-tool-registry.ts +1 -11
- package/src/config/env-registry.ts +1 -1
- package/src/config/env.ts +8 -14
- package/src/config/feature-flag-registry.json +48 -8
- package/src/config/loader.ts +98 -31
- package/src/config/schema.ts +4 -13
- package/src/config/schemas/calls.ts +13 -0
- package/src/config/schemas/fish-audio.ts +39 -0
- package/src/config/schemas/security.ts +0 -4
- package/src/config/types.ts +0 -1
- package/src/contacts/contact-store.ts +39 -0
- package/src/contacts/types.ts +2 -0
- package/src/credential-execution/approval-bridge.ts +1 -0
- package/src/credential-execution/executable-discovery.ts +28 -4
- package/src/credential-execution/feature-gates.ts +16 -0
- package/src/credential-execution/process-manager.ts +38 -0
- package/src/daemon/assistant-attachments.ts +9 -0
- package/src/daemon/config-watcher.ts +5 -0
- package/src/daemon/conversation-tool-setup.ts +0 -105
- package/src/daemon/conversation.ts +10 -1
- package/src/daemon/handlers/config-vercel.ts +92 -0
- package/src/daemon/handlers/skills.ts +2 -15
- package/src/daemon/install-symlink.ts +195 -0
- package/src/daemon/lifecycle.ts +227 -51
- package/src/daemon/message-types/conversations.ts +3 -4
- package/src/daemon/message-types/diagnostics.ts +3 -22
- package/src/daemon/message-types/messages.ts +0 -2
- package/src/daemon/message-types/upgrades.ts +8 -0
- package/src/daemon/server.ts +30 -92
- package/src/events/domain-events.ts +2 -1
- package/src/inbound/platform-callback-registration.ts +3 -3
- package/src/instrument.ts +8 -5
- package/src/memory/conversation-title-service.ts +50 -1
- package/src/memory/db-init.ts +12 -0
- package/src/memory/items-extractor.ts +15 -1
- package/src/memory/job-handlers/conversation-starters.ts +4 -1
- package/src/memory/jobs-store.ts +30 -5
- package/src/memory/jobs-worker.ts +31 -7
- package/src/memory/migrations/001-job-deferrals.ts +19 -0
- package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
- package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
- package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
- package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
- package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
- package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
- package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
- package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
- package/src/memory/migrations/116-messages-fts.ts +106 -1
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
- package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
- package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
- package/src/memory/migrations/141-rename-verification-table.ts +54 -0
- package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
- package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
- package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
- package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
- package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
- package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
- package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
- package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
- package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
- package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
- package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
- package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/migrations/registry.ts +90 -0
- package/src/memory/migrations/validate-migration-state.ts +137 -11
- package/src/memory/qdrant-circuit-breaker.ts +9 -0
- package/src/memory/qdrant-manager.ts +64 -7
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/contacts.ts +1 -0
- package/src/notifications/decision-engine.ts +4 -1
- package/src/oauth/connection-resolver.ts +6 -4
- package/src/permissions/checker.ts +0 -38
- package/src/permissions/shell-identity.ts +76 -22
- package/src/permissions/types.ts +4 -2
- package/src/platform/client.ts +35 -7
- package/src/prompts/persona-resolver.ts +138 -0
- package/src/prompts/system-prompt.ts +36 -4
- package/src/prompts/templates/users/default.md +1 -0
- package/src/providers/registry.ts +27 -40
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
- package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
- package/src/runtime/auth/external-assistant-id.ts +13 -59
- package/src/runtime/auth/route-policy.ts +15 -1
- package/src/runtime/auth/token-service.ts +43 -138
- package/src/runtime/channel-readiness-service.ts +1 -16
- package/src/runtime/http-server.ts +27 -2
- package/src/runtime/middleware/error-handler.ts +1 -9
- package/src/runtime/routes/audio-routes.ts +40 -0
- package/src/runtime/routes/btw-routes.ts +0 -17
- package/src/runtime/routes/conversation-query-routes.ts +63 -1
- package/src/runtime/routes/conversation-routes.ts +4 -44
- package/src/runtime/routes/diagnostics-routes.ts +1 -477
- package/src/runtime/routes/identity-routes.ts +18 -29
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
- package/src/runtime/routes/integrations/vercel.ts +89 -0
- package/src/runtime/routes/log-export-routes.ts +5 -0
- package/src/runtime/routes/memory-item-routes.ts +24 -6
- package/src/runtime/routes/migration-rollback-routes.ts +209 -0
- package/src/runtime/routes/migration-routes.ts +17 -1
- package/src/runtime/routes/notification-routes.ts +58 -0
- package/src/runtime/routes/schedule-routes.ts +65 -0
- package/src/runtime/routes/settings-routes.ts +41 -1
- package/src/runtime/routes/tts-routes.ts +86 -0
- package/src/runtime/routes/upgrade-broadcast-routes.ts +26 -2
- package/src/runtime/routes/workspace-commit-routes.ts +62 -0
- package/src/runtime/routes/workspace-routes.test.ts +22 -1
- package/src/runtime/routes/workspace-routes.ts +1 -1
- package/src/runtime/routes/workspace-utils.ts +86 -2
- package/src/security/ces-credential-client.ts +59 -22
- package/src/security/ces-rpc-credential-backend.ts +85 -0
- package/src/security/credential-backend.ts +12 -88
- package/src/security/keychain-broker-client.ts +10 -2
- package/src/security/secure-keys.ts +94 -113
- package/src/skills/catalog-install.ts +13 -7
- package/src/telemetry/usage-telemetry-reporter.ts +4 -2
- package/src/tools/calls/call-start.ts +1 -0
- package/src/tools/executor.ts +0 -4
- package/src/tools/network/script-proxy/session-manager.ts +19 -4
- package/src/tools/network/web-fetch.ts +3 -1
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/types.ts +0 -8
- package/src/util/errors.ts +0 -12
- package/src/util/platform.ts +3 -50
- package/src/workspace/git-service.ts +5 -2
- package/src/workspace/migrations/001-avatar-rename.ts +15 -0
- package/src/workspace/migrations/003-seed-device-id.ts +17 -1
- package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
- package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
- package/src/workspace/migrations/006-services-config.ts +49 -0
- package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
- package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
- package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
- package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
- package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
- package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
- package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
- package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
- package/src/workspace/migrations/017-seed-persona-dirs.ts +95 -0
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +23 -1
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/runner.ts +106 -2
- package/src/workspace/migrations/types.ts +4 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
- package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
- package/src/__tests__/diagnostics-export.test.ts +0 -288
- package/src/__tests__/local-gateway-health.test.ts +0 -209
- package/src/__tests__/secret-ingress-handler.test.ts +0 -120
- package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
- package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
- package/src/__tests__/swarm-orchestrator.test.ts +0 -463
- package/src/__tests__/swarm-plan-validator.test.ts +0 -384
- package/src/__tests__/swarm-recursion.test.ts +0 -197
- package/src/__tests__/swarm-router-planner.test.ts +0 -234
- package/src/__tests__/swarm-tool.test.ts +0 -185
- package/src/__tests__/swarm-worker-backend.test.ts +0 -144
- package/src/__tests__/swarm-worker-runner.test.ts +0 -288
- package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
- package/src/commands/cc-command-registry.ts +0 -248
- package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
- package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
- package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
- package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
- package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
- package/src/config/schemas/swarm.ts +0 -82
- package/src/logfire.ts +0 -135
- package/src/runtime/local-gateway-health.ts +0 -275
- package/src/security/secret-ingress.ts +0 -68
- package/src/swarm/backend-claude-code.ts +0 -225
- package/src/swarm/checkpoint.ts +0 -137
- package/src/swarm/graph-utils.ts +0 -53
- package/src/swarm/index.ts +0 -55
- package/src/swarm/limits.ts +0 -66
- package/src/swarm/orchestrator.ts +0 -424
- package/src/swarm/plan-validator.ts +0 -117
- package/src/swarm/router-planner.ts +0 -162
- package/src/swarm/router-prompts.ts +0 -39
- package/src/swarm/synthesizer.ts +0 -81
- package/src/swarm/types.ts +0 -72
- package/src/swarm/worker-backend.ts +0 -131
- package/src/swarm/worker-prompts.ts +0 -80
- package/src/swarm/worker-runner.ts +0 -170
- package/src/tools/claude-code/claude-code.ts +0 -610
- package/src/tools/swarm/delegate.ts +0 -205
package/src/config/loader.ts
CHANGED
|
@@ -2,19 +2,15 @@ import {
|
|
|
2
2
|
existsSync,
|
|
3
3
|
mkdirSync,
|
|
4
4
|
readFileSync,
|
|
5
|
+
renameSync,
|
|
5
6
|
statSync,
|
|
6
7
|
writeFileSync,
|
|
7
8
|
} from "node:fs";
|
|
8
|
-
import { dirname } from "node:path";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
9
10
|
|
|
10
11
|
import { ConfigError } from "../util/errors.js";
|
|
11
12
|
import { getLogger } from "../util/logger.js";
|
|
12
|
-
import {
|
|
13
|
-
ensureDataDir,
|
|
14
|
-
getWorkspaceConfigPath,
|
|
15
|
-
readLockfile,
|
|
16
|
-
writeLockfile,
|
|
17
|
-
} from "../util/platform.js";
|
|
13
|
+
import { ensureDataDir, getWorkspaceConfigPath } from "../util/platform.js";
|
|
18
14
|
import { AssistantConfigSchema } from "./schema.js";
|
|
19
15
|
import type { AssistantConfig } from "./types.js";
|
|
20
16
|
|
|
@@ -214,6 +210,35 @@ export function deepMergeMissing(
|
|
|
214
210
|
return changed;
|
|
215
211
|
}
|
|
216
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Deep-merge `overrides` into `target`, overwriting leaf values.
|
|
215
|
+
* Recursively merges nested objects; scalars and arrays from `overrides`
|
|
216
|
+
* replace corresponding values in `target`.
|
|
217
|
+
*/
|
|
218
|
+
export function deepMergeOverwrite(
|
|
219
|
+
target: Record<string, unknown>,
|
|
220
|
+
overrides: Record<string, unknown>,
|
|
221
|
+
): void {
|
|
222
|
+
for (const key of Object.keys(overrides)) {
|
|
223
|
+
const ov = overrides[key];
|
|
224
|
+
if (
|
|
225
|
+
ov != null &&
|
|
226
|
+
typeof ov === "object" &&
|
|
227
|
+
!Array.isArray(ov) &&
|
|
228
|
+
target[key] != null &&
|
|
229
|
+
typeof target[key] === "object" &&
|
|
230
|
+
!Array.isArray(target[key])
|
|
231
|
+
) {
|
|
232
|
+
deepMergeOverwrite(
|
|
233
|
+
target[key] as Record<string, unknown>,
|
|
234
|
+
ov as Record<string, unknown>,
|
|
235
|
+
);
|
|
236
|
+
} else {
|
|
237
|
+
target[key] = ov;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
217
242
|
/**
|
|
218
243
|
* Read the existing config.json from disk, merge any missing schema-default
|
|
219
244
|
* keys, and rewrite only when there is an effective change.
|
|
@@ -248,6 +273,72 @@ function backfillConfigDefaults(
|
|
|
248
273
|
}
|
|
249
274
|
}
|
|
250
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Merge default workspace config from the file referenced by
|
|
278
|
+
* VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH into the workspace config on disk.
|
|
279
|
+
*
|
|
280
|
+
* Called once at daemon startup (before the first loadConfig()) so the
|
|
281
|
+
* defaults are persisted to the workspace config file alongside any
|
|
282
|
+
* schema-level defaults that loadConfig() backfills.
|
|
283
|
+
*/
|
|
284
|
+
export function mergeDefaultWorkspaceConfig(): void {
|
|
285
|
+
const defaultConfigPath = process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
|
|
286
|
+
if (!defaultConfigPath || !existsSync(defaultConfigPath)) return;
|
|
287
|
+
|
|
288
|
+
let defaults: unknown;
|
|
289
|
+
try {
|
|
290
|
+
defaults = JSON.parse(readFileSync(defaultConfigPath, "utf-8"));
|
|
291
|
+
} catch (err) {
|
|
292
|
+
log.warn(
|
|
293
|
+
{ err },
|
|
294
|
+
"Failed to read default workspace config from %s",
|
|
295
|
+
defaultConfigPath,
|
|
296
|
+
);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (
|
|
301
|
+
defaults == null ||
|
|
302
|
+
typeof defaults !== "object" ||
|
|
303
|
+
Array.isArray(defaults)
|
|
304
|
+
) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const configPath = getConfigPath();
|
|
309
|
+
let existing: Record<string, unknown> = {};
|
|
310
|
+
if (existsSync(configPath)) {
|
|
311
|
+
try {
|
|
312
|
+
existing = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
313
|
+
} catch {
|
|
314
|
+
// If existing config is corrupt, start fresh
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
deepMergeOverwrite(existing, defaults as Record<string, unknown>);
|
|
319
|
+
|
|
320
|
+
const dir = dirname(configPath);
|
|
321
|
+
if (!existsSync(dir)) {
|
|
322
|
+
mkdirSync(dir, { recursive: true });
|
|
323
|
+
}
|
|
324
|
+
writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
325
|
+
|
|
326
|
+
// Move the temp file into the workspace directory as a permanent record.
|
|
327
|
+
// This prevents re-application on daemon restart (the env var still points
|
|
328
|
+
// at the old /tmp path which no longer exists).
|
|
329
|
+
try {
|
|
330
|
+
const dest = join(dir, "default-config.json");
|
|
331
|
+
renameSync(defaultConfigPath, dest);
|
|
332
|
+
log.info(
|
|
333
|
+
"Merged default workspace config from %s (archived to %s)",
|
|
334
|
+
defaultConfigPath,
|
|
335
|
+
dest,
|
|
336
|
+
);
|
|
337
|
+
} catch {
|
|
338
|
+
log.info("Merged default workspace config from %s", defaultConfigPath);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
251
342
|
export function loadConfig(): AssistantConfig {
|
|
252
343
|
if (cached) return cached;
|
|
253
344
|
|
|
@@ -375,30 +466,6 @@ export function saveRawConfig(config: Record<string, unknown>): void {
|
|
|
375
466
|
cached = null; // invalidate cache
|
|
376
467
|
}
|
|
377
468
|
|
|
378
|
-
/**
|
|
379
|
-
* Sync client-relevant config values (e.g. platform.baseUrl) to the lockfile
|
|
380
|
-
* so external tools (e.g. vel) can discover them without importing the full
|
|
381
|
-
* config schema. Mirrors the behaviour of `syncConfigToLockfile` in the
|
|
382
|
-
* lightweight CLI (`cli/src/lib/assistant-config.ts`).
|
|
383
|
-
*/
|
|
384
|
-
export function syncConfigToLockfile(): void {
|
|
385
|
-
const configPath = getWorkspaceConfigPath();
|
|
386
|
-
if (!existsSync(configPath)) return;
|
|
387
|
-
|
|
388
|
-
try {
|
|
389
|
-
const raw = JSON.parse(readFileSync(configPath, "utf-8")) as Record<
|
|
390
|
-
string,
|
|
391
|
-
unknown
|
|
392
|
-
>;
|
|
393
|
-
const platform = raw.platform as Record<string, unknown> | undefined;
|
|
394
|
-
const data = readLockfile() ?? {};
|
|
395
|
-
data.platformBaseUrl = (platform?.baseUrl as string) || undefined;
|
|
396
|
-
writeLockfile(data);
|
|
397
|
-
} catch {
|
|
398
|
-
// Config file unreadable — skip sync
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
469
|
export function getNestedValue(
|
|
403
470
|
obj: Record<string, unknown>,
|
|
404
471
|
path: string,
|
package/src/config/schema.ts
CHANGED
|
@@ -40,6 +40,8 @@ export {
|
|
|
40
40
|
ElevenLabsConfigSchema,
|
|
41
41
|
VALID_CONVERSATION_TIMEOUTS,
|
|
42
42
|
} from "./schemas/elevenlabs.js";
|
|
43
|
+
export type { FishAudioConfig } from "./schemas/fish-audio.js";
|
|
44
|
+
export { FishAudioConfigSchema } from "./schemas/fish-audio.js";
|
|
43
45
|
export type { HeartbeatConfig } from "./schemas/heartbeat.js";
|
|
44
46
|
export { HeartbeatConfigSchema } from "./schemas/heartbeat.js";
|
|
45
47
|
export type {
|
|
@@ -173,8 +175,6 @@ export {
|
|
|
173
175
|
SkillsInstallConfigSchema,
|
|
174
176
|
SkillsLoadConfigSchema,
|
|
175
177
|
} from "./schemas/skills.js";
|
|
176
|
-
export type { SwarmConfig } from "./schemas/swarm.js";
|
|
177
|
-
export { SwarmConfigSchema } from "./schemas/swarm.js";
|
|
178
178
|
export type { RateLimitConfig, TimeoutConfig } from "./schemas/timeouts.js";
|
|
179
179
|
export {
|
|
180
180
|
RateLimitConfigSchema,
|
|
@@ -193,6 +193,7 @@ import {
|
|
|
193
193
|
WhatsAppConfigSchema,
|
|
194
194
|
} from "./schemas/channels.js";
|
|
195
195
|
import { ElevenLabsConfigSchema } from "./schemas/elevenlabs.js";
|
|
196
|
+
import { FishAudioConfigSchema } from "./schemas/fish-audio.js";
|
|
196
197
|
import { HeartbeatConfigSchema } from "./schemas/heartbeat.js";
|
|
197
198
|
import {
|
|
198
199
|
ContextWindowConfigSchema,
|
|
@@ -223,7 +224,6 @@ import {
|
|
|
223
224
|
VALID_INFERENCE_PROVIDERS,
|
|
224
225
|
} from "./schemas/services.js";
|
|
225
226
|
import { SkillsConfigSchema } from "./schemas/skills.js";
|
|
226
|
-
import { SwarmConfigSchema } from "./schemas/swarm.js";
|
|
227
227
|
import {
|
|
228
228
|
RateLimitConfigSchema,
|
|
229
229
|
TimeoutConfigSchema,
|
|
@@ -281,7 +281,6 @@ export const AssistantConfigSchema = z
|
|
|
281
281
|
"Custom pricing overrides for specific provider/model combinations",
|
|
282
282
|
),
|
|
283
283
|
heartbeat: HeartbeatConfigSchema.default(HeartbeatConfigSchema.parse({})),
|
|
284
|
-
swarm: SwarmConfigSchema.default(SwarmConfigSchema.parse({})),
|
|
285
284
|
mcp: McpConfigSchema.default(McpConfigSchema.parse({})),
|
|
286
285
|
acp: AcpConfigSchema.default(AcpConfigSchema.parse({})),
|
|
287
286
|
skills: SkillsConfigSchema.default(SkillsConfigSchema.parse({})),
|
|
@@ -293,6 +292,7 @@ export const AssistantConfigSchema = z
|
|
|
293
292
|
elevenlabs: ElevenLabsConfigSchema.default(
|
|
294
293
|
ElevenLabsConfigSchema.parse({}),
|
|
295
294
|
),
|
|
295
|
+
fishAudio: FishAudioConfigSchema.default(FishAudioConfigSchema.parse({})),
|
|
296
296
|
whatsapp: WhatsAppConfigSchema.default(WhatsAppConfigSchema.parse({})),
|
|
297
297
|
telegram: TelegramConfigSchema.default(TelegramConfigSchema.parse({})),
|
|
298
298
|
slack: SlackConfigSchema.default(SlackConfigSchema.parse({})),
|
|
@@ -303,15 +303,6 @@ export const AssistantConfigSchema = z
|
|
|
303
303
|
NotificationsConfigSchema.parse({}),
|
|
304
304
|
),
|
|
305
305
|
ui: UiConfigSchema.default(UiConfigSchema.parse({})),
|
|
306
|
-
assistantFeatureFlagValues: z
|
|
307
|
-
.record(
|
|
308
|
-
z.string(),
|
|
309
|
-
z.boolean({
|
|
310
|
-
error: "assistantFeatureFlagValues values must be booleans",
|
|
311
|
-
}),
|
|
312
|
-
)
|
|
313
|
-
.optional()
|
|
314
|
-
.describe("Feature flag overrides — map of flag names to boolean values"),
|
|
315
306
|
collectUsageData: z
|
|
316
307
|
.boolean()
|
|
317
308
|
.default(true)
|
|
@@ -6,6 +6,7 @@ export const VALID_CALLER_IDENTITY_MODES = [
|
|
|
6
6
|
"user_number",
|
|
7
7
|
] as const;
|
|
8
8
|
const VALID_CALL_TRANSCRIPTION_PROVIDERS = ["Deepgram", "Google"] as const;
|
|
9
|
+
export const VALID_TTS_PROVIDERS = ["elevenlabs", "fish-audio"] as const;
|
|
9
10
|
|
|
10
11
|
export const CallsDisclosureConfigSchema = z
|
|
11
12
|
.object({
|
|
@@ -57,6 +58,18 @@ export const CallsVoiceConfigSchema = z
|
|
|
57
58
|
})
|
|
58
59
|
.default("Deepgram")
|
|
59
60
|
.describe("Speech-to-text provider used for call transcription"),
|
|
61
|
+
speechModel: z
|
|
62
|
+
.string({ error: "calls.voice.speechModel must be a string" })
|
|
63
|
+
.optional()
|
|
64
|
+
.describe(
|
|
65
|
+
"ASR model to use for speech recognition (e.g. nova-3, nova-2-phonecall for Deepgram; telephony, long for Google)",
|
|
66
|
+
),
|
|
67
|
+
ttsProvider: z
|
|
68
|
+
.enum(VALID_TTS_PROVIDERS, {
|
|
69
|
+
error: `calls.voice.ttsProvider must be one of: ${VALID_TTS_PROVIDERS.join(", ")}`,
|
|
70
|
+
})
|
|
71
|
+
.default("elevenlabs")
|
|
72
|
+
.describe("Text-to-speech provider for phone calls"),
|
|
60
73
|
})
|
|
61
74
|
.describe("Voice and speech settings for phone calls");
|
|
62
75
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const FishAudioConfigSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
referenceId: z
|
|
6
|
+
.string({ error: "fishAudio.referenceId must be a string" })
|
|
7
|
+
.default("")
|
|
8
|
+
.describe("Fish Audio voice/clone reference ID"),
|
|
9
|
+
chunkLength: z
|
|
10
|
+
.number({ error: "fishAudio.chunkLength must be a number" })
|
|
11
|
+
.int("fishAudio.chunkLength must be an integer")
|
|
12
|
+
.min(100, "fishAudio.chunkLength must be >= 100")
|
|
13
|
+
.max(300, "fishAudio.chunkLength must be <= 300")
|
|
14
|
+
.default(200)
|
|
15
|
+
.describe("Text chunk size for streaming synthesis"),
|
|
16
|
+
format: z
|
|
17
|
+
.enum(["mp3", "wav", "opus"], {
|
|
18
|
+
error: "fishAudio.format must be one of: mp3, wav, opus",
|
|
19
|
+
})
|
|
20
|
+
.default("mp3")
|
|
21
|
+
.describe("Output audio format"),
|
|
22
|
+
latency: z
|
|
23
|
+
.enum(["normal", "balanced"], {
|
|
24
|
+
error: "fishAudio.latency must be one of: normal, balanced",
|
|
25
|
+
})
|
|
26
|
+
.default("normal")
|
|
27
|
+
.describe(
|
|
28
|
+
"Latency/quality tradeoff for Fish Audio S2 synthesis. 'normal' prioritizes lower latency; 'balanced' trades latency for higher quality.",
|
|
29
|
+
),
|
|
30
|
+
speed: z
|
|
31
|
+
.number({ error: "fishAudio.speed must be a number" })
|
|
32
|
+
.min(0.5, "fishAudio.speed must be >= 0.5")
|
|
33
|
+
.max(2.0, "fishAudio.speed must be <= 2.0")
|
|
34
|
+
.default(1.0)
|
|
35
|
+
.describe("Playback speed multiplier (0.5 = slower, 2.0 = faster)"),
|
|
36
|
+
})
|
|
37
|
+
.describe("Fish Audio text-to-speech configuration");
|
|
38
|
+
|
|
39
|
+
export type FishAudioConfig = z.infer<typeof FishAudioConfigSchema>;
|
|
@@ -50,10 +50,6 @@ export const SecretDetectionConfigSchema = z
|
|
|
50
50
|
.describe(
|
|
51
51
|
"Whether to allow sending a detected secret once (with user confirmation) before redacting future occurrences",
|
|
52
52
|
),
|
|
53
|
-
blockIngress: z
|
|
54
|
-
.boolean({ error: "secretDetection.blockIngress must be a boolean" })
|
|
55
|
-
.default(true)
|
|
56
|
-
.describe("Whether to block secrets in incoming ingress messages"),
|
|
57
53
|
customPatterns: z
|
|
58
54
|
.array(CustomSecretPatternSchema)
|
|
59
55
|
.optional()
|
package/src/config/types.ts
CHANGED
|
@@ -28,6 +28,36 @@ function escapeLike(value: string): string {
|
|
|
28
28
|
return value.replace(/%/g, "").replace(/_/g, "");
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Generate a collision-free slugified filename for a contact's per-user persona file.
|
|
33
|
+
* Produces filenames like "alice.md", "alice-2.md", "alice-3.md", etc.
|
|
34
|
+
*/
|
|
35
|
+
export function generateUserFileSlug(displayName: string): string {
|
|
36
|
+
const slug =
|
|
37
|
+
displayName
|
|
38
|
+
.toLowerCase()
|
|
39
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
40
|
+
.replace(/^-+|-+$/g, "")
|
|
41
|
+
.slice(0, 50) || "user";
|
|
42
|
+
|
|
43
|
+
const db = getDb();
|
|
44
|
+
const rows = db
|
|
45
|
+
.select({ userFile: contacts.userFile })
|
|
46
|
+
.from(contacts)
|
|
47
|
+
.where(like(contacts.userFile, `${escapeLike(slug)}%`))
|
|
48
|
+
.all();
|
|
49
|
+
|
|
50
|
+
const taken = new Set(rows.map((r) => r.userFile));
|
|
51
|
+
|
|
52
|
+
const base = `${slug}.md`;
|
|
53
|
+
if (!taken.has(base)) return base;
|
|
54
|
+
|
|
55
|
+
for (let i = 2; ; i++) {
|
|
56
|
+
const candidate = `${slug}-${i}.md`;
|
|
57
|
+
if (!taken.has(candidate)) return candidate;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
31
61
|
function parseContact(row: typeof contacts.$inferSelect): Contact {
|
|
32
62
|
return {
|
|
33
63
|
id: row.id,
|
|
@@ -40,6 +70,7 @@ function parseContact(row: typeof contacts.$inferSelect): Contact {
|
|
|
40
70
|
role: row.role as Contact["role"],
|
|
41
71
|
contactType: (row.contactType as Contact["contactType"]) ?? "human",
|
|
42
72
|
principalId: row.principalId,
|
|
73
|
+
userFile: row.userFile ?? null,
|
|
43
74
|
};
|
|
44
75
|
}
|
|
45
76
|
|
|
@@ -148,6 +179,7 @@ export function upsertContact(params: {
|
|
|
148
179
|
role?: ContactRole;
|
|
149
180
|
contactType?: ContactType;
|
|
150
181
|
principalId?: string | null;
|
|
182
|
+
userFile?: string | null;
|
|
151
183
|
channels?: SyncChannelData[];
|
|
152
184
|
/** When true, conflicting channels on other contacts are reassigned to this
|
|
153
185
|
* contact instead of being skipped. Used by invite redemption to bind a
|
|
@@ -177,6 +209,7 @@ export function upsertContact(params: {
|
|
|
177
209
|
updateSet.contactType = params.contactType;
|
|
178
210
|
if (params.principalId !== undefined)
|
|
179
211
|
updateSet.principalId = params.principalId;
|
|
212
|
+
if (params.userFile !== undefined) updateSet.userFile = params.userFile;
|
|
180
213
|
|
|
181
214
|
db.update(contacts)
|
|
182
215
|
.set(updateSet)
|
|
@@ -224,6 +257,7 @@ export function upsertContact(params: {
|
|
|
224
257
|
updateSet.contactType = params.contactType;
|
|
225
258
|
if (params.principalId !== undefined)
|
|
226
259
|
updateSet.principalId = params.principalId;
|
|
260
|
+
if (params.userFile !== undefined) updateSet.userFile = params.userFile;
|
|
227
261
|
|
|
228
262
|
db.update(contacts)
|
|
229
263
|
.set(updateSet)
|
|
@@ -239,6 +273,10 @@ export function upsertContact(params: {
|
|
|
239
273
|
|
|
240
274
|
// Create new contact
|
|
241
275
|
contactId = contactId ?? uuid();
|
|
276
|
+
const userFileValue =
|
|
277
|
+
params.userFile !== undefined
|
|
278
|
+
? params.userFile
|
|
279
|
+
: generateUserFileSlug(params.displayName);
|
|
242
280
|
db.insert(contacts)
|
|
243
281
|
.values({
|
|
244
282
|
id: contactId,
|
|
@@ -247,6 +285,7 @@ export function upsertContact(params: {
|
|
|
247
285
|
role: params.role ?? "contact",
|
|
248
286
|
contactType: params.contactType ?? "human",
|
|
249
287
|
principalId: params.principalId ?? null,
|
|
288
|
+
userFile: userFileValue ?? null,
|
|
250
289
|
createdAt: now,
|
|
251
290
|
updatedAt: now,
|
|
252
291
|
})
|
package/src/contacts/types.ts
CHANGED
|
@@ -79,6 +79,11 @@ export interface LocalDiscoverySuccess {
|
|
|
79
79
|
executablePath: string;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
export interface LocalSourceDiscoverySuccess {
|
|
83
|
+
mode: "local-source";
|
|
84
|
+
sourcePath: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
82
87
|
export interface ManagedDiscoverySuccess {
|
|
83
88
|
mode: "managed";
|
|
84
89
|
socketPath: string;
|
|
@@ -91,6 +96,7 @@ export interface DiscoveryFailure {
|
|
|
91
96
|
|
|
92
97
|
export type DiscoveryResult =
|
|
93
98
|
| LocalDiscoverySuccess
|
|
99
|
+
| LocalSourceDiscoverySuccess
|
|
94
100
|
| ManagedDiscoverySuccess
|
|
95
101
|
| DiscoveryFailure;
|
|
96
102
|
|
|
@@ -101,11 +107,16 @@ export type DiscoveryResult =
|
|
|
101
107
|
/**
|
|
102
108
|
* Discover the local CES executable.
|
|
103
109
|
*
|
|
104
|
-
* Searches well-known paths for the `credential-executor` binary.
|
|
105
|
-
*
|
|
110
|
+
* Searches well-known paths for the `credential-executor` binary. If the
|
|
111
|
+
* compiled binary is not found, falls back to the TypeScript source entry
|
|
112
|
+
* point in the monorepo. Returns a structured result — never throws. If
|
|
113
|
+
* neither the binary nor the source entry point is found, returns
|
|
106
114
|
* `{ mode: "unavailable" }` so the caller can fail closed.
|
|
107
115
|
*/
|
|
108
|
-
export function discoverLocalCes():
|
|
116
|
+
export function discoverLocalCes():
|
|
117
|
+
| LocalDiscoverySuccess
|
|
118
|
+
| LocalSourceDiscoverySuccess
|
|
119
|
+
| DiscoveryFailure {
|
|
109
120
|
const searchPaths = getLocalBinarySearchPaths();
|
|
110
121
|
|
|
111
122
|
for (const candidate of searchPaths) {
|
|
@@ -115,7 +126,20 @@ export function discoverLocalCes(): LocalDiscoverySuccess | DiscoveryFailure {
|
|
|
115
126
|
}
|
|
116
127
|
}
|
|
117
128
|
|
|
118
|
-
|
|
129
|
+
// Fallback: check for source entry point in the monorepo
|
|
130
|
+
const monorepoRoot = join(import.meta.dir, "..", "..", "..", "..");
|
|
131
|
+
const sourceEntry = join(
|
|
132
|
+
monorepoRoot,
|
|
133
|
+
"credential-executor",
|
|
134
|
+
"src",
|
|
135
|
+
"main.ts",
|
|
136
|
+
);
|
|
137
|
+
if (existsSync(sourceEntry)) {
|
|
138
|
+
log.info({ path: sourceEntry }, "Found local CES source entry point");
|
|
139
|
+
return { mode: "local-source", sourcePath: sourceEntry };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const reason = `CES executable not found. Searched: ${searchPaths.join(", ")}; also checked source at ${sourceEntry}`;
|
|
119
143
|
log.warn(reason);
|
|
120
144
|
return { mode: "unavailable", reason };
|
|
121
145
|
}
|
|
@@ -35,6 +35,10 @@ export const CES_GRANT_AUDIT_FLAG_KEY =
|
|
|
35
35
|
export const CES_MANAGED_SIDECAR_FLAG_KEY =
|
|
36
36
|
"feature_flags.ces-managed-sidecar.enabled" as const;
|
|
37
37
|
|
|
38
|
+
/** Gate for routing credential reads/writes through the CES process. */
|
|
39
|
+
export const CES_CREDENTIAL_BACKEND_FLAG_KEY =
|
|
40
|
+
"feature_flags.ces-credential-backend.enabled" as const;
|
|
41
|
+
|
|
38
42
|
// ---------------------------------------------------------------------------
|
|
39
43
|
// Public API — predicate functions
|
|
40
44
|
// ---------------------------------------------------------------------------
|
|
@@ -73,3 +77,15 @@ export function isCesGrantAuditEnabled(config: AssistantConfig): boolean {
|
|
|
73
77
|
export function isCesManagedSidecarEnabled(config: AssistantConfig): boolean {
|
|
74
78
|
return isAssistantFeatureFlagEnabled(CES_MANAGED_SIDECAR_FLAG_KEY, config);
|
|
75
79
|
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Whether credential reads and writes should be routed through the CES process.
|
|
83
|
+
*/
|
|
84
|
+
export function isCesCredentialBackendEnabled(
|
|
85
|
+
config: AssistantConfig,
|
|
86
|
+
): boolean {
|
|
87
|
+
return isAssistantFeatureFlagEnabled(
|
|
88
|
+
CES_CREDENTIAL_BACKEND_FLAG_KEY,
|
|
89
|
+
config,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
discoverLocalCes,
|
|
39
39
|
type DiscoveryResult,
|
|
40
40
|
type LocalDiscoverySuccess,
|
|
41
|
+
type LocalSourceDiscoverySuccess,
|
|
41
42
|
type ManagedDiscoverySuccess,
|
|
42
43
|
} from "./executable-discovery.js";
|
|
43
44
|
import { isCesManagedSidecarEnabled } from "./feature-gates.js";
|
|
@@ -156,6 +157,12 @@ export function createCesProcessManager(
|
|
|
156
157
|
return transport;
|
|
157
158
|
}
|
|
158
159
|
|
|
160
|
+
if (discoveryResult.mode === "local-source") {
|
|
161
|
+
const transport = await startLocalSourceProcess(discoveryResult);
|
|
162
|
+
running = true;
|
|
163
|
+
return transport;
|
|
164
|
+
}
|
|
165
|
+
|
|
159
166
|
// managed mode
|
|
160
167
|
const transport = await connectManagedSocket(discoveryResult);
|
|
161
168
|
running = true;
|
|
@@ -235,6 +242,37 @@ export function createCesProcessManager(
|
|
|
235
242
|
return createStdioTransport(proc);
|
|
236
243
|
}
|
|
237
244
|
|
|
245
|
+
// -------------------------------------------------------------------------
|
|
246
|
+
// Local source mode — child process over stdio (bun run)
|
|
247
|
+
// -------------------------------------------------------------------------
|
|
248
|
+
|
|
249
|
+
async function startLocalSourceProcess(
|
|
250
|
+
discovery: LocalSourceDiscoverySuccess,
|
|
251
|
+
): Promise<CesTransport> {
|
|
252
|
+
log.info(
|
|
253
|
+
{ sourcePath: discovery.sourcePath },
|
|
254
|
+
"Spawning CES child process from source",
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
const proc = Bun.spawn({
|
|
258
|
+
cmd: ["bun", "run", discovery.sourcePath],
|
|
259
|
+
stdin: "pipe",
|
|
260
|
+
stdout: "pipe",
|
|
261
|
+
stderr: "ignore",
|
|
262
|
+
env: {
|
|
263
|
+
...process.env,
|
|
264
|
+
// Signal to CES that it was launched by the assistant
|
|
265
|
+
CES_LAUNCHED_BY: "assistant",
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
childProcess = proc;
|
|
270
|
+
|
|
271
|
+
log.info({ pid: proc.pid }, "CES child process started (from source)");
|
|
272
|
+
|
|
273
|
+
return createStdioTransport(proc);
|
|
274
|
+
}
|
|
275
|
+
|
|
238
276
|
// -------------------------------------------------------------------------
|
|
239
277
|
// Managed mode — Unix socket connection
|
|
240
278
|
// -------------------------------------------------------------------------
|
|
@@ -76,6 +76,15 @@ const EXTENSION_MIME_MAP: Record<string, string> = {
|
|
|
76
76
|
js: "text/javascript",
|
|
77
77
|
ts: "text/typescript",
|
|
78
78
|
|
|
79
|
+
// Audio
|
|
80
|
+
mp3: "audio/mpeg",
|
|
81
|
+
wav: "audio/wav",
|
|
82
|
+
ogg: "audio/ogg",
|
|
83
|
+
flac: "audio/flac",
|
|
84
|
+
aac: "audio/aac",
|
|
85
|
+
m4a: "audio/x-m4a",
|
|
86
|
+
opus: "audio/opus",
|
|
87
|
+
|
|
79
88
|
// Video
|
|
80
89
|
mp4: "video/mp4",
|
|
81
90
|
webm: "video/webm",
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
|
|
15
|
+
import { clearFeatureFlagOverridesCache } from "../config/assistant-feature-flags.js";
|
|
15
16
|
import { getConfig, invalidateConfigCache } from "../config/loader.js";
|
|
16
17
|
import { clearEmbeddingBackendCache } from "../memory/embedding-backend.js";
|
|
17
18
|
import { clearCache as clearTrustCache } from "../permissions/trust-store.js";
|
|
@@ -153,6 +154,10 @@ export class ConfigWatcher {
|
|
|
153
154
|
"trust.json": () => {
|
|
154
155
|
clearTrustCache();
|
|
155
156
|
},
|
|
157
|
+
"feature-flags.json": () => {
|
|
158
|
+
clearFeatureFlagOverridesCache();
|
|
159
|
+
onConversationEvict();
|
|
160
|
+
},
|
|
156
161
|
"secret-allowlist.json": () => {
|
|
157
162
|
resetAllowlist();
|
|
158
163
|
try {
|