@agenticmail/core 0.9.39 → 0.9.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1644,6 +1644,7 @@ __export(index_exports, {
1644
1644
  personaPathFor: () => personaPathFor,
1645
1645
  planBridgeWake: () => planBridgeWake,
1646
1646
  pollForOperatorAnswer: () => pollForOperatorAnswer,
1647
+ readAgentPersonaFile: () => readAgentPersonaFile,
1647
1648
  recallMemory: () => recallMemory,
1648
1649
  recordToolCall: () => recordToolCall,
1649
1650
  redactBotToken: () => redactBotToken,
@@ -1682,6 +1683,7 @@ __export(index_exports, {
1682
1683
  threadIdFor: () => threadIdFor,
1683
1684
  tokenize: () => tokenize,
1684
1685
  tryJoin: () => tryJoin,
1686
+ updateAgentPersonaFrontmatter: () => updateAgentPersonaFrontmatter,
1685
1687
  userSkillsDir: () => userSkillsDir,
1686
1688
  validateApiUrl: () => validateApiUrl,
1687
1689
  validatePhoneMissionPolicy: () => validatePhoneMissionPolicy,
@@ -7813,7 +7815,14 @@ function validatePhoneMissionPolicy(policy) {
7813
7815
  // manager) can read a concrete value without juggling undefined.
7814
7816
  // Caller-omitted → DEFAULT_*. Caller-set → clamped to server caps.
7815
7817
  extensionPolicy: resolveExtensionPolicy(policy.extensionPolicy),
7816
- callbackPolicy: resolveCallbackPolicy(policy.callbackPolicy)
7818
+ callbackPolicy: resolveCallbackPolicy(policy.callbackPolicy),
7819
+ // v0.9.95 — voice-runtime overrides. Pass-through; the registry
7820
+ // validates the provider id and voice-against-catalogue at
7821
+ // session-open time so we don't have to import the registry
7822
+ // here (would create a cycle with realtime-bridge.ts).
7823
+ voiceRuntime: typeof policy.voiceRuntime === "string" && policy.voiceRuntime.trim() ? policy.voiceRuntime.trim() : void 0,
7824
+ voiceModel: typeof policy.voiceModel === "string" && policy.voiceModel.trim() ? policy.voiceModel.trim() : void 0,
7825
+ voice: typeof policy.voice === "string" && policy.voice.trim() ? policy.voice.trim() : void 0
7817
7826
  },
7818
7827
  issues: []
7819
7828
  };
@@ -12267,13 +12276,42 @@ function resolveVoiceRuntime(providerId, config, options = {}) {
12267
12276
  }
12268
12277
  const model = options.model && options.model.trim() || provider.defaultModel;
12269
12278
  const url = `${provider.websocketBaseUrl}?model=${encodeURIComponent(model)}`;
12279
+ let voice = "";
12280
+ let voiceSource = "";
12281
+ const requested = (options.voice || "").trim();
12282
+ if (requested) {
12283
+ if (provider.voices.includes(requested) || provider.customVoicesSupported) {
12284
+ voice = requested;
12285
+ voiceSource = "mission policy";
12286
+ } else {
12287
+ console.warn(
12288
+ `[voice-providers] Voice "${requested}" is not in ${provider.id}'s catalogue (${provider.voices.join(", ")}). Falling through to ${provider.defaultVoice}.`
12289
+ );
12290
+ }
12291
+ }
12292
+ if (!voice) {
12293
+ const installDefault = config.voiceProviderVoices?.[provider.id];
12294
+ if (installDefault && installDefault.trim()) {
12295
+ const v = installDefault.trim();
12296
+ if (provider.voices.includes(v) || provider.customVoicesSupported) {
12297
+ voice = v;
12298
+ voiceSource = `config.voiceProviderVoices.${provider.id}`;
12299
+ }
12300
+ }
12301
+ }
12302
+ if (!voice) {
12303
+ voice = provider.defaultVoice;
12304
+ voiceSource = `${provider.id} default`;
12305
+ }
12270
12306
  return {
12271
12307
  providerId: provider.id,
12272
12308
  providerDisplayName: provider.displayName,
12273
12309
  url,
12274
12310
  model,
12275
12311
  apiKey,
12276
- apiKeySource
12312
+ apiKeySource,
12313
+ voice,
12314
+ voiceSource
12277
12315
  };
12278
12316
  }
12279
12317
 
@@ -12289,7 +12327,13 @@ registerVoiceProvider({
12289
12327
  // before the generic voiceProviderKeys map so existing installs
12290
12328
  // continue to work without migration.
12291
12329
  apiKeyConfigField: "openaiApiKey",
12292
- description: "OpenAI Realtime (gpt-realtime). Default voice runtime; supports linear PCM @ 24 kHz (46elks) and G.711 \xB5-law @ 8 kHz (Twilio) without transcoding."
12330
+ description: "OpenAI Realtime (gpt-realtime). Default voice runtime; supports linear PCM @ 24 kHz (46elks) and G.711 \xB5-law @ 8 kHz (Twilio) without transcoding.",
12331
+ // v0.9.95 — voice catalogue. Names match what the Realtime session
12332
+ // accepts under `audio.output.voice`. `marin` and `cedar` are the
12333
+ // GA gpt-realtime additions; the rest are the legacy roster carried
12334
+ // forward from gpt-4o-realtime-preview.
12335
+ voices: ["alloy", "ash", "ballad", "cedar", "coral", "echo", "marin", "sage", "shimmer", "verse"],
12336
+ defaultVoice: "marin"
12293
12337
  });
12294
12338
 
12295
12339
  // src/phone/voice-providers/grok.ts
@@ -12299,7 +12343,18 @@ registerVoiceProvider({
12299
12343
  websocketBaseUrl: "wss://api.x.ai/v1/realtime",
12300
12344
  defaultModel: "grok-voice-latest",
12301
12345
  apiKeyEnvVar: "XAI_API_KEY",
12302
- description: 'xAI Grok Voice Agent \u2014 OpenAI-Realtime-compatible WebSocket protocol; select via mission policy.voiceRuntime="grok" or env AGENTICMAIL_VOICE_RUNTIME=grok.'
12346
+ description: 'xAI Grok Voice Agent \u2014 OpenAI-Realtime-compatible WebSocket protocol; select via mission policy.voiceRuntime="grok" or env AGENTICMAIL_VOICE_RUNTIME=grok.',
12347
+ // v0.9.95 — voice catalogue. xAI ships 5 expressive built-in
12348
+ // voices for the realtime Voice Agent. Three are explicitly named
12349
+ // in the announcement (Ara, Eve, Leo); the other two are
12350
+ // browsable in console.x.ai's Voice Library along with the
12351
+ // broader 80+ voice catalogue. The full live list is at
12352
+ // GET /v1/tts/voices. We don't try to enumerate all 80+ here —
12353
+ // customVoicesSupported lets operators paste any voice_id from
12354
+ // their console.
12355
+ voices: ["ara", "eve", "leo"],
12356
+ defaultVoice: "ara",
12357
+ customVoicesSupported: true
12303
12358
  });
12304
12359
 
12305
12360
  // src/telemetry.ts
@@ -16435,8 +16490,19 @@ function loadAgentPersona(agentName) {
16435
16490
  const path2 = personaPathFor(agentName);
16436
16491
  try {
16437
16492
  if ((0, import_node_fs15.existsSync)(path2)) {
16438
- const content = (0, import_node_fs15.readFileSync)(path2, "utf-8").trim();
16439
- if (content) return content;
16493
+ const raw = (0, import_node_fs15.readFileSync)(path2, "utf-8");
16494
+ if (raw.trim()) {
16495
+ const text = raw.replace(/\r\n/g, "\n");
16496
+ if (text.startsWith("---\n")) {
16497
+ const close = text.indexOf("\n---", 4);
16498
+ if (close > 0) {
16499
+ let cursor = close + 4;
16500
+ while (cursor < text.length && (text[cursor] === "\n" || text[cursor] === "\r")) cursor++;
16501
+ return text.slice(cursor).trim();
16502
+ }
16503
+ }
16504
+ return text.trim();
16505
+ }
16440
16506
  }
16441
16507
  } catch {
16442
16508
  }
@@ -16456,6 +16522,61 @@ function saveAgentPersona(agentName, content) {
16456
16522
  (0, import_node_fs15.writeFileSync)(path2, content.trim() + "\n", { mode: 420 });
16457
16523
  return path2;
16458
16524
  }
16525
+ function readAgentPersonaFile(agentName) {
16526
+ const path2 = personaPathFor(agentName);
16527
+ let raw = "";
16528
+ try {
16529
+ if ((0, import_node_fs15.existsSync)(path2)) raw = (0, import_node_fs15.readFileSync)(path2, "utf-8");
16530
+ } catch {
16531
+ }
16532
+ if (!raw.trim()) {
16533
+ return { frontmatter: {}, body: loadAgentPersona(agentName) };
16534
+ }
16535
+ const text = raw.replace(/\r\n/g, "\n");
16536
+ if (!text.startsWith("---\n")) {
16537
+ return { frontmatter: {}, body: text.trim() };
16538
+ }
16539
+ const close = text.indexOf("\n---", 4);
16540
+ if (close < 0) {
16541
+ return { frontmatter: {}, body: text.trim() };
16542
+ }
16543
+ const yamlBlock = text.slice(4, close);
16544
+ const bodyStart = close + 4;
16545
+ let cursor = bodyStart;
16546
+ while (cursor < text.length && (text[cursor] === "\n" || text[cursor] === "\r")) cursor++;
16547
+ const body = text.slice(cursor).trim();
16548
+ const frontmatter = {};
16549
+ for (const line of yamlBlock.split("\n")) {
16550
+ const m = /^\s*([A-Za-z][A-Za-z0-9_-]*)\s*:\s*(.*?)\s*$/.exec(line);
16551
+ if (!m) continue;
16552
+ const key = m[1];
16553
+ const value = m[2].replace(/^["']|["']$/g, "");
16554
+ if (key === "voice") frontmatter.voice = value;
16555
+ else if (key === "voiceRuntime") frontmatter.voiceRuntime = value;
16556
+ }
16557
+ return { frontmatter, body };
16558
+ }
16559
+ function updateAgentPersonaFrontmatter(agentName, patch) {
16560
+ const { frontmatter, body } = readAgentPersonaFile(agentName);
16561
+ const merged = { ...frontmatter };
16562
+ if (patch.voice !== void 0) merged.voice = patch.voice;
16563
+ if (patch.voiceRuntime !== void 0) merged.voiceRuntime = patch.voiceRuntime;
16564
+ const lines = [];
16565
+ if (merged.voice && merged.voice.trim()) lines.push(`voice: ${merged.voice.trim()}`);
16566
+ if (merged.voiceRuntime && merged.voiceRuntime.trim()) lines.push(`voiceRuntime: ${merged.voiceRuntime.trim()}`);
16567
+ const path2 = personaPathFor(agentName);
16568
+ const dir2 = path2.substring(0, path2.lastIndexOf("/"));
16569
+ if (!(0, import_node_fs15.existsSync)(dir2)) (0, import_node_fs15.mkdirSync)(dir2, { recursive: true });
16570
+ const content = lines.length > 0 ? `---
16571
+ ${lines.join("\n")}
16572
+ ---
16573
+
16574
+ ${body}
16575
+ ` : `${body}
16576
+ `;
16577
+ (0, import_node_fs15.writeFileSync)(path2, content, { mode: 420 });
16578
+ return path2;
16579
+ }
16459
16580
  // Annotate the CommonJS export names for ESM import in node:
16460
16581
  0 && (module.exports = {
16461
16582
  AGENT_ROLES,
@@ -16650,6 +16771,7 @@ function saveAgentPersona(agentName, content) {
16650
16771
  personaPathFor,
16651
16772
  planBridgeWake,
16652
16773
  pollForOperatorAnswer,
16774
+ readAgentPersonaFile,
16653
16775
  recallMemory,
16654
16776
  recordToolCall,
16655
16777
  redactBotToken,
@@ -16688,6 +16810,7 @@ function saveAgentPersona(agentName, content) {
16688
16810
  threadIdFor,
16689
16811
  tokenize,
16690
16812
  tryJoin,
16813
+ updateAgentPersonaFrontmatter,
16691
16814
  userSkillsDir,
16692
16815
  validateApiUrl,
16693
16816
  validatePhoneMissionPolicy,
package/dist/index.d.cts CHANGED
@@ -238,6 +238,15 @@ interface AgenticMailConfig {
238
238
  * pool. Read from per-provider env vars (e.g. `XAI_API_KEY`) at boot.
239
239
  */
240
240
  voiceProviderKeys?: Record<string, string>;
241
+ /**
242
+ * v0.9.95 — install-wide default voice CHARACTER per provider
243
+ * (e.g. `{ openai: 'cedar', grok: 'ara' }`). Optional — when a
244
+ * provider's slot is empty, the bridge falls back to the
245
+ * provider's own `defaultVoice`. Per-agent persona + per-call
246
+ * mission policy still beat this. The CLI's `agenticmail
247
+ * setup-voice` voice picker writes here.
248
+ */
249
+ voiceProviderVoices?: Record<string, string>;
241
250
  /**
242
251
  * v0.9.93 — default voice-runtime provider id for phone missions
243
252
  * that don't pin one on their own policy. `'openai'` (the existing
@@ -2764,6 +2773,25 @@ interface OpenClawPhoneMissionPolicy {
2764
2773
  * {@link DEFAULT_CALLBACK_POLICY} when omitted.
2765
2774
  */
2766
2775
  callbackPolicy?: PhoneCallbackPolicy;
2776
+ /**
2777
+ * v0.9.95 — voice-runtime provider id ('openai', 'grok', any
2778
+ * future plugin). Per-call override that beats agent persona
2779
+ * frontmatter, install default, and bridge default. Optional.
2780
+ */
2781
+ voiceRuntime?: string;
2782
+ /**
2783
+ * v0.9.95 — model name override (e.g. `'gpt-realtime-mini'` for
2784
+ * cost-tuning, `'grok-voice-fast'` for latency). Optional.
2785
+ */
2786
+ voiceModel?: string;
2787
+ /**
2788
+ * v0.9.95 — voice CHARACTER override (e.g. `'cedar'`, `'ara'`, or
2789
+ * a custom-voice id from Grok). Optional. Validated against the
2790
+ * provider's catalogue at session-open time; unknown names against
2791
+ * a fixed-catalogue provider fall through to the provider default
2792
+ * with a log warning.
2793
+ */
2794
+ voice?: string;
2767
2795
  }
2768
2796
  interface StartPhoneMissionInput {
2769
2797
  to: string;
@@ -3908,6 +3936,28 @@ interface VoiceProvider {
3908
3936
  * Optional — defaults are fine for the standard providers.
3909
3937
  */
3910
3938
  description?: string;
3939
+ /**
3940
+ * v0.9.95 — built-in voice catalogue. The names the operator can
3941
+ * pick when configuring a default voice for the agent or pinning
3942
+ * one per-call. Empty array means "use whatever defaultVoice we
3943
+ * ship" — used by providers like Grok that support arbitrary
3944
+ * voice ids (cloned voices) instead of a fixed list.
3945
+ */
3946
+ voices: string[];
3947
+ /**
3948
+ * v0.9.95 — default voice the bridge picks when neither the
3949
+ * mission policy nor the agent persona pins one. Per-provider:
3950
+ * OpenAI defaults to "marin"; Grok lets the provider pick.
3951
+ */
3952
+ defaultVoice: string;
3953
+ /**
3954
+ * v0.9.95 — true when the provider accepts arbitrary voice ids
3955
+ * beyond `voices` (e.g. Grok's Custom Voices API returns a
3956
+ * `voice_id` that plugs in here). Tells the CLI picker to show a
3957
+ * free-text input + a "paste a custom voice id" option after the
3958
+ * built-in list.
3959
+ */
3960
+ customVoicesSupported?: boolean;
3911
3961
  }
3912
3962
  /**
3913
3963
  * The bridge needs all the inputs needed to open a session in one
@@ -3925,6 +3975,17 @@ interface VoiceRuntimeConnection {
3925
3975
  apiKey: string;
3926
3976
  /** Human-readable source of the key, for boot logs only (e.g. `"env XAI_API_KEY"`). */
3927
3977
  apiKeySource: string;
3978
+ /**
3979
+ * v0.9.95 — resolved voice name (sent in session.update under
3980
+ * `audio.output.voice`). Picked from (in order):
3981
+ * 1. caller-passed `options.voice` (mission policy)
3982
+ * 2. agent persona's `voice:` frontmatter
3983
+ * 3. install default in `config.voiceProviderVoices[<providerId>]`
3984
+ * 4. provider's `defaultVoice` (e.g. OpenAI "marin", Grok "ara")
3985
+ */
3986
+ voice: string;
3987
+ /** Human-readable source of the voice pick, for boot logs / audit. */
3988
+ voiceSource: string;
3928
3989
  }
3929
3990
 
3930
3991
  /**
@@ -3959,6 +4020,7 @@ declare function getVoiceProvider(id: string): VoiceProvider | undefined;
3959
4020
  */
3960
4021
  declare function resolveVoiceRuntime(providerId: string | undefined, config: AgenticMailConfig, options?: {
3961
4022
  model?: string;
4023
+ voice?: string;
3962
4024
  }): VoiceRuntimeConnection;
3963
4025
 
3964
4026
  type PhoneTransportProvider = '46elks' | 'twilio';
@@ -6372,11 +6434,16 @@ declare function buildDefaultPersona(agentName: string): string;
6372
6434
  /** Resolve the per-agent persona path on disk. */
6373
6435
  declare function personaPathFor(agentName: string): string;
6374
6436
  /**
6375
- * Load the persona for {@link agentName}. Auto-creates the file with
6376
- * {@link buildDefaultPersona} content on first read. Idempotent: a
6377
- * second call returns whatever's on disk. Never throws a permission
6378
- * error or filesystem quirk falls back to the in-memory default so the
6379
- * voice / email / telegram path is never crashed by a missing file.
6437
+ * Load the persona BODY for {@link agentName}. Auto-creates the file
6438
+ * with {@link buildDefaultPersona} content on first read. Idempotent.
6439
+ * Never throws a permission error or filesystem quirk falls back
6440
+ * to the in-memory default so the voice / email / telegram path is
6441
+ * never crashed by a missing file.
6442
+ *
6443
+ * v0.9.95 — if the file has YAML frontmatter (voice / voiceRuntime
6444
+ * keys, written by `agenticmail persona --voice <name>`), the
6445
+ * frontmatter is stripped from the returned string. Use
6446
+ * {@link readAgentPersonaFile} to get the parsed frontmatter too.
6380
6447
  */
6381
6448
  declare function loadAgentPersona(agentName: string): string;
6382
6449
  /**
@@ -6384,5 +6451,43 @@ declare function loadAgentPersona(agentName: string): string;
6384
6451
  * edit command. Returns the path written to.
6385
6452
  */
6386
6453
  declare function saveAgentPersona(agentName: string, content: string): string;
6454
+ /**
6455
+ * v0.9.95 — structured per-agent voice preferences. Stored as YAML
6456
+ * frontmatter at the top of the persona file:
6457
+ *
6458
+ * ---
6459
+ * voice: cedar
6460
+ * voiceRuntime: openai
6461
+ * ---
6462
+ * # Who you are
6463
+ * ...
6464
+ *
6465
+ * Both fields optional. Unknown keys are ignored on read. The CLI's
6466
+ * `agenticmail persona --voice <name>` writes here. The realtime
6467
+ * bridge consults this between the mission policy and the install
6468
+ * default so an agent can have a consistent voice across every call
6469
+ * without the caller pinning it on every invocation.
6470
+ */
6471
+ interface AgentPersonaFrontmatter {
6472
+ voice?: string;
6473
+ voiceRuntime?: string;
6474
+ }
6475
+ /**
6476
+ * Read frontmatter + body from the persona file. Best-effort; missing
6477
+ * file returns empty frontmatter + an auto-seeded body. Robust to:
6478
+ * - No frontmatter at all (legacy files written before 0.9.95).
6479
+ * - Frontmatter with leading whitespace / CRLF.
6480
+ * - Junk lines in the YAML block — we only pick the keys we know.
6481
+ */
6482
+ declare function readAgentPersonaFile(agentName: string): {
6483
+ frontmatter: AgentPersonaFrontmatter;
6484
+ body: string;
6485
+ };
6486
+ /**
6487
+ * Update one or more frontmatter keys on an agent's persona file.
6488
+ * Preserves the existing body. Auto-seeds the body if the file
6489
+ * didn't exist yet.
6490
+ */
6491
+ declare function updateAgentPersonaFrontmatter(agentName: string, patch: AgentPersonaFrontmatter): string;
6387
6492
 
6388
- export { AGENT_ROLES, AGENT_STATE_ROOT, ASK_OPERATOR_TOOL, AccountManager, type AddressInfo, type Agent, AgentDeletionService, type AgentMemoryEntry, type AgentMemoryFields, AgentMemoryManager, type AgentMemoryOptions, type AgentMemoryRead, AgentMemoryStore, type AgentRole, AgenticMailClient, type AgenticMailClientOptions, type AgenticMailConfig, type ArchiveAndDeleteOptions, type ArchivedEmail, type Attachment, type AttachmentAdvisory, type AudioAction, type AudioEditOptions, BRIDGE_OPERATOR_LIVE_WINDOW_MS, type BridgeMailContext, type BridgeWakeError, type BridgeWakePromptArgs, type BridgeWakeResult, type BridgeWakeRoute, type CachedMessage, CloudflareClient, type CreateAgentOptions, type CreateMemoryInput, DEFAULT_AGENT_NAME, DEFAULT_AGENT_ROLE, DEFAULT_CALLBACK_POLICY, DEFAULT_EXTENSION_POLICY, DEFAULT_REALTIME_AUDIO_FORMAT, DEFAULT_REALTIME_MODEL, DEFAULT_REALTIME_VOICE, DEFAULT_SESSION_MAX_AGE_MS, DEFAULT_WEB_SEARCH_ENDPOINT, DNSConfigurator, type Database, type DeletionReport, type DeletionSummary, DependencyChecker, DependencyInstaller, type DependencyStatus, type DnsRecord, type DnsSetupResult, type DomainInfo, DomainManager, type DomainModeConfig, type DomainPurchaseResult, DomainPurchaser, type DomainSearchResult, type DomainSetupResult, ELKS_REALTIME_AUDIO_FORMATS, ELKS_REALTIME_WS_PATH, END_CALL_TOOL, EXTEND_CALL_TIME_TOOL, type ElksRealtimeAudioFormat, type ElksRealtimeAudioMessage, type ElksRealtimeByeMessage, type ElksRealtimeHelloMessage, type ElksRealtimeInboundMessage, type ElksRealtimeOutboundMessage, ElksRealtimeTransport, type EmailEnvelope, type EmailRouteAction, type EmailRouteClass, type EmailRouteClassification, type EmailRouteInput, EmailSearchIndex, type FolderInfo, GET_CALL_STATUS_TOOL, GET_DATETIME_TOOL, type GatewayConfig, GatewayManager, type GatewayManagerOptions, type GatewayMode, type GatewayStatus, type GetDatetimeOptions, type GetUpdatesOptions, type HostName, type HostSession, type HostSessionResumeMode, type ImageAction, type ImageEditOptions, type InboundEmail, type InboundSmsEvent, type InboxEvent, type InboxExpungeEvent, type InboxFlagsEvent, type InboxNewEvent, InboxWatcher, type InboxWatcherOptions, type InstallProgress, LOAD_SKILL_TOOL, type LinkAdvisory, type LocalSmtpConfig, MEMORY_CATEGORIES, MailReceiver, type MailReceiverOptions, MailSender, type MailSenderOptions, type MailboxInfo, type MediaBinary, type MediaCapability, type MediaCapabilityReport, type MediaFileResult, type MediaInfoResult, MediaManager, type MediaManagerOptions, type MediaStreamInfo, type MemoryCategory, type MemoryImportance, type MemoryQueryOptions, type MemoryRecaller, MemorySearchIndex, type MemorySource, type MemoryStats, OPENAI_REALTIME_URL, OPERATOR_QUERY_POLL_INTERVAL_MS, OPERATOR_QUERY_SUBJECT_TAG, OPERATOR_QUERY_TIMEOUT_MS, OPERATOR_QUERY_TIMEOUT_SENTINEL, type OpenClawPhoneMissionPolicy, type OperatorQueryNotificationInput, type OperatorQueryPollOptions, type OperatorQueryUrgency, type OperatorReplyKind, type OutboundCategory, type OutboundScanInput, type OutboundScanResult, type OutboundWarning, PERSONA_FILENAME, PHONE_CALLBACK_MAX_DELAY_SECONDS, PHONE_CALLBACK_MIN_DELAY_SECONDS, PHONE_CALL_CONTROL_PROVIDERS, PHONE_MAX_CONCURRENT_MISSIONS, PHONE_MIN_WEBHOOK_SECRET_LENGTH, PHONE_MISSION_STATES, PHONE_RATE_LIMIT_PER_HOUR, PHONE_RATE_LIMIT_PER_MINUTE, PHONE_REGION_SCOPES, PHONE_SERVER_MAX_ATTEMPTS, PHONE_SERVER_MAX_CALLBACK_CHAIN, PHONE_SERVER_MAX_CALL_DURATION_SECONDS, PHONE_SERVER_MAX_COST_PER_MISSION, PHONE_SERVER_MAX_EXTENSION_REQUESTS_PER_CALL, PHONE_SERVER_MAX_EXTENSION_SECONDS_PER_REQUEST, PHONE_SERVER_MAX_TOTAL_EXTENSION_SECONDS, PHONE_TASK_MAX_LENGTH, type ParsedAttachment, type ParsedEmail, type ParsedOperatorReply, type ParsedSms, type ParsedTelegramMessage, PathTraversalError, type PhoneAlternativePolicy, type PhoneCallMission, type PhoneCallbackPolicy, type PhoneConfirmPolicy, type PhoneExtensionPolicy, PhoneManager, type PhoneMissionStartValidationResult, type PhoneMissionState, type PhoneMissionTranscriptEntry, type PhoneMissionValidationIssue, type PhoneMissionValidationResult, type PhoneNumberRisk, type PhoneOperatorQuery, PhoneRateLimitError, type PhoneRegionScope, type PhoneScheduledCallback, type PhoneTransportConfig, type PhoneTransportProfile, type PhoneTransportProvider, type PhoneTransportValidationResult, PhoneWebhookAuthError, type PhoneWebhookResult, type PlanBridgeWakeArgs, type PurchasedDomain, REALTIME_AUDIO_SAMPLE_RATE, REALTIME_MAX_AUDIO_FRAME_BASE64, REALTIME_TOOL_CALL_TIMEOUT_MS, REALTIME_TOOL_DEFINITIONS, RECALL_MEMORY_TOOL, REDACTED, RELAY_PRESETS, type RealtimeBridgePort, type RealtimeBridgeTranscriptEntry, type RealtimeInboundEvent, type RealtimeInstructionOptions, type RealtimeSessionConfigOptions, type RealtimeToolCall, type RealtimeToolDefinition, type RealtimeToolHandler, type RealtimeToolResult, type RealtimeTransportAdapter, type RealtimeTransportProvider, RealtimeVoiceBridge, type RealtimeVoiceBridgeOptions, RelayBridge, type RelayBridgeOptions, type RelayConfig, RelayGateway, type RelayProvider, type RelaySearchResult, type ResumeErrorClassificationOptions, SCHEDULE_CALLBACK_TOOL, SEARCH_EMAIL_TOOL, SEARCH_SKILLS_TOOL, SPAM_THRESHOLD, type SafeJoinOptions, type SanitizeDetection, type SanitizeResult, type ScheduledCallbackRequest, type SearchCriteria, type SearchableEmail, type SecurityAdvisory, type SendMailOptions, type SendResult, type SendResultWithRaw, type SendSmsInput, type SendSmsResult, type SendTelegramMessageOptions, type SendTelegramMessageResult, ServiceManager, type ServiceStatus, type SetWebhookOptions, type SetupConfig, SetupManager, type SetupResult, type Severity, type Skill, type SkillCategory, type SkillContext, type SkillExitStrategy, type SkillSummary, type SkillTactic, type SkillValidationError, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, type SmsProvider, type SpamCategory, type SpamResult, type SpamRuleMatch, StalwartAdmin, type StalwartAdminOptions, type StalwartPrincipal, type StartPhoneCallOptions, type StartPhoneCallResult, type StartPhoneMissionInput, TELEGRAM_API_BASE, TELEGRAM_CHUNK_SIZE, TELEGRAM_MESSAGE_LIMIT, TELEGRAM_MIN_WEBHOOK_SECRET_LENGTH, TELEGRAM_OPERATOR_QUERY_TAG, TELEGRAM_STOP_WORDS, TELEGRAM_WEBHOOK_SECRET_RE, TELEPHONY_TRANSPORT_CAPABILITIES, TWILIO_MEDIA_SAMPLE_RATE, TWILIO_REALTIME_WS_PATH, TelegramApiError, type TelegramApiOptions, type TelegramBotInfo, type TelegramChatType, type TelegramConfig, TelegramManager, type TelegramMessage, type TelegramMode, type TelephonyTransportCapability, ThreadCache, type ThreadCacheEntry, type ThreadCacheOptions, type ThreadIdInput, type ToolExecutor, type TtsGenerateOptions, type TunnelConfig, TunnelManager, type TwilioConnectedMessage, type TwilioMarkMessage, type TwilioMediaMessage, type TwilioRealtimeInboundMessage, type TwilioRealtimeOutboundMessage, TwilioRealtimeTransport, type TwilioStartMessage, type TwilioStopMessage, type TwilioStreamTwiMLOptions, UnsafeApiUrlError, type UpdateMemoryInput, type ValidatedPhoneMissionStart, type VideoAction, type VideoEditOptions, type VideoTimelineEntry, type VideoUnderstandOptions, type VideoUnderstandResult, type VoiceCloneOptions, type VoiceProvider, type VoiceRuntimeConnection, WARNING_THRESHOLD, WEB_SEARCH_TOOL, WEB_SEARCH_UNTRUSTED_PREFIX, type WatcherOptions, type WebSearchOptions, assertWithinBase, bridgeWakeErrorMessage, bridgeWakeLastSeenAgeMs, buildApiUrl, buildDefaultPersona, buildElksAudioMessage, buildElksByeMessage, buildElksHandshakeMessages, buildElksInterruptMessage, buildElksListeningMessage, buildElksSendingMessage, buildInboundSecurityAdvisory, buildOpenAIRealtimeUrl, buildPhoneTransportConfig, buildRealtimeInstructions, buildRealtimeSessionConfig, buildRealtimeToolGuidance, buildTwilioClearMessage, buildTwilioMarkMessage, buildTwilioMediaMessage, buildTwilioSayTwiML, buildTwilioSignature, buildTwilioStreamTwiML, callTelegramApi, classifyEmailRoute, classifyPhoneNumberRisk, classifyResumeError, clearMediaCapabilityCache, closeDatabase, composeBridgeWakePrompt, createRealtimeTransport, createTestDatabase, createToolExecutor, debug, debugWarn, deleteTelegramWebhook, detectBinary, ensureDataDir, escapeXml, extractEmailAddress, extractVerificationCode, flushTelemetry, forgetHostSession, formatOperatorQueryTelegramMessage, getDatabase, getDatetime, getMediaCapabilities, getOperatorEmail, getSmsProvider, getTelegramChat, getTelegramMe, getTelegramUpdates, getTelegramWebhookInfo, getVoiceProvider, hostSessionStoragePath, inferPhoneRegion, invalidateSkillCache, isInternalEmail, isLoopbackMailHost, isOperatorReplySender, isPhoneRegionAllowed, isSessionFresh, isTelegramChatAllowed, isTelegramStopCommand, isValidPhoneNumber, listSkills, listVoiceProviders, loadAgentPersona, loadHostSession, loadSkill, mapProviderSmsStatus, nextTelegramOffset, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, operatorQuerySubject, parseElksRealtimeMessage, parseEmail, parseGoogleVoiceSms, parseOperatorQueryReply, parseTelegramOperatorReply, parseTelegramUpdate, parseTwilioRealtimeMessage, personaPathFor, planBridgeWake, pollForOperatorAnswer, recallMemory, recordToolCall, redactBotToken, redactObject, redactPhoneTransportConfig, redactSecret, redactSmsConfig, redactTelegramConfig, registerVoiceProvider, renderSkillAsPrompt, requireBinary, requireWhisperModel, resolveCallbackPolicy, resolveConfig, resolveExtensionPolicy, resolveTlsRejectUnauthorized, resolveVoiceRuntime, safeJoin, sanitizeEmail, saveAgentPersona, saveConfig, saveHostSession, saveUserSkill, scanOutboundEmail, scoreEmail, searchSkills, sendTelegramMessage, setOperatorEmail, setTelegramWebhook, setTelemetryVersion, shouldSkipBridgeWakeForLiveOperator, splitTelegramMessage, startRelayBridge, stem, stripTelegramMarkdown, threadIdFor, tokenize, tryJoin, userSkillsDir, validateApiUrl, validatePhoneMissionPolicy, validatePhoneMissionStart, validatePhoneTransportProfile, validateSkill, validateTwilioSignature, webSearch };
6493
+ export { AGENT_ROLES, AGENT_STATE_ROOT, ASK_OPERATOR_TOOL, AccountManager, type AddressInfo, type Agent, AgentDeletionService, type AgentMemoryEntry, type AgentMemoryFields, AgentMemoryManager, type AgentMemoryOptions, type AgentMemoryRead, AgentMemoryStore, type AgentPersonaFrontmatter, type AgentRole, AgenticMailClient, type AgenticMailClientOptions, type AgenticMailConfig, type ArchiveAndDeleteOptions, type ArchivedEmail, type Attachment, type AttachmentAdvisory, type AudioAction, type AudioEditOptions, BRIDGE_OPERATOR_LIVE_WINDOW_MS, type BridgeMailContext, type BridgeWakeError, type BridgeWakePromptArgs, type BridgeWakeResult, type BridgeWakeRoute, type CachedMessage, CloudflareClient, type CreateAgentOptions, type CreateMemoryInput, DEFAULT_AGENT_NAME, DEFAULT_AGENT_ROLE, DEFAULT_CALLBACK_POLICY, DEFAULT_EXTENSION_POLICY, DEFAULT_REALTIME_AUDIO_FORMAT, DEFAULT_REALTIME_MODEL, DEFAULT_REALTIME_VOICE, DEFAULT_SESSION_MAX_AGE_MS, DEFAULT_WEB_SEARCH_ENDPOINT, DNSConfigurator, type Database, type DeletionReport, type DeletionSummary, DependencyChecker, DependencyInstaller, type DependencyStatus, type DnsRecord, type DnsSetupResult, type DomainInfo, DomainManager, type DomainModeConfig, type DomainPurchaseResult, DomainPurchaser, type DomainSearchResult, type DomainSetupResult, ELKS_REALTIME_AUDIO_FORMATS, ELKS_REALTIME_WS_PATH, END_CALL_TOOL, EXTEND_CALL_TIME_TOOL, type ElksRealtimeAudioFormat, type ElksRealtimeAudioMessage, type ElksRealtimeByeMessage, type ElksRealtimeHelloMessage, type ElksRealtimeInboundMessage, type ElksRealtimeOutboundMessage, ElksRealtimeTransport, type EmailEnvelope, type EmailRouteAction, type EmailRouteClass, type EmailRouteClassification, type EmailRouteInput, EmailSearchIndex, type FolderInfo, GET_CALL_STATUS_TOOL, GET_DATETIME_TOOL, type GatewayConfig, GatewayManager, type GatewayManagerOptions, type GatewayMode, type GatewayStatus, type GetDatetimeOptions, type GetUpdatesOptions, type HostName, type HostSession, type HostSessionResumeMode, type ImageAction, type ImageEditOptions, type InboundEmail, type InboundSmsEvent, type InboxEvent, type InboxExpungeEvent, type InboxFlagsEvent, type InboxNewEvent, InboxWatcher, type InboxWatcherOptions, type InstallProgress, LOAD_SKILL_TOOL, type LinkAdvisory, type LocalSmtpConfig, MEMORY_CATEGORIES, MailReceiver, type MailReceiverOptions, MailSender, type MailSenderOptions, type MailboxInfo, type MediaBinary, type MediaCapability, type MediaCapabilityReport, type MediaFileResult, type MediaInfoResult, MediaManager, type MediaManagerOptions, type MediaStreamInfo, type MemoryCategory, type MemoryImportance, type MemoryQueryOptions, type MemoryRecaller, MemorySearchIndex, type MemorySource, type MemoryStats, OPENAI_REALTIME_URL, OPERATOR_QUERY_POLL_INTERVAL_MS, OPERATOR_QUERY_SUBJECT_TAG, OPERATOR_QUERY_TIMEOUT_MS, OPERATOR_QUERY_TIMEOUT_SENTINEL, type OpenClawPhoneMissionPolicy, type OperatorQueryNotificationInput, type OperatorQueryPollOptions, type OperatorQueryUrgency, type OperatorReplyKind, type OutboundCategory, type OutboundScanInput, type OutboundScanResult, type OutboundWarning, PERSONA_FILENAME, PHONE_CALLBACK_MAX_DELAY_SECONDS, PHONE_CALLBACK_MIN_DELAY_SECONDS, PHONE_CALL_CONTROL_PROVIDERS, PHONE_MAX_CONCURRENT_MISSIONS, PHONE_MIN_WEBHOOK_SECRET_LENGTH, PHONE_MISSION_STATES, PHONE_RATE_LIMIT_PER_HOUR, PHONE_RATE_LIMIT_PER_MINUTE, PHONE_REGION_SCOPES, PHONE_SERVER_MAX_ATTEMPTS, PHONE_SERVER_MAX_CALLBACK_CHAIN, PHONE_SERVER_MAX_CALL_DURATION_SECONDS, PHONE_SERVER_MAX_COST_PER_MISSION, PHONE_SERVER_MAX_EXTENSION_REQUESTS_PER_CALL, PHONE_SERVER_MAX_EXTENSION_SECONDS_PER_REQUEST, PHONE_SERVER_MAX_TOTAL_EXTENSION_SECONDS, PHONE_TASK_MAX_LENGTH, type ParsedAttachment, type ParsedEmail, type ParsedOperatorReply, type ParsedSms, type ParsedTelegramMessage, PathTraversalError, type PhoneAlternativePolicy, type PhoneCallMission, type PhoneCallbackPolicy, type PhoneConfirmPolicy, type PhoneExtensionPolicy, PhoneManager, type PhoneMissionStartValidationResult, type PhoneMissionState, type PhoneMissionTranscriptEntry, type PhoneMissionValidationIssue, type PhoneMissionValidationResult, type PhoneNumberRisk, type PhoneOperatorQuery, PhoneRateLimitError, type PhoneRegionScope, type PhoneScheduledCallback, type PhoneTransportConfig, type PhoneTransportProfile, type PhoneTransportProvider, type PhoneTransportValidationResult, PhoneWebhookAuthError, type PhoneWebhookResult, type PlanBridgeWakeArgs, type PurchasedDomain, REALTIME_AUDIO_SAMPLE_RATE, REALTIME_MAX_AUDIO_FRAME_BASE64, REALTIME_TOOL_CALL_TIMEOUT_MS, REALTIME_TOOL_DEFINITIONS, RECALL_MEMORY_TOOL, REDACTED, RELAY_PRESETS, type RealtimeBridgePort, type RealtimeBridgeTranscriptEntry, type RealtimeInboundEvent, type RealtimeInstructionOptions, type RealtimeSessionConfigOptions, type RealtimeToolCall, type RealtimeToolDefinition, type RealtimeToolHandler, type RealtimeToolResult, type RealtimeTransportAdapter, type RealtimeTransportProvider, RealtimeVoiceBridge, type RealtimeVoiceBridgeOptions, RelayBridge, type RelayBridgeOptions, type RelayConfig, RelayGateway, type RelayProvider, type RelaySearchResult, type ResumeErrorClassificationOptions, SCHEDULE_CALLBACK_TOOL, SEARCH_EMAIL_TOOL, SEARCH_SKILLS_TOOL, SPAM_THRESHOLD, type SafeJoinOptions, type SanitizeDetection, type SanitizeResult, type ScheduledCallbackRequest, type SearchCriteria, type SearchableEmail, type SecurityAdvisory, type SendMailOptions, type SendResult, type SendResultWithRaw, type SendSmsInput, type SendSmsResult, type SendTelegramMessageOptions, type SendTelegramMessageResult, ServiceManager, type ServiceStatus, type SetWebhookOptions, type SetupConfig, SetupManager, type SetupResult, type Severity, type Skill, type SkillCategory, type SkillContext, type SkillExitStrategy, type SkillSummary, type SkillTactic, type SkillValidationError, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, type SmsProvider, type SpamCategory, type SpamResult, type SpamRuleMatch, StalwartAdmin, type StalwartAdminOptions, type StalwartPrincipal, type StartPhoneCallOptions, type StartPhoneCallResult, type StartPhoneMissionInput, TELEGRAM_API_BASE, TELEGRAM_CHUNK_SIZE, TELEGRAM_MESSAGE_LIMIT, TELEGRAM_MIN_WEBHOOK_SECRET_LENGTH, TELEGRAM_OPERATOR_QUERY_TAG, TELEGRAM_STOP_WORDS, TELEGRAM_WEBHOOK_SECRET_RE, TELEPHONY_TRANSPORT_CAPABILITIES, TWILIO_MEDIA_SAMPLE_RATE, TWILIO_REALTIME_WS_PATH, TelegramApiError, type TelegramApiOptions, type TelegramBotInfo, type TelegramChatType, type TelegramConfig, TelegramManager, type TelegramMessage, type TelegramMode, type TelephonyTransportCapability, ThreadCache, type ThreadCacheEntry, type ThreadCacheOptions, type ThreadIdInput, type ToolExecutor, type TtsGenerateOptions, type TunnelConfig, TunnelManager, type TwilioConnectedMessage, type TwilioMarkMessage, type TwilioMediaMessage, type TwilioRealtimeInboundMessage, type TwilioRealtimeOutboundMessage, TwilioRealtimeTransport, type TwilioStartMessage, type TwilioStopMessage, type TwilioStreamTwiMLOptions, UnsafeApiUrlError, type UpdateMemoryInput, type ValidatedPhoneMissionStart, type VideoAction, type VideoEditOptions, type VideoTimelineEntry, type VideoUnderstandOptions, type VideoUnderstandResult, type VoiceCloneOptions, type VoiceProvider, type VoiceRuntimeConnection, WARNING_THRESHOLD, WEB_SEARCH_TOOL, WEB_SEARCH_UNTRUSTED_PREFIX, type WatcherOptions, type WebSearchOptions, assertWithinBase, bridgeWakeErrorMessage, bridgeWakeLastSeenAgeMs, buildApiUrl, buildDefaultPersona, buildElksAudioMessage, buildElksByeMessage, buildElksHandshakeMessages, buildElksInterruptMessage, buildElksListeningMessage, buildElksSendingMessage, buildInboundSecurityAdvisory, buildOpenAIRealtimeUrl, buildPhoneTransportConfig, buildRealtimeInstructions, buildRealtimeSessionConfig, buildRealtimeToolGuidance, buildTwilioClearMessage, buildTwilioMarkMessage, buildTwilioMediaMessage, buildTwilioSayTwiML, buildTwilioSignature, buildTwilioStreamTwiML, callTelegramApi, classifyEmailRoute, classifyPhoneNumberRisk, classifyResumeError, clearMediaCapabilityCache, closeDatabase, composeBridgeWakePrompt, createRealtimeTransport, createTestDatabase, createToolExecutor, debug, debugWarn, deleteTelegramWebhook, detectBinary, ensureDataDir, escapeXml, extractEmailAddress, extractVerificationCode, flushTelemetry, forgetHostSession, formatOperatorQueryTelegramMessage, getDatabase, getDatetime, getMediaCapabilities, getOperatorEmail, getSmsProvider, getTelegramChat, getTelegramMe, getTelegramUpdates, getTelegramWebhookInfo, getVoiceProvider, hostSessionStoragePath, inferPhoneRegion, invalidateSkillCache, isInternalEmail, isLoopbackMailHost, isOperatorReplySender, isPhoneRegionAllowed, isSessionFresh, isTelegramChatAllowed, isTelegramStopCommand, isValidPhoneNumber, listSkills, listVoiceProviders, loadAgentPersona, loadHostSession, loadSkill, mapProviderSmsStatus, nextTelegramOffset, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, operatorQuerySubject, parseElksRealtimeMessage, parseEmail, parseGoogleVoiceSms, parseOperatorQueryReply, parseTelegramOperatorReply, parseTelegramUpdate, parseTwilioRealtimeMessage, personaPathFor, planBridgeWake, pollForOperatorAnswer, readAgentPersonaFile, recallMemory, recordToolCall, redactBotToken, redactObject, redactPhoneTransportConfig, redactSecret, redactSmsConfig, redactTelegramConfig, registerVoiceProvider, renderSkillAsPrompt, requireBinary, requireWhisperModel, resolveCallbackPolicy, resolveConfig, resolveExtensionPolicy, resolveTlsRejectUnauthorized, resolveVoiceRuntime, safeJoin, sanitizeEmail, saveAgentPersona, saveConfig, saveHostSession, saveUserSkill, scanOutboundEmail, scoreEmail, searchSkills, sendTelegramMessage, setOperatorEmail, setTelegramWebhook, setTelemetryVersion, shouldSkipBridgeWakeForLiveOperator, splitTelegramMessage, startRelayBridge, stem, stripTelegramMarkdown, threadIdFor, tokenize, tryJoin, updateAgentPersonaFrontmatter, userSkillsDir, validateApiUrl, validatePhoneMissionPolicy, validatePhoneMissionStart, validatePhoneTransportProfile, validateSkill, validateTwilioSignature, webSearch };
package/dist/index.d.ts CHANGED
@@ -238,6 +238,15 @@ interface AgenticMailConfig {
238
238
  * pool. Read from per-provider env vars (e.g. `XAI_API_KEY`) at boot.
239
239
  */
240
240
  voiceProviderKeys?: Record<string, string>;
241
+ /**
242
+ * v0.9.95 — install-wide default voice CHARACTER per provider
243
+ * (e.g. `{ openai: 'cedar', grok: 'ara' }`). Optional — when a
244
+ * provider's slot is empty, the bridge falls back to the
245
+ * provider's own `defaultVoice`. Per-agent persona + per-call
246
+ * mission policy still beat this. The CLI's `agenticmail
247
+ * setup-voice` voice picker writes here.
248
+ */
249
+ voiceProviderVoices?: Record<string, string>;
241
250
  /**
242
251
  * v0.9.93 — default voice-runtime provider id for phone missions
243
252
  * that don't pin one on their own policy. `'openai'` (the existing
@@ -2764,6 +2773,25 @@ interface OpenClawPhoneMissionPolicy {
2764
2773
  * {@link DEFAULT_CALLBACK_POLICY} when omitted.
2765
2774
  */
2766
2775
  callbackPolicy?: PhoneCallbackPolicy;
2776
+ /**
2777
+ * v0.9.95 — voice-runtime provider id ('openai', 'grok', any
2778
+ * future plugin). Per-call override that beats agent persona
2779
+ * frontmatter, install default, and bridge default. Optional.
2780
+ */
2781
+ voiceRuntime?: string;
2782
+ /**
2783
+ * v0.9.95 — model name override (e.g. `'gpt-realtime-mini'` for
2784
+ * cost-tuning, `'grok-voice-fast'` for latency). Optional.
2785
+ */
2786
+ voiceModel?: string;
2787
+ /**
2788
+ * v0.9.95 — voice CHARACTER override (e.g. `'cedar'`, `'ara'`, or
2789
+ * a custom-voice id from Grok). Optional. Validated against the
2790
+ * provider's catalogue at session-open time; unknown names against
2791
+ * a fixed-catalogue provider fall through to the provider default
2792
+ * with a log warning.
2793
+ */
2794
+ voice?: string;
2767
2795
  }
2768
2796
  interface StartPhoneMissionInput {
2769
2797
  to: string;
@@ -3908,6 +3936,28 @@ interface VoiceProvider {
3908
3936
  * Optional — defaults are fine for the standard providers.
3909
3937
  */
3910
3938
  description?: string;
3939
+ /**
3940
+ * v0.9.95 — built-in voice catalogue. The names the operator can
3941
+ * pick when configuring a default voice for the agent or pinning
3942
+ * one per-call. Empty array means "use whatever defaultVoice we
3943
+ * ship" — used by providers like Grok that support arbitrary
3944
+ * voice ids (cloned voices) instead of a fixed list.
3945
+ */
3946
+ voices: string[];
3947
+ /**
3948
+ * v0.9.95 — default voice the bridge picks when neither the
3949
+ * mission policy nor the agent persona pins one. Per-provider:
3950
+ * OpenAI defaults to "marin"; Grok lets the provider pick.
3951
+ */
3952
+ defaultVoice: string;
3953
+ /**
3954
+ * v0.9.95 — true when the provider accepts arbitrary voice ids
3955
+ * beyond `voices` (e.g. Grok's Custom Voices API returns a
3956
+ * `voice_id` that plugs in here). Tells the CLI picker to show a
3957
+ * free-text input + a "paste a custom voice id" option after the
3958
+ * built-in list.
3959
+ */
3960
+ customVoicesSupported?: boolean;
3911
3961
  }
3912
3962
  /**
3913
3963
  * The bridge needs all the inputs needed to open a session in one
@@ -3925,6 +3975,17 @@ interface VoiceRuntimeConnection {
3925
3975
  apiKey: string;
3926
3976
  /** Human-readable source of the key, for boot logs only (e.g. `"env XAI_API_KEY"`). */
3927
3977
  apiKeySource: string;
3978
+ /**
3979
+ * v0.9.95 — resolved voice name (sent in session.update under
3980
+ * `audio.output.voice`). Picked from (in order):
3981
+ * 1. caller-passed `options.voice` (mission policy)
3982
+ * 2. agent persona's `voice:` frontmatter
3983
+ * 3. install default in `config.voiceProviderVoices[<providerId>]`
3984
+ * 4. provider's `defaultVoice` (e.g. OpenAI "marin", Grok "ara")
3985
+ */
3986
+ voice: string;
3987
+ /** Human-readable source of the voice pick, for boot logs / audit. */
3988
+ voiceSource: string;
3928
3989
  }
3929
3990
 
3930
3991
  /**
@@ -3959,6 +4020,7 @@ declare function getVoiceProvider(id: string): VoiceProvider | undefined;
3959
4020
  */
3960
4021
  declare function resolveVoiceRuntime(providerId: string | undefined, config: AgenticMailConfig, options?: {
3961
4022
  model?: string;
4023
+ voice?: string;
3962
4024
  }): VoiceRuntimeConnection;
3963
4025
 
3964
4026
  type PhoneTransportProvider = '46elks' | 'twilio';
@@ -6372,11 +6434,16 @@ declare function buildDefaultPersona(agentName: string): string;
6372
6434
  /** Resolve the per-agent persona path on disk. */
6373
6435
  declare function personaPathFor(agentName: string): string;
6374
6436
  /**
6375
- * Load the persona for {@link agentName}. Auto-creates the file with
6376
- * {@link buildDefaultPersona} content on first read. Idempotent: a
6377
- * second call returns whatever's on disk. Never throws a permission
6378
- * error or filesystem quirk falls back to the in-memory default so the
6379
- * voice / email / telegram path is never crashed by a missing file.
6437
+ * Load the persona BODY for {@link agentName}. Auto-creates the file
6438
+ * with {@link buildDefaultPersona} content on first read. Idempotent.
6439
+ * Never throws a permission error or filesystem quirk falls back
6440
+ * to the in-memory default so the voice / email / telegram path is
6441
+ * never crashed by a missing file.
6442
+ *
6443
+ * v0.9.95 — if the file has YAML frontmatter (voice / voiceRuntime
6444
+ * keys, written by `agenticmail persona --voice <name>`), the
6445
+ * frontmatter is stripped from the returned string. Use
6446
+ * {@link readAgentPersonaFile} to get the parsed frontmatter too.
6380
6447
  */
6381
6448
  declare function loadAgentPersona(agentName: string): string;
6382
6449
  /**
@@ -6384,5 +6451,43 @@ declare function loadAgentPersona(agentName: string): string;
6384
6451
  * edit command. Returns the path written to.
6385
6452
  */
6386
6453
  declare function saveAgentPersona(agentName: string, content: string): string;
6454
+ /**
6455
+ * v0.9.95 — structured per-agent voice preferences. Stored as YAML
6456
+ * frontmatter at the top of the persona file:
6457
+ *
6458
+ * ---
6459
+ * voice: cedar
6460
+ * voiceRuntime: openai
6461
+ * ---
6462
+ * # Who you are
6463
+ * ...
6464
+ *
6465
+ * Both fields optional. Unknown keys are ignored on read. The CLI's
6466
+ * `agenticmail persona --voice <name>` writes here. The realtime
6467
+ * bridge consults this between the mission policy and the install
6468
+ * default so an agent can have a consistent voice across every call
6469
+ * without the caller pinning it on every invocation.
6470
+ */
6471
+ interface AgentPersonaFrontmatter {
6472
+ voice?: string;
6473
+ voiceRuntime?: string;
6474
+ }
6475
+ /**
6476
+ * Read frontmatter + body from the persona file. Best-effort; missing
6477
+ * file returns empty frontmatter + an auto-seeded body. Robust to:
6478
+ * - No frontmatter at all (legacy files written before 0.9.95).
6479
+ * - Frontmatter with leading whitespace / CRLF.
6480
+ * - Junk lines in the YAML block — we only pick the keys we know.
6481
+ */
6482
+ declare function readAgentPersonaFile(agentName: string): {
6483
+ frontmatter: AgentPersonaFrontmatter;
6484
+ body: string;
6485
+ };
6486
+ /**
6487
+ * Update one or more frontmatter keys on an agent's persona file.
6488
+ * Preserves the existing body. Auto-seeds the body if the file
6489
+ * didn't exist yet.
6490
+ */
6491
+ declare function updateAgentPersonaFrontmatter(agentName: string, patch: AgentPersonaFrontmatter): string;
6387
6492
 
6388
- export { AGENT_ROLES, AGENT_STATE_ROOT, ASK_OPERATOR_TOOL, AccountManager, type AddressInfo, type Agent, AgentDeletionService, type AgentMemoryEntry, type AgentMemoryFields, AgentMemoryManager, type AgentMemoryOptions, type AgentMemoryRead, AgentMemoryStore, type AgentRole, AgenticMailClient, type AgenticMailClientOptions, type AgenticMailConfig, type ArchiveAndDeleteOptions, type ArchivedEmail, type Attachment, type AttachmentAdvisory, type AudioAction, type AudioEditOptions, BRIDGE_OPERATOR_LIVE_WINDOW_MS, type BridgeMailContext, type BridgeWakeError, type BridgeWakePromptArgs, type BridgeWakeResult, type BridgeWakeRoute, type CachedMessage, CloudflareClient, type CreateAgentOptions, type CreateMemoryInput, DEFAULT_AGENT_NAME, DEFAULT_AGENT_ROLE, DEFAULT_CALLBACK_POLICY, DEFAULT_EXTENSION_POLICY, DEFAULT_REALTIME_AUDIO_FORMAT, DEFAULT_REALTIME_MODEL, DEFAULT_REALTIME_VOICE, DEFAULT_SESSION_MAX_AGE_MS, DEFAULT_WEB_SEARCH_ENDPOINT, DNSConfigurator, type Database, type DeletionReport, type DeletionSummary, DependencyChecker, DependencyInstaller, type DependencyStatus, type DnsRecord, type DnsSetupResult, type DomainInfo, DomainManager, type DomainModeConfig, type DomainPurchaseResult, DomainPurchaser, type DomainSearchResult, type DomainSetupResult, ELKS_REALTIME_AUDIO_FORMATS, ELKS_REALTIME_WS_PATH, END_CALL_TOOL, EXTEND_CALL_TIME_TOOL, type ElksRealtimeAudioFormat, type ElksRealtimeAudioMessage, type ElksRealtimeByeMessage, type ElksRealtimeHelloMessage, type ElksRealtimeInboundMessage, type ElksRealtimeOutboundMessage, ElksRealtimeTransport, type EmailEnvelope, type EmailRouteAction, type EmailRouteClass, type EmailRouteClassification, type EmailRouteInput, EmailSearchIndex, type FolderInfo, GET_CALL_STATUS_TOOL, GET_DATETIME_TOOL, type GatewayConfig, GatewayManager, type GatewayManagerOptions, type GatewayMode, type GatewayStatus, type GetDatetimeOptions, type GetUpdatesOptions, type HostName, type HostSession, type HostSessionResumeMode, type ImageAction, type ImageEditOptions, type InboundEmail, type InboundSmsEvent, type InboxEvent, type InboxExpungeEvent, type InboxFlagsEvent, type InboxNewEvent, InboxWatcher, type InboxWatcherOptions, type InstallProgress, LOAD_SKILL_TOOL, type LinkAdvisory, type LocalSmtpConfig, MEMORY_CATEGORIES, MailReceiver, type MailReceiverOptions, MailSender, type MailSenderOptions, type MailboxInfo, type MediaBinary, type MediaCapability, type MediaCapabilityReport, type MediaFileResult, type MediaInfoResult, MediaManager, type MediaManagerOptions, type MediaStreamInfo, type MemoryCategory, type MemoryImportance, type MemoryQueryOptions, type MemoryRecaller, MemorySearchIndex, type MemorySource, type MemoryStats, OPENAI_REALTIME_URL, OPERATOR_QUERY_POLL_INTERVAL_MS, OPERATOR_QUERY_SUBJECT_TAG, OPERATOR_QUERY_TIMEOUT_MS, OPERATOR_QUERY_TIMEOUT_SENTINEL, type OpenClawPhoneMissionPolicy, type OperatorQueryNotificationInput, type OperatorQueryPollOptions, type OperatorQueryUrgency, type OperatorReplyKind, type OutboundCategory, type OutboundScanInput, type OutboundScanResult, type OutboundWarning, PERSONA_FILENAME, PHONE_CALLBACK_MAX_DELAY_SECONDS, PHONE_CALLBACK_MIN_DELAY_SECONDS, PHONE_CALL_CONTROL_PROVIDERS, PHONE_MAX_CONCURRENT_MISSIONS, PHONE_MIN_WEBHOOK_SECRET_LENGTH, PHONE_MISSION_STATES, PHONE_RATE_LIMIT_PER_HOUR, PHONE_RATE_LIMIT_PER_MINUTE, PHONE_REGION_SCOPES, PHONE_SERVER_MAX_ATTEMPTS, PHONE_SERVER_MAX_CALLBACK_CHAIN, PHONE_SERVER_MAX_CALL_DURATION_SECONDS, PHONE_SERVER_MAX_COST_PER_MISSION, PHONE_SERVER_MAX_EXTENSION_REQUESTS_PER_CALL, PHONE_SERVER_MAX_EXTENSION_SECONDS_PER_REQUEST, PHONE_SERVER_MAX_TOTAL_EXTENSION_SECONDS, PHONE_TASK_MAX_LENGTH, type ParsedAttachment, type ParsedEmail, type ParsedOperatorReply, type ParsedSms, type ParsedTelegramMessage, PathTraversalError, type PhoneAlternativePolicy, type PhoneCallMission, type PhoneCallbackPolicy, type PhoneConfirmPolicy, type PhoneExtensionPolicy, PhoneManager, type PhoneMissionStartValidationResult, type PhoneMissionState, type PhoneMissionTranscriptEntry, type PhoneMissionValidationIssue, type PhoneMissionValidationResult, type PhoneNumberRisk, type PhoneOperatorQuery, PhoneRateLimitError, type PhoneRegionScope, type PhoneScheduledCallback, type PhoneTransportConfig, type PhoneTransportProfile, type PhoneTransportProvider, type PhoneTransportValidationResult, PhoneWebhookAuthError, type PhoneWebhookResult, type PlanBridgeWakeArgs, type PurchasedDomain, REALTIME_AUDIO_SAMPLE_RATE, REALTIME_MAX_AUDIO_FRAME_BASE64, REALTIME_TOOL_CALL_TIMEOUT_MS, REALTIME_TOOL_DEFINITIONS, RECALL_MEMORY_TOOL, REDACTED, RELAY_PRESETS, type RealtimeBridgePort, type RealtimeBridgeTranscriptEntry, type RealtimeInboundEvent, type RealtimeInstructionOptions, type RealtimeSessionConfigOptions, type RealtimeToolCall, type RealtimeToolDefinition, type RealtimeToolHandler, type RealtimeToolResult, type RealtimeTransportAdapter, type RealtimeTransportProvider, RealtimeVoiceBridge, type RealtimeVoiceBridgeOptions, RelayBridge, type RelayBridgeOptions, type RelayConfig, RelayGateway, type RelayProvider, type RelaySearchResult, type ResumeErrorClassificationOptions, SCHEDULE_CALLBACK_TOOL, SEARCH_EMAIL_TOOL, SEARCH_SKILLS_TOOL, SPAM_THRESHOLD, type SafeJoinOptions, type SanitizeDetection, type SanitizeResult, type ScheduledCallbackRequest, type SearchCriteria, type SearchableEmail, type SecurityAdvisory, type SendMailOptions, type SendResult, type SendResultWithRaw, type SendSmsInput, type SendSmsResult, type SendTelegramMessageOptions, type SendTelegramMessageResult, ServiceManager, type ServiceStatus, type SetWebhookOptions, type SetupConfig, SetupManager, type SetupResult, type Severity, type Skill, type SkillCategory, type SkillContext, type SkillExitStrategy, type SkillSummary, type SkillTactic, type SkillValidationError, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, type SmsProvider, type SpamCategory, type SpamResult, type SpamRuleMatch, StalwartAdmin, type StalwartAdminOptions, type StalwartPrincipal, type StartPhoneCallOptions, type StartPhoneCallResult, type StartPhoneMissionInput, TELEGRAM_API_BASE, TELEGRAM_CHUNK_SIZE, TELEGRAM_MESSAGE_LIMIT, TELEGRAM_MIN_WEBHOOK_SECRET_LENGTH, TELEGRAM_OPERATOR_QUERY_TAG, TELEGRAM_STOP_WORDS, TELEGRAM_WEBHOOK_SECRET_RE, TELEPHONY_TRANSPORT_CAPABILITIES, TWILIO_MEDIA_SAMPLE_RATE, TWILIO_REALTIME_WS_PATH, TelegramApiError, type TelegramApiOptions, type TelegramBotInfo, type TelegramChatType, type TelegramConfig, TelegramManager, type TelegramMessage, type TelegramMode, type TelephonyTransportCapability, ThreadCache, type ThreadCacheEntry, type ThreadCacheOptions, type ThreadIdInput, type ToolExecutor, type TtsGenerateOptions, type TunnelConfig, TunnelManager, type TwilioConnectedMessage, type TwilioMarkMessage, type TwilioMediaMessage, type TwilioRealtimeInboundMessage, type TwilioRealtimeOutboundMessage, TwilioRealtimeTransport, type TwilioStartMessage, type TwilioStopMessage, type TwilioStreamTwiMLOptions, UnsafeApiUrlError, type UpdateMemoryInput, type ValidatedPhoneMissionStart, type VideoAction, type VideoEditOptions, type VideoTimelineEntry, type VideoUnderstandOptions, type VideoUnderstandResult, type VoiceCloneOptions, type VoiceProvider, type VoiceRuntimeConnection, WARNING_THRESHOLD, WEB_SEARCH_TOOL, WEB_SEARCH_UNTRUSTED_PREFIX, type WatcherOptions, type WebSearchOptions, assertWithinBase, bridgeWakeErrorMessage, bridgeWakeLastSeenAgeMs, buildApiUrl, buildDefaultPersona, buildElksAudioMessage, buildElksByeMessage, buildElksHandshakeMessages, buildElksInterruptMessage, buildElksListeningMessage, buildElksSendingMessage, buildInboundSecurityAdvisory, buildOpenAIRealtimeUrl, buildPhoneTransportConfig, buildRealtimeInstructions, buildRealtimeSessionConfig, buildRealtimeToolGuidance, buildTwilioClearMessage, buildTwilioMarkMessage, buildTwilioMediaMessage, buildTwilioSayTwiML, buildTwilioSignature, buildTwilioStreamTwiML, callTelegramApi, classifyEmailRoute, classifyPhoneNumberRisk, classifyResumeError, clearMediaCapabilityCache, closeDatabase, composeBridgeWakePrompt, createRealtimeTransport, createTestDatabase, createToolExecutor, debug, debugWarn, deleteTelegramWebhook, detectBinary, ensureDataDir, escapeXml, extractEmailAddress, extractVerificationCode, flushTelemetry, forgetHostSession, formatOperatorQueryTelegramMessage, getDatabase, getDatetime, getMediaCapabilities, getOperatorEmail, getSmsProvider, getTelegramChat, getTelegramMe, getTelegramUpdates, getTelegramWebhookInfo, getVoiceProvider, hostSessionStoragePath, inferPhoneRegion, invalidateSkillCache, isInternalEmail, isLoopbackMailHost, isOperatorReplySender, isPhoneRegionAllowed, isSessionFresh, isTelegramChatAllowed, isTelegramStopCommand, isValidPhoneNumber, listSkills, listVoiceProviders, loadAgentPersona, loadHostSession, loadSkill, mapProviderSmsStatus, nextTelegramOffset, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, operatorQuerySubject, parseElksRealtimeMessage, parseEmail, parseGoogleVoiceSms, parseOperatorQueryReply, parseTelegramOperatorReply, parseTelegramUpdate, parseTwilioRealtimeMessage, personaPathFor, planBridgeWake, pollForOperatorAnswer, recallMemory, recordToolCall, redactBotToken, redactObject, redactPhoneTransportConfig, redactSecret, redactSmsConfig, redactTelegramConfig, registerVoiceProvider, renderSkillAsPrompt, requireBinary, requireWhisperModel, resolveCallbackPolicy, resolveConfig, resolveExtensionPolicy, resolveTlsRejectUnauthorized, resolveVoiceRuntime, safeJoin, sanitizeEmail, saveAgentPersona, saveConfig, saveHostSession, saveUserSkill, scanOutboundEmail, scoreEmail, searchSkills, sendTelegramMessage, setOperatorEmail, setTelegramWebhook, setTelemetryVersion, shouldSkipBridgeWakeForLiveOperator, splitTelegramMessage, startRelayBridge, stem, stripTelegramMarkdown, threadIdFor, tokenize, tryJoin, userSkillsDir, validateApiUrl, validatePhoneMissionPolicy, validatePhoneMissionStart, validatePhoneTransportProfile, validateSkill, validateTwilioSignature, webSearch };
6493
+ export { AGENT_ROLES, AGENT_STATE_ROOT, ASK_OPERATOR_TOOL, AccountManager, type AddressInfo, type Agent, AgentDeletionService, type AgentMemoryEntry, type AgentMemoryFields, AgentMemoryManager, type AgentMemoryOptions, type AgentMemoryRead, AgentMemoryStore, type AgentPersonaFrontmatter, type AgentRole, AgenticMailClient, type AgenticMailClientOptions, type AgenticMailConfig, type ArchiveAndDeleteOptions, type ArchivedEmail, type Attachment, type AttachmentAdvisory, type AudioAction, type AudioEditOptions, BRIDGE_OPERATOR_LIVE_WINDOW_MS, type BridgeMailContext, type BridgeWakeError, type BridgeWakePromptArgs, type BridgeWakeResult, type BridgeWakeRoute, type CachedMessage, CloudflareClient, type CreateAgentOptions, type CreateMemoryInput, DEFAULT_AGENT_NAME, DEFAULT_AGENT_ROLE, DEFAULT_CALLBACK_POLICY, DEFAULT_EXTENSION_POLICY, DEFAULT_REALTIME_AUDIO_FORMAT, DEFAULT_REALTIME_MODEL, DEFAULT_REALTIME_VOICE, DEFAULT_SESSION_MAX_AGE_MS, DEFAULT_WEB_SEARCH_ENDPOINT, DNSConfigurator, type Database, type DeletionReport, type DeletionSummary, DependencyChecker, DependencyInstaller, type DependencyStatus, type DnsRecord, type DnsSetupResult, type DomainInfo, DomainManager, type DomainModeConfig, type DomainPurchaseResult, DomainPurchaser, type DomainSearchResult, type DomainSetupResult, ELKS_REALTIME_AUDIO_FORMATS, ELKS_REALTIME_WS_PATH, END_CALL_TOOL, EXTEND_CALL_TIME_TOOL, type ElksRealtimeAudioFormat, type ElksRealtimeAudioMessage, type ElksRealtimeByeMessage, type ElksRealtimeHelloMessage, type ElksRealtimeInboundMessage, type ElksRealtimeOutboundMessage, ElksRealtimeTransport, type EmailEnvelope, type EmailRouteAction, type EmailRouteClass, type EmailRouteClassification, type EmailRouteInput, EmailSearchIndex, type FolderInfo, GET_CALL_STATUS_TOOL, GET_DATETIME_TOOL, type GatewayConfig, GatewayManager, type GatewayManagerOptions, type GatewayMode, type GatewayStatus, type GetDatetimeOptions, type GetUpdatesOptions, type HostName, type HostSession, type HostSessionResumeMode, type ImageAction, type ImageEditOptions, type InboundEmail, type InboundSmsEvent, type InboxEvent, type InboxExpungeEvent, type InboxFlagsEvent, type InboxNewEvent, InboxWatcher, type InboxWatcherOptions, type InstallProgress, LOAD_SKILL_TOOL, type LinkAdvisory, type LocalSmtpConfig, MEMORY_CATEGORIES, MailReceiver, type MailReceiverOptions, MailSender, type MailSenderOptions, type MailboxInfo, type MediaBinary, type MediaCapability, type MediaCapabilityReport, type MediaFileResult, type MediaInfoResult, MediaManager, type MediaManagerOptions, type MediaStreamInfo, type MemoryCategory, type MemoryImportance, type MemoryQueryOptions, type MemoryRecaller, MemorySearchIndex, type MemorySource, type MemoryStats, OPENAI_REALTIME_URL, OPERATOR_QUERY_POLL_INTERVAL_MS, OPERATOR_QUERY_SUBJECT_TAG, OPERATOR_QUERY_TIMEOUT_MS, OPERATOR_QUERY_TIMEOUT_SENTINEL, type OpenClawPhoneMissionPolicy, type OperatorQueryNotificationInput, type OperatorQueryPollOptions, type OperatorQueryUrgency, type OperatorReplyKind, type OutboundCategory, type OutboundScanInput, type OutboundScanResult, type OutboundWarning, PERSONA_FILENAME, PHONE_CALLBACK_MAX_DELAY_SECONDS, PHONE_CALLBACK_MIN_DELAY_SECONDS, PHONE_CALL_CONTROL_PROVIDERS, PHONE_MAX_CONCURRENT_MISSIONS, PHONE_MIN_WEBHOOK_SECRET_LENGTH, PHONE_MISSION_STATES, PHONE_RATE_LIMIT_PER_HOUR, PHONE_RATE_LIMIT_PER_MINUTE, PHONE_REGION_SCOPES, PHONE_SERVER_MAX_ATTEMPTS, PHONE_SERVER_MAX_CALLBACK_CHAIN, PHONE_SERVER_MAX_CALL_DURATION_SECONDS, PHONE_SERVER_MAX_COST_PER_MISSION, PHONE_SERVER_MAX_EXTENSION_REQUESTS_PER_CALL, PHONE_SERVER_MAX_EXTENSION_SECONDS_PER_REQUEST, PHONE_SERVER_MAX_TOTAL_EXTENSION_SECONDS, PHONE_TASK_MAX_LENGTH, type ParsedAttachment, type ParsedEmail, type ParsedOperatorReply, type ParsedSms, type ParsedTelegramMessage, PathTraversalError, type PhoneAlternativePolicy, type PhoneCallMission, type PhoneCallbackPolicy, type PhoneConfirmPolicy, type PhoneExtensionPolicy, PhoneManager, type PhoneMissionStartValidationResult, type PhoneMissionState, type PhoneMissionTranscriptEntry, type PhoneMissionValidationIssue, type PhoneMissionValidationResult, type PhoneNumberRisk, type PhoneOperatorQuery, PhoneRateLimitError, type PhoneRegionScope, type PhoneScheduledCallback, type PhoneTransportConfig, type PhoneTransportProfile, type PhoneTransportProvider, type PhoneTransportValidationResult, PhoneWebhookAuthError, type PhoneWebhookResult, type PlanBridgeWakeArgs, type PurchasedDomain, REALTIME_AUDIO_SAMPLE_RATE, REALTIME_MAX_AUDIO_FRAME_BASE64, REALTIME_TOOL_CALL_TIMEOUT_MS, REALTIME_TOOL_DEFINITIONS, RECALL_MEMORY_TOOL, REDACTED, RELAY_PRESETS, type RealtimeBridgePort, type RealtimeBridgeTranscriptEntry, type RealtimeInboundEvent, type RealtimeInstructionOptions, type RealtimeSessionConfigOptions, type RealtimeToolCall, type RealtimeToolDefinition, type RealtimeToolHandler, type RealtimeToolResult, type RealtimeTransportAdapter, type RealtimeTransportProvider, RealtimeVoiceBridge, type RealtimeVoiceBridgeOptions, RelayBridge, type RelayBridgeOptions, type RelayConfig, RelayGateway, type RelayProvider, type RelaySearchResult, type ResumeErrorClassificationOptions, SCHEDULE_CALLBACK_TOOL, SEARCH_EMAIL_TOOL, SEARCH_SKILLS_TOOL, SPAM_THRESHOLD, type SafeJoinOptions, type SanitizeDetection, type SanitizeResult, type ScheduledCallbackRequest, type SearchCriteria, type SearchableEmail, type SecurityAdvisory, type SendMailOptions, type SendResult, type SendResultWithRaw, type SendSmsInput, type SendSmsResult, type SendTelegramMessageOptions, type SendTelegramMessageResult, ServiceManager, type ServiceStatus, type SetWebhookOptions, type SetupConfig, SetupManager, type SetupResult, type Severity, type Skill, type SkillCategory, type SkillContext, type SkillExitStrategy, type SkillSummary, type SkillTactic, type SkillValidationError, type SmsConfig, SmsManager, type SmsMessage, SmsPoller, type SmsProvider, type SpamCategory, type SpamResult, type SpamRuleMatch, StalwartAdmin, type StalwartAdminOptions, type StalwartPrincipal, type StartPhoneCallOptions, type StartPhoneCallResult, type StartPhoneMissionInput, TELEGRAM_API_BASE, TELEGRAM_CHUNK_SIZE, TELEGRAM_MESSAGE_LIMIT, TELEGRAM_MIN_WEBHOOK_SECRET_LENGTH, TELEGRAM_OPERATOR_QUERY_TAG, TELEGRAM_STOP_WORDS, TELEGRAM_WEBHOOK_SECRET_RE, TELEPHONY_TRANSPORT_CAPABILITIES, TWILIO_MEDIA_SAMPLE_RATE, TWILIO_REALTIME_WS_PATH, TelegramApiError, type TelegramApiOptions, type TelegramBotInfo, type TelegramChatType, type TelegramConfig, TelegramManager, type TelegramMessage, type TelegramMode, type TelephonyTransportCapability, ThreadCache, type ThreadCacheEntry, type ThreadCacheOptions, type ThreadIdInput, type ToolExecutor, type TtsGenerateOptions, type TunnelConfig, TunnelManager, type TwilioConnectedMessage, type TwilioMarkMessage, type TwilioMediaMessage, type TwilioRealtimeInboundMessage, type TwilioRealtimeOutboundMessage, TwilioRealtimeTransport, type TwilioStartMessage, type TwilioStopMessage, type TwilioStreamTwiMLOptions, UnsafeApiUrlError, type UpdateMemoryInput, type ValidatedPhoneMissionStart, type VideoAction, type VideoEditOptions, type VideoTimelineEntry, type VideoUnderstandOptions, type VideoUnderstandResult, type VoiceCloneOptions, type VoiceProvider, type VoiceRuntimeConnection, WARNING_THRESHOLD, WEB_SEARCH_TOOL, WEB_SEARCH_UNTRUSTED_PREFIX, type WatcherOptions, type WebSearchOptions, assertWithinBase, bridgeWakeErrorMessage, bridgeWakeLastSeenAgeMs, buildApiUrl, buildDefaultPersona, buildElksAudioMessage, buildElksByeMessage, buildElksHandshakeMessages, buildElksInterruptMessage, buildElksListeningMessage, buildElksSendingMessage, buildInboundSecurityAdvisory, buildOpenAIRealtimeUrl, buildPhoneTransportConfig, buildRealtimeInstructions, buildRealtimeSessionConfig, buildRealtimeToolGuidance, buildTwilioClearMessage, buildTwilioMarkMessage, buildTwilioMediaMessage, buildTwilioSayTwiML, buildTwilioSignature, buildTwilioStreamTwiML, callTelegramApi, classifyEmailRoute, classifyPhoneNumberRisk, classifyResumeError, clearMediaCapabilityCache, closeDatabase, composeBridgeWakePrompt, createRealtimeTransport, createTestDatabase, createToolExecutor, debug, debugWarn, deleteTelegramWebhook, detectBinary, ensureDataDir, escapeXml, extractEmailAddress, extractVerificationCode, flushTelemetry, forgetHostSession, formatOperatorQueryTelegramMessage, getDatabase, getDatetime, getMediaCapabilities, getOperatorEmail, getSmsProvider, getTelegramChat, getTelegramMe, getTelegramUpdates, getTelegramWebhookInfo, getVoiceProvider, hostSessionStoragePath, inferPhoneRegion, invalidateSkillCache, isInternalEmail, isLoopbackMailHost, isOperatorReplySender, isPhoneRegionAllowed, isSessionFresh, isTelegramChatAllowed, isTelegramStopCommand, isValidPhoneNumber, listSkills, listVoiceProviders, loadAgentPersona, loadHostSession, loadSkill, mapProviderSmsStatus, nextTelegramOffset, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, operatorQuerySubject, parseElksRealtimeMessage, parseEmail, parseGoogleVoiceSms, parseOperatorQueryReply, parseTelegramOperatorReply, parseTelegramUpdate, parseTwilioRealtimeMessage, personaPathFor, planBridgeWake, pollForOperatorAnswer, readAgentPersonaFile, recallMemory, recordToolCall, redactBotToken, redactObject, redactPhoneTransportConfig, redactSecret, redactSmsConfig, redactTelegramConfig, registerVoiceProvider, renderSkillAsPrompt, requireBinary, requireWhisperModel, resolveCallbackPolicy, resolveConfig, resolveExtensionPolicy, resolveTlsRejectUnauthorized, resolveVoiceRuntime, safeJoin, sanitizeEmail, saveAgentPersona, saveConfig, saveHostSession, saveUserSkill, scanOutboundEmail, scoreEmail, searchSkills, sendTelegramMessage, setOperatorEmail, setTelegramWebhook, setTelemetryVersion, shouldSkipBridgeWakeForLiveOperator, splitTelegramMessage, startRelayBridge, stem, stripTelegramMarkdown, threadIdFor, tokenize, tryJoin, updateAgentPersonaFrontmatter, userSkillsDir, validateApiUrl, validatePhoneMissionPolicy, validatePhoneMissionStart, validatePhoneTransportProfile, validateSkill, validateTwilioSignature, webSearch };
package/dist/index.js CHANGED
@@ -6136,7 +6136,14 @@ function validatePhoneMissionPolicy(policy) {
6136
6136
  // manager) can read a concrete value without juggling undefined.
6137
6137
  // Caller-omitted → DEFAULT_*. Caller-set → clamped to server caps.
6138
6138
  extensionPolicy: resolveExtensionPolicy(policy.extensionPolicy),
6139
- callbackPolicy: resolveCallbackPolicy(policy.callbackPolicy)
6139
+ callbackPolicy: resolveCallbackPolicy(policy.callbackPolicy),
6140
+ // v0.9.95 — voice-runtime overrides. Pass-through; the registry
6141
+ // validates the provider id and voice-against-catalogue at
6142
+ // session-open time so we don't have to import the registry
6143
+ // here (would create a cycle with realtime-bridge.ts).
6144
+ voiceRuntime: typeof policy.voiceRuntime === "string" && policy.voiceRuntime.trim() ? policy.voiceRuntime.trim() : void 0,
6145
+ voiceModel: typeof policy.voiceModel === "string" && policy.voiceModel.trim() ? policy.voiceModel.trim() : void 0,
6146
+ voice: typeof policy.voice === "string" && policy.voice.trim() ? policy.voice.trim() : void 0
6140
6147
  },
6141
6148
  issues: []
6142
6149
  };
@@ -10590,13 +10597,42 @@ function resolveVoiceRuntime(providerId, config, options = {}) {
10590
10597
  }
10591
10598
  const model = options.model && options.model.trim() || provider.defaultModel;
10592
10599
  const url = `${provider.websocketBaseUrl}?model=${encodeURIComponent(model)}`;
10600
+ let voice = "";
10601
+ let voiceSource = "";
10602
+ const requested = (options.voice || "").trim();
10603
+ if (requested) {
10604
+ if (provider.voices.includes(requested) || provider.customVoicesSupported) {
10605
+ voice = requested;
10606
+ voiceSource = "mission policy";
10607
+ } else {
10608
+ console.warn(
10609
+ `[voice-providers] Voice "${requested}" is not in ${provider.id}'s catalogue (${provider.voices.join(", ")}). Falling through to ${provider.defaultVoice}.`
10610
+ );
10611
+ }
10612
+ }
10613
+ if (!voice) {
10614
+ const installDefault = config.voiceProviderVoices?.[provider.id];
10615
+ if (installDefault && installDefault.trim()) {
10616
+ const v = installDefault.trim();
10617
+ if (provider.voices.includes(v) || provider.customVoicesSupported) {
10618
+ voice = v;
10619
+ voiceSource = `config.voiceProviderVoices.${provider.id}`;
10620
+ }
10621
+ }
10622
+ }
10623
+ if (!voice) {
10624
+ voice = provider.defaultVoice;
10625
+ voiceSource = `${provider.id} default`;
10626
+ }
10593
10627
  return {
10594
10628
  providerId: provider.id,
10595
10629
  providerDisplayName: provider.displayName,
10596
10630
  url,
10597
10631
  model,
10598
10632
  apiKey,
10599
- apiKeySource
10633
+ apiKeySource,
10634
+ voice,
10635
+ voiceSource
10600
10636
  };
10601
10637
  }
10602
10638
 
@@ -10612,7 +10648,13 @@ registerVoiceProvider({
10612
10648
  // before the generic voiceProviderKeys map so existing installs
10613
10649
  // continue to work without migration.
10614
10650
  apiKeyConfigField: "openaiApiKey",
10615
- description: "OpenAI Realtime (gpt-realtime). Default voice runtime; supports linear PCM @ 24 kHz (46elks) and G.711 \xB5-law @ 8 kHz (Twilio) without transcoding."
10651
+ description: "OpenAI Realtime (gpt-realtime). Default voice runtime; supports linear PCM @ 24 kHz (46elks) and G.711 \xB5-law @ 8 kHz (Twilio) without transcoding.",
10652
+ // v0.9.95 — voice catalogue. Names match what the Realtime session
10653
+ // accepts under `audio.output.voice`. `marin` and `cedar` are the
10654
+ // GA gpt-realtime additions; the rest are the legacy roster carried
10655
+ // forward from gpt-4o-realtime-preview.
10656
+ voices: ["alloy", "ash", "ballad", "cedar", "coral", "echo", "marin", "sage", "shimmer", "verse"],
10657
+ defaultVoice: "marin"
10616
10658
  });
10617
10659
 
10618
10660
  // src/phone/voice-providers/grok.ts
@@ -10622,7 +10664,18 @@ registerVoiceProvider({
10622
10664
  websocketBaseUrl: "wss://api.x.ai/v1/realtime",
10623
10665
  defaultModel: "grok-voice-latest",
10624
10666
  apiKeyEnvVar: "XAI_API_KEY",
10625
- description: 'xAI Grok Voice Agent \u2014 OpenAI-Realtime-compatible WebSocket protocol; select via mission policy.voiceRuntime="grok" or env AGENTICMAIL_VOICE_RUNTIME=grok.'
10667
+ description: 'xAI Grok Voice Agent \u2014 OpenAI-Realtime-compatible WebSocket protocol; select via mission policy.voiceRuntime="grok" or env AGENTICMAIL_VOICE_RUNTIME=grok.',
10668
+ // v0.9.95 — voice catalogue. xAI ships 5 expressive built-in
10669
+ // voices for the realtime Voice Agent. Three are explicitly named
10670
+ // in the announcement (Ara, Eve, Leo); the other two are
10671
+ // browsable in console.x.ai's Voice Library along with the
10672
+ // broader 80+ voice catalogue. The full live list is at
10673
+ // GET /v1/tts/voices. We don't try to enumerate all 80+ here —
10674
+ // customVoicesSupported lets operators paste any voice_id from
10675
+ // their console.
10676
+ voices: ["ara", "eve", "leo"],
10677
+ defaultVoice: "ara",
10678
+ customVoicesSupported: true
10626
10679
  });
10627
10680
 
10628
10681
  // src/telemetry.ts
@@ -14774,8 +14827,19 @@ function loadAgentPersona(agentName) {
14774
14827
  const path2 = personaPathFor(agentName);
14775
14828
  try {
14776
14829
  if (existsSync14(path2)) {
14777
- const content = readFileSync10(path2, "utf-8").trim();
14778
- if (content) return content;
14830
+ const raw = readFileSync10(path2, "utf-8");
14831
+ if (raw.trim()) {
14832
+ const text = raw.replace(/\r\n/g, "\n");
14833
+ if (text.startsWith("---\n")) {
14834
+ const close = text.indexOf("\n---", 4);
14835
+ if (close > 0) {
14836
+ let cursor = close + 4;
14837
+ while (cursor < text.length && (text[cursor] === "\n" || text[cursor] === "\r")) cursor++;
14838
+ return text.slice(cursor).trim();
14839
+ }
14840
+ }
14841
+ return text.trim();
14842
+ }
14779
14843
  }
14780
14844
  } catch {
14781
14845
  }
@@ -14795,6 +14859,61 @@ function saveAgentPersona(agentName, content) {
14795
14859
  writeFileSync11(path2, content.trim() + "\n", { mode: 420 });
14796
14860
  return path2;
14797
14861
  }
14862
+ function readAgentPersonaFile(agentName) {
14863
+ const path2 = personaPathFor(agentName);
14864
+ let raw = "";
14865
+ try {
14866
+ if (existsSync14(path2)) raw = readFileSync10(path2, "utf-8");
14867
+ } catch {
14868
+ }
14869
+ if (!raw.trim()) {
14870
+ return { frontmatter: {}, body: loadAgentPersona(agentName) };
14871
+ }
14872
+ const text = raw.replace(/\r\n/g, "\n");
14873
+ if (!text.startsWith("---\n")) {
14874
+ return { frontmatter: {}, body: text.trim() };
14875
+ }
14876
+ const close = text.indexOf("\n---", 4);
14877
+ if (close < 0) {
14878
+ return { frontmatter: {}, body: text.trim() };
14879
+ }
14880
+ const yamlBlock = text.slice(4, close);
14881
+ const bodyStart = close + 4;
14882
+ let cursor = bodyStart;
14883
+ while (cursor < text.length && (text[cursor] === "\n" || text[cursor] === "\r")) cursor++;
14884
+ const body = text.slice(cursor).trim();
14885
+ const frontmatter = {};
14886
+ for (const line of yamlBlock.split("\n")) {
14887
+ const m = /^\s*([A-Za-z][A-Za-z0-9_-]*)\s*:\s*(.*?)\s*$/.exec(line);
14888
+ if (!m) continue;
14889
+ const key = m[1];
14890
+ const value = m[2].replace(/^["']|["']$/g, "");
14891
+ if (key === "voice") frontmatter.voice = value;
14892
+ else if (key === "voiceRuntime") frontmatter.voiceRuntime = value;
14893
+ }
14894
+ return { frontmatter, body };
14895
+ }
14896
+ function updateAgentPersonaFrontmatter(agentName, patch) {
14897
+ const { frontmatter, body } = readAgentPersonaFile(agentName);
14898
+ const merged = { ...frontmatter };
14899
+ if (patch.voice !== void 0) merged.voice = patch.voice;
14900
+ if (patch.voiceRuntime !== void 0) merged.voiceRuntime = patch.voiceRuntime;
14901
+ const lines = [];
14902
+ if (merged.voice && merged.voice.trim()) lines.push(`voice: ${merged.voice.trim()}`);
14903
+ if (merged.voiceRuntime && merged.voiceRuntime.trim()) lines.push(`voiceRuntime: ${merged.voiceRuntime.trim()}`);
14904
+ const path2 = personaPathFor(agentName);
14905
+ const dir2 = path2.substring(0, path2.lastIndexOf("/"));
14906
+ if (!existsSync14(dir2)) mkdirSync12(dir2, { recursive: true });
14907
+ const content = lines.length > 0 ? `---
14908
+ ${lines.join("\n")}
14909
+ ---
14910
+
14911
+ ${body}
14912
+ ` : `${body}
14913
+ `;
14914
+ writeFileSync11(path2, content, { mode: 420 });
14915
+ return path2;
14916
+ }
14798
14917
  export {
14799
14918
  AGENT_ROLES,
14800
14919
  AGENT_STATE_ROOT,
@@ -14988,6 +15107,7 @@ export {
14988
15107
  personaPathFor,
14989
15108
  planBridgeWake,
14990
15109
  pollForOperatorAnswer,
15110
+ readAgentPersonaFile,
14991
15111
  recallMemory,
14992
15112
  recordToolCall,
14993
15113
  redactBotToken,
@@ -15026,6 +15146,7 @@ export {
15026
15146
  threadIdFor,
15027
15147
  tokenize,
15028
15148
  tryJoin,
15149
+ updateAgentPersonaFrontmatter,
15029
15150
  userSkillsDir,
15030
15151
  validateApiUrl,
15031
15152
  validatePhoneMissionPolicy,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/core",
3
- "version": "0.9.39",
3
+ "version": "0.9.40",
4
4
  "description": "Core SDK for AgenticMail — email, SMS, and phone call-control for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",