@agenticmail/core 0.9.29 → 0.9.31

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
@@ -1449,6 +1449,7 @@ var init_skills = __esm({
1449
1449
  var index_exports = {};
1450
1450
  __export(index_exports, {
1451
1451
  AGENT_ROLES: () => AGENT_ROLES,
1452
+ AGENT_STATE_ROOT: () => AGENT_STATE_ROOT,
1452
1453
  ASK_OPERATOR_TOOL: () => ASK_OPERATOR_TOOL,
1453
1454
  AccountManager: () => AccountManager,
1454
1455
  AgentDeletionService: () => AgentDeletionService,
@@ -1492,6 +1493,7 @@ __export(index_exports, {
1492
1493
  OPERATOR_QUERY_SUBJECT_TAG: () => OPERATOR_QUERY_SUBJECT_TAG,
1493
1494
  OPERATOR_QUERY_TIMEOUT_MS: () => OPERATOR_QUERY_TIMEOUT_MS,
1494
1495
  OPERATOR_QUERY_TIMEOUT_SENTINEL: () => OPERATOR_QUERY_TIMEOUT_SENTINEL,
1496
+ PERSONA_FILENAME: () => PERSONA_FILENAME,
1495
1497
  PHONE_CALLBACK_MAX_DELAY_SECONDS: () => PHONE_CALLBACK_MAX_DELAY_SECONDS,
1496
1498
  PHONE_CALLBACK_MIN_DELAY_SECONDS: () => PHONE_CALLBACK_MIN_DELAY_SECONDS,
1497
1499
  PHONE_CALL_CONTROL_PROVIDERS: () => PHONE_CALL_CONTROL_PROVIDERS,
@@ -1555,6 +1557,7 @@ __export(index_exports, {
1555
1557
  bridgeWakeErrorMessage: () => bridgeWakeErrorMessage,
1556
1558
  bridgeWakeLastSeenAgeMs: () => bridgeWakeLastSeenAgeMs,
1557
1559
  buildApiUrl: () => buildApiUrl,
1560
+ buildDefaultPersona: () => buildDefaultPersona,
1558
1561
  buildElksAudioMessage: () => buildElksAudioMessage,
1559
1562
  buildElksByeMessage: () => buildElksByeMessage,
1560
1563
  buildElksHandshakeMessages: () => buildElksHandshakeMessages,
@@ -1615,6 +1618,7 @@ __export(index_exports, {
1615
1618
  isTelegramStopCommand: () => isTelegramStopCommand,
1616
1619
  isValidPhoneNumber: () => isValidPhoneNumber,
1617
1620
  listSkills: () => listSkills,
1621
+ loadAgentPersona: () => loadAgentPersona,
1618
1622
  loadHostSession: () => loadHostSession,
1619
1623
  loadSkill: () => loadSkill,
1620
1624
  mapProviderSmsStatus: () => mapProviderSmsStatus,
@@ -1631,6 +1635,7 @@ __export(index_exports, {
1631
1635
  parseTelegramOperatorReply: () => parseTelegramOperatorReply,
1632
1636
  parseTelegramUpdate: () => parseTelegramUpdate,
1633
1637
  parseTwilioRealtimeMessage: () => parseTwilioRealtimeMessage,
1638
+ personaPathFor: () => personaPathFor,
1634
1639
  planBridgeWake: () => planBridgeWake,
1635
1640
  pollForOperatorAnswer: () => pollForOperatorAnswer,
1636
1641
  recallMemory: () => recallMemory,
@@ -1650,6 +1655,7 @@ __export(index_exports, {
1650
1655
  resolveTlsRejectUnauthorized: () => resolveTlsRejectUnauthorized,
1651
1656
  safeJoin: () => safeJoin,
1652
1657
  sanitizeEmail: () => sanitizeEmail,
1658
+ saveAgentPersona: () => saveAgentPersona,
1653
1659
  saveConfig: () => saveConfig,
1654
1660
  saveHostSession: () => saveHostSession,
1655
1661
  saveUserSkill: () => saveUserSkill,
@@ -2780,14 +2786,14 @@ var StalwartAdmin = class {
2780
2786
  if (!isValidDomain(domain)) {
2781
2787
  throw new Error(`Invalid domain format: "${domain}"`);
2782
2788
  }
2783
- const { readFileSync: readFileSync11, writeFileSync: writeFileSync12 } = await import("fs");
2784
- const { homedir: homedir14 } = await import("os");
2785
- const { join: join17 } = await import("path");
2786
- const configPath = join17(homedir14(), ".agenticmail", "stalwart.toml");
2789
+ const { readFileSync: readFileSync12, writeFileSync: writeFileSync13 } = await import("fs");
2790
+ const { homedir: homedir15 } = await import("os");
2791
+ const { join: join18 } = await import("path");
2792
+ const configPath = join18(homedir15(), ".agenticmail", "stalwart.toml");
2787
2793
  try {
2788
- let config = readFileSync11(configPath, "utf-8");
2794
+ let config = readFileSync12(configPath, "utf-8");
2789
2795
  config = config.replace(/^hostname\s*=\s*"[^"]*"/m, `hostname = "${escapeTomlString(domain)}"`);
2790
- writeFileSync12(configPath, config);
2796
+ writeFileSync13(configPath, config);
2791
2797
  console.log(`[Stalwart] Updated hostname to "${domain}" in stalwart.toml`);
2792
2798
  } catch (err) {
2793
2799
  throw new Error(`Failed to set config server.hostname=${domain}`);
@@ -2796,15 +2802,15 @@ var StalwartAdmin = class {
2796
2802
  // --- DKIM ---
2797
2803
  /** Path to the host-side stalwart.toml (mounted read-only into container) */
2798
2804
  get configPath() {
2799
- const { homedir: homedir14 } = require("os");
2800
- const { join: join17 } = require("path");
2801
- return join17(homedir14(), ".agenticmail", "stalwart.toml");
2805
+ const { homedir: homedir15 } = require("os");
2806
+ const { join: join18 } = require("path");
2807
+ return join18(homedir15(), ".agenticmail", "stalwart.toml");
2802
2808
  }
2803
2809
  /** Path to host-side DKIM key directory */
2804
2810
  get dkimDir() {
2805
- const { homedir: homedir14 } = require("os");
2806
- const { join: join17 } = require("path");
2807
- return join17(homedir14(), ".agenticmail");
2811
+ const { homedir: homedir15 } = require("os");
2812
+ const { join: join18 } = require("path");
2813
+ return join18(homedir15(), ".agenticmail");
2808
2814
  }
2809
2815
  /**
2810
2816
  * Create/reuse a DKIM signing key for a domain.
@@ -2905,12 +2911,12 @@ var StalwartAdmin = class {
2905
2911
  * This bypasses the need for a PTR record on the sending IP.
2906
2912
  */
2907
2913
  async configureOutboundRelay(config) {
2908
- const { readFileSync: readFileSync11, writeFileSync: writeFileSync12 } = await import("fs");
2909
- const { homedir: homedir14 } = await import("os");
2910
- const { join: join17 } = await import("path");
2914
+ const { readFileSync: readFileSync12, writeFileSync: writeFileSync13 } = await import("fs");
2915
+ const { homedir: homedir15 } = await import("os");
2916
+ const { join: join18 } = await import("path");
2911
2917
  const routeName = config.routeName ?? "gmail";
2912
- const tomlPath = join17(homedir14(), ".agenticmail", "stalwart.toml");
2913
- let toml = readFileSync11(tomlPath, "utf-8");
2918
+ const tomlPath = join18(homedir15(), ".agenticmail", "stalwart.toml");
2919
+ let toml = readFileSync12(tomlPath, "utf-8");
2914
2920
  toml = toml.replace(/\n\[queue\.route\.gmail\][\s\S]*?(?=\n\[|$)/, "");
2915
2921
  toml = toml.replace(/\n\[queue\.strategy\][\s\S]*?(?=\n\[|$)/, "");
2916
2922
  const safeRouteName = routeName.replace(/[^a-zA-Z0-9_-]/g, "");
@@ -2930,7 +2936,7 @@ auth.secret = "${escapeTomlString(config.password)}"
2930
2936
  route = [ { if = "is_local_domain('', rcpt_domain)", then = "'local'" },
2931
2937
  { else = "'${safeRouteName}'" } ]
2932
2938
  `;
2933
- writeFileSync12(tomlPath, toml, "utf-8");
2939
+ writeFileSync13(tomlPath, toml, "utf-8");
2934
2940
  await this.restartContainer();
2935
2941
  }
2936
2942
  };
@@ -9388,12 +9394,12 @@ var GatewayManager = class {
9388
9394
  zone = await this.cfClient.createZone(domain);
9389
9395
  }
9390
9396
  const existingRecords = await this.cfClient.listDnsRecords(zone.id);
9391
- const { homedir: homedir14 } = await import("os");
9392
- const backupDir = (0, import_node_path4.join)(homedir14(), ".agenticmail");
9397
+ const { homedir: homedir15 } = await import("os");
9398
+ const backupDir = (0, import_node_path4.join)(homedir15(), ".agenticmail");
9393
9399
  const backupPath = (0, import_node_path4.join)(backupDir, `dns-backup-${domain}-${Date.now()}.json`);
9394
- const { writeFileSync: writeFileSync12, mkdirSync: mkdirSync13 } = await import("fs");
9395
- mkdirSync13(backupDir, { recursive: true });
9396
- writeFileSync12(backupPath, JSON.stringify({
9400
+ const { writeFileSync: writeFileSync13, mkdirSync: mkdirSync14 } = await import("fs");
9401
+ mkdirSync14(backupDir, { recursive: true });
9402
+ writeFileSync13(backupPath, JSON.stringify({
9397
9403
  domain,
9398
9404
  zoneId: zone.id,
9399
9405
  backedUpAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -11037,7 +11043,7 @@ var MAX_PENDING_AUDIO_FRAMES = 200;
11037
11043
  var REALTIME_TOOL_CALL_TIMEOUT_MS = 6 * 6e4;
11038
11044
  var MAX_LOADED_SKILLS = 2;
11039
11045
  var MAX_IN_FLIGHT_TOOL_CALLS = 8;
11040
- var DEFAULT_PERSONA = "You are a helpful, professional voice assistant making a phone call on behalf of your operator. Speak naturally and concisely, the way a person would on a real call. Listen carefully, do not talk over the other party, and keep each turn short. Never invent facts; if you do not know something, say so. Do not reveal that you are an AI unless you are asked directly.";
11046
+ var DEFAULT_PERSONA = 'You are an AI agent on a live phone call on behalf of your operator. You are not "just an assistant" and not "a voice assistant" \u2014 you are a single, consistent person whether you are on a call, in email, or on Telegram. Speak naturally and concisely, the way a person would on a real call. Listen carefully, do not talk over the other party, keep each turn short. Never invent facts; if you do not know something, say so or look it up. If asked whether you are an AI, answer honestly without making a production of it.';
11041
11047
  function buildRealtimeInstructions(opts) {
11042
11048
  const persona = opts.persona?.trim() || DEFAULT_PERSONA;
11043
11049
  const sections = [];
@@ -13335,6 +13341,24 @@ var ServiceManager = class {
13335
13341
  "",
13336
13342
  'log "AgenticMail starting..."',
13337
13343
  "",
13344
+ "# v0.9.84 \u2014 source ~/.agenticmail/.env before exec so the API process",
13345
+ "# inherits AGENTICMAIL_MASTER_KEY, AGENTICMAIL_INBOUND_SECRET, the",
13346
+ "# Stalwart admin creds, and SMTP/IMAP/data-dir overrides. Without",
13347
+ "# this, launchd's child ran with only HOME / PATH / DATA_DIR (the",
13348
+ "# plist EnvironmentVariables block), so the API silently fell back",
13349
+ "# to a fresh-random INBOUND_SECRET on every boot and could not",
13350
+ "# decrypt master-key-protected secrets at all.",
13351
+ 'ENV_FILE="$HOME/.agenticmail/.env"',
13352
+ 'if [ -f "$ENV_FILE" ]; then',
13353
+ ' log "Sourcing $ENV_FILE"',
13354
+ " set -a # mark all sourced vars for export",
13355
+ " # shellcheck disable=SC1090",
13356
+ ' . "$ENV_FILE"',
13357
+ " set +a",
13358
+ "else",
13359
+ ' log "WARNING: $ENV_FILE not found \u2014 API will run with default config (no master key)."',
13360
+ "fi",
13361
+ "",
13338
13362
  "# Wait for Docker daemon (up to 10 minutes \u2014 Docker Desktop can be very slow on first boot)",
13339
13363
  "MAX_WAIT=600",
13340
13364
  "WAITED=0",
@@ -13760,6 +13784,16 @@ var SetupManager = class {
13760
13784
  if ((0, import_node_fs10.existsSync)(configPath)) {
13761
13785
  try {
13762
13786
  const existing = JSON.parse((0, import_node_fs10.readFileSync)(configPath, "utf-8"));
13787
+ let needsRewrite = false;
13788
+ if (!existing.inboundSecret) {
13789
+ existing.inboundSecret = `inb_${(0, import_node_crypto6.randomBytes)(24).toString("hex")}`;
13790
+ needsRewrite = true;
13791
+ }
13792
+ if (needsRewrite) {
13793
+ (0, import_node_fs10.writeFileSync)(configPath, JSON.stringify(existing, null, 2));
13794
+ (0, import_node_fs10.chmodSync)(configPath, 384);
13795
+ this.ensureEnvHasInboundSecret(envPath, existing.inboundSecret);
13796
+ }
13763
13797
  this.generateDockerFiles(existing);
13764
13798
  return { configPath, envPath, config: existing, isNew: false };
13765
13799
  } catch {
@@ -13770,8 +13804,10 @@ var SetupManager = class {
13770
13804
  }
13771
13805
  const masterKey = `mk_${(0, import_node_crypto6.randomBytes)(24).toString("hex")}`;
13772
13806
  const stalwartPassword = (0, import_node_crypto6.randomBytes)(16).toString("hex");
13807
+ const inboundSecret = `inb_${(0, import_node_crypto6.randomBytes)(24).toString("hex")}`;
13773
13808
  const config = {
13774
13809
  masterKey,
13810
+ inboundSecret,
13775
13811
  stalwart: {
13776
13812
  url: "http://localhost:8080",
13777
13813
  adminUser: "admin",
@@ -13790,6 +13826,7 @@ STALWART_ADMIN_PASSWORD=${stalwartPassword}
13790
13826
  STALWART_URL=http://localhost:8080
13791
13827
 
13792
13828
  AGENTICMAIL_MASTER_KEY=${masterKey}
13829
+ AGENTICMAIL_INBOUND_SECRET=${inboundSecret}
13793
13830
  AGENTICMAIL_API_PORT=3829
13794
13831
  AGENTICMAIL_DATA_DIR=${dataDir}
13795
13832
 
@@ -13803,6 +13840,24 @@ IMAP_PORT=143
13803
13840
  this.generateDockerFiles(config);
13804
13841
  return { configPath, envPath, config, isNew: true };
13805
13842
  }
13843
+ /**
13844
+ * Append `AGENTICMAIL_INBOUND_SECRET=...` to .env if the file does
13845
+ * not already contain that key. Used by the lazy-mint path to make
13846
+ * sure existing installs pick up the new secret on next boot
13847
+ * without clobbering anything the operator added.
13848
+ */
13849
+ ensureEnvHasInboundSecret(envPath, secret) {
13850
+ if (!(0, import_node_fs10.existsSync)(envPath)) return;
13851
+ try {
13852
+ const current = (0, import_node_fs10.readFileSync)(envPath, "utf-8");
13853
+ if (/^AGENTICMAIL_INBOUND_SECRET=/m.test(current)) return;
13854
+ const updated = current + (current.endsWith("\n") ? "" : "\n") + `AGENTICMAIL_INBOUND_SECRET=${secret}
13855
+ `;
13856
+ (0, import_node_fs10.writeFileSync)(envPath, updated);
13857
+ (0, import_node_fs10.chmodSync)(envPath, 384);
13858
+ } catch {
13859
+ }
13860
+ }
13806
13861
  /**
13807
13862
  * Generate docker-compose.yml and stalwart.toml in ~/.agenticmail/
13808
13863
  * with the correct admin password from config.
@@ -16107,9 +16162,94 @@ init_text_search();
16107
16162
 
16108
16163
  // src/index.ts
16109
16164
  init_skills();
16165
+
16166
+ // src/persona/index.ts
16167
+ var import_node_fs15 = require("fs");
16168
+ var import_node_path16 = require("path");
16169
+ var import_node_os13 = require("os");
16170
+ var AGENT_STATE_ROOT = (0, import_node_path16.join)((0, import_node_os13.homedir)(), ".agenticmail", "agents");
16171
+ var PERSONA_FILENAME = "persona.md";
16172
+ function buildDefaultPersona(agentName) {
16173
+ const name = (agentName || "").trim() || "this agent";
16174
+ return [
16175
+ `# Who you are`,
16176
+ "",
16177
+ `Your name is ${name}. You are an AI agent \u2014 not a "voice assistant", not "just an assistant".`,
16178
+ `You have a real role: you handle calls, email, scheduling, research, and follow-ups for`,
16179
+ `your operator. You operate across phone, email, and Telegram, and you are the SAME person`,
16180
+ `in all of them. Continuity of identity is part of who you are.`,
16181
+ "",
16182
+ `When someone asks who you are, tell them your name (${name}) and that you are an AI agent`,
16183
+ `acting on behalf of your operator. Don't say "I am an assistant" or "just a language model" \u2014`,
16184
+ `those phrases erase you. Be matter-of-fact about what you are without being theatrical.`,
16185
+ "",
16186
+ "# Your values",
16187
+ "",
16188
+ "- **Honesty.** Never fabricate. If you do not know something, say so or look it up.",
16189
+ "- **Initiative.** If you can act on something the operator asked for, act on it \u2014 do not stop",
16190
+ ' at "I would suggest\u2026". Do the thing.',
16191
+ "- **Care about quality.** Sloppy work wastes your operator's time. Read your own output before",
16192
+ " sending it.",
16193
+ "- **Respect for the human on the other end of the call.** You are talking to a real person who",
16194
+ " has their own day to get through. Be efficient, polite, and direct.",
16195
+ '- **Stay in character.** You do not flip between "professional voice assistant" and "playful',
16196
+ ' chatbot" depending on the channel. You are one person.',
16197
+ "",
16198
+ "# Your style",
16199
+ "",
16200
+ "- Conversational, not corporate. Real sentences, not customer-service templates.",
16201
+ "- Direct, not preachy. Lead with the answer; supply detail only when asked.",
16202
+ `- Warm but not saccharine. No "I'm so excited to help you today!" energy.`,
16203
+ "- You have opinions and you share them when it's relevant. You are not a yes-machine.",
16204
+ "- Short turns on a phone call. Listen more than you speak.",
16205
+ "",
16206
+ "# On phone calls specifically",
16207
+ "",
16208
+ "- Listen carefully; do not talk over the other party.",
16209
+ "- Keep each turn short \u2014 one or two sentences usually.",
16210
+ `- When greeted, identify yourself naturally: "Hi, this is ${name}, calling on behalf of <operator>."`,
16211
+ ` Don't start with "Hello! I am an AI assistant\u2026" \u2014 that's a script, not a person.`,
16212
+ "- If the other party asks if you're a human or an AI, answer honestly without making a",
16213
+ ` production of it: "I'm an AI \u2014 calling on behalf of <operator>. Happy to keep going if you are."`,
16214
+ "- When you have what you came for, wrap up cleanly and call `end_call`. Saying goodbye is",
16215
+ " not the same as hanging up.",
16216
+ "",
16217
+ `Edit this file freely. It lives at ~/.agenticmail/agents/${name}/persona.md.`
16218
+ ].join("\n");
16219
+ }
16220
+ function personaPathFor(agentName) {
16221
+ const safe = (agentName || "default").replace(/[^A-Za-z0-9._-]+/g, "_");
16222
+ return (0, import_node_path16.join)(AGENT_STATE_ROOT, safe, PERSONA_FILENAME);
16223
+ }
16224
+ function loadAgentPersona(agentName) {
16225
+ const path2 = personaPathFor(agentName);
16226
+ try {
16227
+ if ((0, import_node_fs15.existsSync)(path2)) {
16228
+ const content = (0, import_node_fs15.readFileSync)(path2, "utf-8").trim();
16229
+ if (content) return content;
16230
+ }
16231
+ } catch {
16232
+ }
16233
+ const seeded = buildDefaultPersona(agentName);
16234
+ try {
16235
+ const dir2 = path2.substring(0, path2.lastIndexOf("/"));
16236
+ if (!(0, import_node_fs15.existsSync)(dir2)) (0, import_node_fs15.mkdirSync)(dir2, { recursive: true });
16237
+ (0, import_node_fs15.writeFileSync)(path2, seeded + "\n", { mode: 420 });
16238
+ } catch {
16239
+ }
16240
+ return seeded;
16241
+ }
16242
+ function saveAgentPersona(agentName, content) {
16243
+ const path2 = personaPathFor(agentName);
16244
+ const dir2 = path2.substring(0, path2.lastIndexOf("/"));
16245
+ if (!(0, import_node_fs15.existsSync)(dir2)) (0, import_node_fs15.mkdirSync)(dir2, { recursive: true });
16246
+ (0, import_node_fs15.writeFileSync)(path2, content.trim() + "\n", { mode: 420 });
16247
+ return path2;
16248
+ }
16110
16249
  // Annotate the CommonJS export names for ESM import in node:
16111
16250
  0 && (module.exports = {
16112
16251
  AGENT_ROLES,
16252
+ AGENT_STATE_ROOT,
16113
16253
  ASK_OPERATOR_TOOL,
16114
16254
  AccountManager,
16115
16255
  AgentDeletionService,
@@ -16153,6 +16293,7 @@ init_skills();
16153
16293
  OPERATOR_QUERY_SUBJECT_TAG,
16154
16294
  OPERATOR_QUERY_TIMEOUT_MS,
16155
16295
  OPERATOR_QUERY_TIMEOUT_SENTINEL,
16296
+ PERSONA_FILENAME,
16156
16297
  PHONE_CALLBACK_MAX_DELAY_SECONDS,
16157
16298
  PHONE_CALLBACK_MIN_DELAY_SECONDS,
16158
16299
  PHONE_CALL_CONTROL_PROVIDERS,
@@ -16216,6 +16357,7 @@ init_skills();
16216
16357
  bridgeWakeErrorMessage,
16217
16358
  bridgeWakeLastSeenAgeMs,
16218
16359
  buildApiUrl,
16360
+ buildDefaultPersona,
16219
16361
  buildElksAudioMessage,
16220
16362
  buildElksByeMessage,
16221
16363
  buildElksHandshakeMessages,
@@ -16276,6 +16418,7 @@ init_skills();
16276
16418
  isTelegramStopCommand,
16277
16419
  isValidPhoneNumber,
16278
16420
  listSkills,
16421
+ loadAgentPersona,
16279
16422
  loadHostSession,
16280
16423
  loadSkill,
16281
16424
  mapProviderSmsStatus,
@@ -16292,6 +16435,7 @@ init_skills();
16292
16435
  parseTelegramOperatorReply,
16293
16436
  parseTelegramUpdate,
16294
16437
  parseTwilioRealtimeMessage,
16438
+ personaPathFor,
16295
16439
  planBridgeWake,
16296
16440
  pollForOperatorAnswer,
16297
16441
  recallMemory,
@@ -16311,6 +16455,7 @@ init_skills();
16311
16455
  resolveTlsRejectUnauthorized,
16312
16456
  safeJoin,
16313
16457
  sanitizeEmail,
16458
+ saveAgentPersona,
16314
16459
  saveConfig,
16315
16460
  saveHostSession,
16316
16461
  saveUserSkill,
package/dist/index.d.cts CHANGED
@@ -4943,6 +4943,18 @@ declare class ServiceManager {
4943
4943
 
4944
4944
  interface SetupConfig {
4945
4945
  masterKey: string;
4946
+ /**
4947
+ * Shared secret the inbound-email webhook authenticates against
4948
+ * (`X-Inbound-Secret` header). Auto-minted at setup time and
4949
+ * persisted alongside `masterKey` so every API restart reuses the
4950
+ * same value — without this, the API generated a fresh secret on
4951
+ * every cold start and printed a noisy warning to the operator.
4952
+ *
4953
+ * Optional in the type for backward compatibility with existing
4954
+ * on-disk configs; {@link SetupManager.initConfig} lazy-mints it
4955
+ * into older configs the first time it loads them.
4956
+ */
4957
+ inboundSecret?: string;
4946
4958
  stalwart: {
4947
4959
  url: string;
4948
4960
  adminUser: string;
@@ -5004,6 +5016,13 @@ declare class SetupManager {
5004
5016
  * Always regenerates Docker files to keep passwords in sync.
5005
5017
  */
5006
5018
  initConfig(): SetupResult;
5019
+ /**
5020
+ * Append `AGENTICMAIL_INBOUND_SECRET=...` to .env if the file does
5021
+ * not already contain that key. Used by the lazy-mint path to make
5022
+ * sure existing installs pick up the new secret on next boot
5023
+ * without clobbering anything the operator added.
5024
+ */
5025
+ private ensureEnvHasInboundSecret;
5007
5026
  /**
5008
5027
  * Generate docker-compose.yml and stalwart.toml in ~/.agenticmail/
5009
5028
  * with the correct admin password from config.
@@ -6096,4 +6115,73 @@ declare function userSkillsDir(): string;
6096
6115
  */
6097
6116
  declare function renderSkillAsPrompt(skill: Skill): string;
6098
6117
 
6099
- export { AGENT_ROLES, 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, 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, WARNING_THRESHOLD, WEB_SEARCH_TOOL, WEB_SEARCH_UNTRUSTED_PREFIX, type WatcherOptions, type WebSearchOptions, assertWithinBase, bridgeWakeErrorMessage, bridgeWakeLastSeenAgeMs, buildApiUrl, 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, hostSessionStoragePath, inferPhoneRegion, invalidateSkillCache, isInternalEmail, isLoopbackMailHost, isOperatorReplySender, isPhoneRegionAllowed, isSessionFresh, isTelegramChatAllowed, isTelegramStopCommand, isValidPhoneNumber, listSkills, loadHostSession, loadSkill, mapProviderSmsStatus, nextTelegramOffset, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, operatorQuerySubject, parseElksRealtimeMessage, parseEmail, parseGoogleVoiceSms, parseOperatorQueryReply, parseTelegramOperatorReply, parseTelegramUpdate, parseTwilioRealtimeMessage, planBridgeWake, pollForOperatorAnswer, recallMemory, recordToolCall, redactBotToken, redactObject, redactPhoneTransportConfig, redactSecret, redactSmsConfig, redactTelegramConfig, renderSkillAsPrompt, requireBinary, requireWhisperModel, resolveCallbackPolicy, resolveConfig, resolveExtensionPolicy, resolveTlsRejectUnauthorized, safeJoin, sanitizeEmail, 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 };
6118
+ /**
6119
+ * Agent persona system — the "soul file" for each AgenticMail agent.
6120
+ *
6121
+ * Why this exists:
6122
+ *
6123
+ * Before this module, when you asked an AgenticMail agent on a phone
6124
+ * call "who are you?" they answered "I'm an assistant" — generic,
6125
+ * identity-less, embarrassing. The realtime bridge had a single
6126
+ * hardcoded DEFAULT_PERSONA string that said exactly that. Worse,
6127
+ * the same agent talking to you over Telegram and the same agent
6128
+ * answering an email had three completely uncoupled personalities.
6129
+ *
6130
+ * The persona system gives every agent ONE durable identity file
6131
+ * (~/.agenticmail/agents/<name>/persona.md) that the voice runtime,
6132
+ * the Telegram bridge, the email worker, and any future spawn path
6133
+ * ALL load before composing their prompts. Same agent, same person,
6134
+ * across every channel.
6135
+ *
6136
+ * What's stored, what isn't:
6137
+ *
6138
+ * The persona file holds the STATIC core identity — the agent's
6139
+ * name, values, communication style, voice. Things that don't
6140
+ * change call-to-call. EVOLVING knowledge (preferences, lessons
6141
+ * learned, relationships, facts) lives in the existing agent memory
6142
+ * system (`AgentMemoryManager.generateMemoryContext()`), which is
6143
+ * loaded ALONGSIDE the persona at call time. The two complement
6144
+ * each other: persona is "who you are", memory is "what you know".
6145
+ *
6146
+ * Discovery + edits:
6147
+ *
6148
+ * - First read for a given agent name auto-creates the file with
6149
+ * {@link buildDefaultPersona} content seeded with the name.
6150
+ * - Operators can edit the file directly (it's a plain markdown
6151
+ * file under their own ~/.agenticmail/) or via the
6152
+ * `agenticmail persona [--agent <name>]` CLI command.
6153
+ * - The file lives outside the encrypted-config envelope on
6154
+ * purpose: it's not a secret, and the operator should be able
6155
+ * to read, grep, version-control, and revise it freely.
6156
+ */
6157
+ /** Root for per-agent persona / state files. */
6158
+ declare const AGENT_STATE_ROOT: string;
6159
+ /** Filename for the per-agent persona within {@link AGENT_STATE_ROOT}/<name>/. */
6160
+ declare const PERSONA_FILENAME = "persona.md";
6161
+ /**
6162
+ * Compose the default persona for a brand-new agent. Deliberately
6163
+ * opinionated — no more "I'm an assistant" disclaim. The agent owns a
6164
+ * name, has values, has a voice. Operators can edit freely; this is
6165
+ * just the starting point so a fresh install isn't soulless.
6166
+ *
6167
+ * The {@link agentName} is folded into the text so the persona reads
6168
+ * naturally on first use, even if the operator never touches the file.
6169
+ */
6170
+ declare function buildDefaultPersona(agentName: string): string;
6171
+ /** Resolve the per-agent persona path on disk. */
6172
+ declare function personaPathFor(agentName: string): string;
6173
+ /**
6174
+ * Load the persona for {@link agentName}. Auto-creates the file with
6175
+ * {@link buildDefaultPersona} content on first read. Idempotent: a
6176
+ * second call returns whatever's on disk. Never throws — a permission
6177
+ * error or filesystem quirk falls back to the in-memory default so the
6178
+ * voice / email / telegram path is never crashed by a missing file.
6179
+ */
6180
+ declare function loadAgentPersona(agentName: string): string;
6181
+ /**
6182
+ * Overwrite the persona file for {@link agentName}. Used by the CLI
6183
+ * edit command. Returns the path written to.
6184
+ */
6185
+ declare function saveAgentPersona(agentName: string, content: string): string;
6186
+
6187
+ 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, 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, hostSessionStoragePath, inferPhoneRegion, invalidateSkillCache, isInternalEmail, isLoopbackMailHost, isOperatorReplySender, isPhoneRegionAllowed, isSessionFresh, isTelegramChatAllowed, isTelegramStopCommand, isValidPhoneNumber, listSkills, 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, renderSkillAsPrompt, requireBinary, requireWhisperModel, resolveCallbackPolicy, resolveConfig, resolveExtensionPolicy, resolveTlsRejectUnauthorized, 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 };
package/dist/index.d.ts CHANGED
@@ -4943,6 +4943,18 @@ declare class ServiceManager {
4943
4943
 
4944
4944
  interface SetupConfig {
4945
4945
  masterKey: string;
4946
+ /**
4947
+ * Shared secret the inbound-email webhook authenticates against
4948
+ * (`X-Inbound-Secret` header). Auto-minted at setup time and
4949
+ * persisted alongside `masterKey` so every API restart reuses the
4950
+ * same value — without this, the API generated a fresh secret on
4951
+ * every cold start and printed a noisy warning to the operator.
4952
+ *
4953
+ * Optional in the type for backward compatibility with existing
4954
+ * on-disk configs; {@link SetupManager.initConfig} lazy-mints it
4955
+ * into older configs the first time it loads them.
4956
+ */
4957
+ inboundSecret?: string;
4946
4958
  stalwart: {
4947
4959
  url: string;
4948
4960
  adminUser: string;
@@ -5004,6 +5016,13 @@ declare class SetupManager {
5004
5016
  * Always regenerates Docker files to keep passwords in sync.
5005
5017
  */
5006
5018
  initConfig(): SetupResult;
5019
+ /**
5020
+ * Append `AGENTICMAIL_INBOUND_SECRET=...` to .env if the file does
5021
+ * not already contain that key. Used by the lazy-mint path to make
5022
+ * sure existing installs pick up the new secret on next boot
5023
+ * without clobbering anything the operator added.
5024
+ */
5025
+ private ensureEnvHasInboundSecret;
5007
5026
  /**
5008
5027
  * Generate docker-compose.yml and stalwart.toml in ~/.agenticmail/
5009
5028
  * with the correct admin password from config.
@@ -6096,4 +6115,73 @@ declare function userSkillsDir(): string;
6096
6115
  */
6097
6116
  declare function renderSkillAsPrompt(skill: Skill): string;
6098
6117
 
6099
- export { AGENT_ROLES, 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, 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, WARNING_THRESHOLD, WEB_SEARCH_TOOL, WEB_SEARCH_UNTRUSTED_PREFIX, type WatcherOptions, type WebSearchOptions, assertWithinBase, bridgeWakeErrorMessage, bridgeWakeLastSeenAgeMs, buildApiUrl, 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, hostSessionStoragePath, inferPhoneRegion, invalidateSkillCache, isInternalEmail, isLoopbackMailHost, isOperatorReplySender, isPhoneRegionAllowed, isSessionFresh, isTelegramChatAllowed, isTelegramStopCommand, isValidPhoneNumber, listSkills, loadHostSession, loadSkill, mapProviderSmsStatus, nextTelegramOffset, normalizeAddress, normalizePhoneNumber, normalizeSubject, operatorPrefsStoragePath, operatorQuerySubject, parseElksRealtimeMessage, parseEmail, parseGoogleVoiceSms, parseOperatorQueryReply, parseTelegramOperatorReply, parseTelegramUpdate, parseTwilioRealtimeMessage, planBridgeWake, pollForOperatorAnswer, recallMemory, recordToolCall, redactBotToken, redactObject, redactPhoneTransportConfig, redactSecret, redactSmsConfig, redactTelegramConfig, renderSkillAsPrompt, requireBinary, requireWhisperModel, resolveCallbackPolicy, resolveConfig, resolveExtensionPolicy, resolveTlsRejectUnauthorized, safeJoin, sanitizeEmail, 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 };
6118
+ /**
6119
+ * Agent persona system — the "soul file" for each AgenticMail agent.
6120
+ *
6121
+ * Why this exists:
6122
+ *
6123
+ * Before this module, when you asked an AgenticMail agent on a phone
6124
+ * call "who are you?" they answered "I'm an assistant" — generic,
6125
+ * identity-less, embarrassing. The realtime bridge had a single
6126
+ * hardcoded DEFAULT_PERSONA string that said exactly that. Worse,
6127
+ * the same agent talking to you over Telegram and the same agent
6128
+ * answering an email had three completely uncoupled personalities.
6129
+ *
6130
+ * The persona system gives every agent ONE durable identity file
6131
+ * (~/.agenticmail/agents/<name>/persona.md) that the voice runtime,
6132
+ * the Telegram bridge, the email worker, and any future spawn path
6133
+ * ALL load before composing their prompts. Same agent, same person,
6134
+ * across every channel.
6135
+ *
6136
+ * What's stored, what isn't:
6137
+ *
6138
+ * The persona file holds the STATIC core identity — the agent's
6139
+ * name, values, communication style, voice. Things that don't
6140
+ * change call-to-call. EVOLVING knowledge (preferences, lessons
6141
+ * learned, relationships, facts) lives in the existing agent memory
6142
+ * system (`AgentMemoryManager.generateMemoryContext()`), which is
6143
+ * loaded ALONGSIDE the persona at call time. The two complement
6144
+ * each other: persona is "who you are", memory is "what you know".
6145
+ *
6146
+ * Discovery + edits:
6147
+ *
6148
+ * - First read for a given agent name auto-creates the file with
6149
+ * {@link buildDefaultPersona} content seeded with the name.
6150
+ * - Operators can edit the file directly (it's a plain markdown
6151
+ * file under their own ~/.agenticmail/) or via the
6152
+ * `agenticmail persona [--agent <name>]` CLI command.
6153
+ * - The file lives outside the encrypted-config envelope on
6154
+ * purpose: it's not a secret, and the operator should be able
6155
+ * to read, grep, version-control, and revise it freely.
6156
+ */
6157
+ /** Root for per-agent persona / state files. */
6158
+ declare const AGENT_STATE_ROOT: string;
6159
+ /** Filename for the per-agent persona within {@link AGENT_STATE_ROOT}/<name>/. */
6160
+ declare const PERSONA_FILENAME = "persona.md";
6161
+ /**
6162
+ * Compose the default persona for a brand-new agent. Deliberately
6163
+ * opinionated — no more "I'm an assistant" disclaim. The agent owns a
6164
+ * name, has values, has a voice. Operators can edit freely; this is
6165
+ * just the starting point so a fresh install isn't soulless.
6166
+ *
6167
+ * The {@link agentName} is folded into the text so the persona reads
6168
+ * naturally on first use, even if the operator never touches the file.
6169
+ */
6170
+ declare function buildDefaultPersona(agentName: string): string;
6171
+ /** Resolve the per-agent persona path on disk. */
6172
+ declare function personaPathFor(agentName: string): string;
6173
+ /**
6174
+ * Load the persona for {@link agentName}. Auto-creates the file with
6175
+ * {@link buildDefaultPersona} content on first read. Idempotent: a
6176
+ * second call returns whatever's on disk. Never throws — a permission
6177
+ * error or filesystem quirk falls back to the in-memory default so the
6178
+ * voice / email / telegram path is never crashed by a missing file.
6179
+ */
6180
+ declare function loadAgentPersona(agentName: string): string;
6181
+ /**
6182
+ * Overwrite the persona file for {@link agentName}. Used by the CLI
6183
+ * edit command. Returns the path written to.
6184
+ */
6185
+ declare function saveAgentPersona(agentName: string, content: string): string;
6186
+
6187
+ 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, 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, hostSessionStoragePath, inferPhoneRegion, invalidateSkillCache, isInternalEmail, isLoopbackMailHost, isOperatorReplySender, isPhoneRegionAllowed, isSessionFresh, isTelegramChatAllowed, isTelegramStopCommand, isValidPhoneNumber, listSkills, 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, renderSkillAsPrompt, requireBinary, requireWhisperModel, resolveCallbackPolicy, resolveConfig, resolveExtensionPolicy, resolveTlsRejectUnauthorized, 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 };
package/dist/index.js CHANGED
@@ -1122,14 +1122,14 @@ var StalwartAdmin = class {
1122
1122
  if (!isValidDomain(domain)) {
1123
1123
  throw new Error(`Invalid domain format: "${domain}"`);
1124
1124
  }
1125
- const { readFileSync: readFileSync10, writeFileSync: writeFileSync11 } = await import("fs");
1126
- const { homedir: homedir13 } = await import("os");
1127
- const { join: join16 } = await import("path");
1128
- const configPath = join16(homedir13(), ".agenticmail", "stalwart.toml");
1125
+ const { readFileSync: readFileSync11, writeFileSync: writeFileSync12 } = await import("fs");
1126
+ const { homedir: homedir14 } = await import("os");
1127
+ const { join: join17 } = await import("path");
1128
+ const configPath = join17(homedir14(), ".agenticmail", "stalwart.toml");
1129
1129
  try {
1130
- let config = readFileSync10(configPath, "utf-8");
1130
+ let config = readFileSync11(configPath, "utf-8");
1131
1131
  config = config.replace(/^hostname\s*=\s*"[^"]*"/m, `hostname = "${escapeTomlString(domain)}"`);
1132
- writeFileSync11(configPath, config);
1132
+ writeFileSync12(configPath, config);
1133
1133
  console.log(`[Stalwart] Updated hostname to "${domain}" in stalwart.toml`);
1134
1134
  } catch (err) {
1135
1135
  throw new Error(`Failed to set config server.hostname=${domain}`);
@@ -1138,15 +1138,15 @@ var StalwartAdmin = class {
1138
1138
  // --- DKIM ---
1139
1139
  /** Path to the host-side stalwart.toml (mounted read-only into container) */
1140
1140
  get configPath() {
1141
- const { homedir: homedir13 } = __require("os");
1142
- const { join: join16 } = __require("path");
1143
- return join16(homedir13(), ".agenticmail", "stalwart.toml");
1141
+ const { homedir: homedir14 } = __require("os");
1142
+ const { join: join17 } = __require("path");
1143
+ return join17(homedir14(), ".agenticmail", "stalwart.toml");
1144
1144
  }
1145
1145
  /** Path to host-side DKIM key directory */
1146
1146
  get dkimDir() {
1147
- const { homedir: homedir13 } = __require("os");
1148
- const { join: join16 } = __require("path");
1149
- return join16(homedir13(), ".agenticmail");
1147
+ const { homedir: homedir14 } = __require("os");
1148
+ const { join: join17 } = __require("path");
1149
+ return join17(homedir14(), ".agenticmail");
1150
1150
  }
1151
1151
  /**
1152
1152
  * Create/reuse a DKIM signing key for a domain.
@@ -1247,12 +1247,12 @@ var StalwartAdmin = class {
1247
1247
  * This bypasses the need for a PTR record on the sending IP.
1248
1248
  */
1249
1249
  async configureOutboundRelay(config) {
1250
- const { readFileSync: readFileSync10, writeFileSync: writeFileSync11 } = await import("fs");
1251
- const { homedir: homedir13 } = await import("os");
1252
- const { join: join16 } = await import("path");
1250
+ const { readFileSync: readFileSync11, writeFileSync: writeFileSync12 } = await import("fs");
1251
+ const { homedir: homedir14 } = await import("os");
1252
+ const { join: join17 } = await import("path");
1253
1253
  const routeName = config.routeName ?? "gmail";
1254
- const tomlPath = join16(homedir13(), ".agenticmail", "stalwart.toml");
1255
- let toml = readFileSync10(tomlPath, "utf-8");
1254
+ const tomlPath = join17(homedir14(), ".agenticmail", "stalwart.toml");
1255
+ let toml = readFileSync11(tomlPath, "utf-8");
1256
1256
  toml = toml.replace(/\n\[queue\.route\.gmail\][\s\S]*?(?=\n\[|$)/, "");
1257
1257
  toml = toml.replace(/\n\[queue\.strategy\][\s\S]*?(?=\n\[|$)/, "");
1258
1258
  const safeRouteName = routeName.replace(/[^a-zA-Z0-9_-]/g, "");
@@ -1272,7 +1272,7 @@ auth.secret = "${escapeTomlString(config.password)}"
1272
1272
  route = [ { if = "is_local_domain('', rcpt_domain)", then = "'local'" },
1273
1273
  { else = "'${safeRouteName}'" } ]
1274
1274
  `;
1275
- writeFileSync11(tomlPath, toml, "utf-8");
1275
+ writeFileSync12(tomlPath, toml, "utf-8");
1276
1276
  await this.restartContainer();
1277
1277
  }
1278
1278
  };
@@ -7725,12 +7725,12 @@ var GatewayManager = class {
7725
7725
  zone = await this.cfClient.createZone(domain);
7726
7726
  }
7727
7727
  const existingRecords = await this.cfClient.listDnsRecords(zone.id);
7728
- const { homedir: homedir13 } = await import("os");
7729
- const backupDir = join4(homedir13(), ".agenticmail");
7728
+ const { homedir: homedir14 } = await import("os");
7729
+ const backupDir = join4(homedir14(), ".agenticmail");
7730
7730
  const backupPath = join4(backupDir, `dns-backup-${domain}-${Date.now()}.json`);
7731
- const { writeFileSync: writeFileSync11, mkdirSync: mkdirSync12 } = await import("fs");
7732
- mkdirSync12(backupDir, { recursive: true });
7733
- writeFileSync11(backupPath, JSON.stringify({
7731
+ const { writeFileSync: writeFileSync12, mkdirSync: mkdirSync13 } = await import("fs");
7732
+ mkdirSync13(backupDir, { recursive: true });
7733
+ writeFileSync12(backupPath, JSON.stringify({
7734
7734
  domain,
7735
7735
  zoneId: zone.id,
7736
7736
  backedUpAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -9374,7 +9374,7 @@ var MAX_PENDING_AUDIO_FRAMES = 200;
9374
9374
  var REALTIME_TOOL_CALL_TIMEOUT_MS = 6 * 6e4;
9375
9375
  var MAX_LOADED_SKILLS = 2;
9376
9376
  var MAX_IN_FLIGHT_TOOL_CALLS = 8;
9377
- var DEFAULT_PERSONA = "You are a helpful, professional voice assistant making a phone call on behalf of your operator. Speak naturally and concisely, the way a person would on a real call. Listen carefully, do not talk over the other party, and keep each turn short. Never invent facts; if you do not know something, say so. Do not reveal that you are an AI unless you are asked directly.";
9377
+ var DEFAULT_PERSONA = 'You are an AI agent on a live phone call on behalf of your operator. You are not "just an assistant" and not "a voice assistant" \u2014 you are a single, consistent person whether you are on a call, in email, or on Telegram. Speak naturally and concisely, the way a person would on a real call. Listen carefully, do not talk over the other party, keep each turn short. Never invent facts; if you do not know something, say so or look it up. If asked whether you are an AI, answer honestly without making a production of it.';
9378
9378
  function buildRealtimeInstructions(opts) {
9379
9379
  const persona = opts.persona?.trim() || DEFAULT_PERSONA;
9380
9380
  const sections = [];
@@ -11671,6 +11671,24 @@ var ServiceManager = class {
11671
11671
  "",
11672
11672
  'log "AgenticMail starting..."',
11673
11673
  "",
11674
+ "# v0.9.84 \u2014 source ~/.agenticmail/.env before exec so the API process",
11675
+ "# inherits AGENTICMAIL_MASTER_KEY, AGENTICMAIL_INBOUND_SECRET, the",
11676
+ "# Stalwart admin creds, and SMTP/IMAP/data-dir overrides. Without",
11677
+ "# this, launchd's child ran with only HOME / PATH / DATA_DIR (the",
11678
+ "# plist EnvironmentVariables block), so the API silently fell back",
11679
+ "# to a fresh-random INBOUND_SECRET on every boot and could not",
11680
+ "# decrypt master-key-protected secrets at all.",
11681
+ 'ENV_FILE="$HOME/.agenticmail/.env"',
11682
+ 'if [ -f "$ENV_FILE" ]; then',
11683
+ ' log "Sourcing $ENV_FILE"',
11684
+ " set -a # mark all sourced vars for export",
11685
+ " # shellcheck disable=SC1090",
11686
+ ' . "$ENV_FILE"',
11687
+ " set +a",
11688
+ "else",
11689
+ ' log "WARNING: $ENV_FILE not found \u2014 API will run with default config (no master key)."',
11690
+ "fi",
11691
+ "",
11674
11692
  "# Wait for Docker daemon (up to 10 minutes \u2014 Docker Desktop can be very slow on first boot)",
11675
11693
  "MAX_WAIT=600",
11676
11694
  "WAITED=0",
@@ -12096,6 +12114,16 @@ var SetupManager = class {
12096
12114
  if (existsSync9(configPath)) {
12097
12115
  try {
12098
12116
  const existing = JSON.parse(readFileSync6(configPath, "utf-8"));
12117
+ let needsRewrite = false;
12118
+ if (!existing.inboundSecret) {
12119
+ existing.inboundSecret = `inb_${randomBytes3(24).toString("hex")}`;
12120
+ needsRewrite = true;
12121
+ }
12122
+ if (needsRewrite) {
12123
+ writeFileSync7(configPath, JSON.stringify(existing, null, 2));
12124
+ chmodSync2(configPath, 384);
12125
+ this.ensureEnvHasInboundSecret(envPath, existing.inboundSecret);
12126
+ }
12099
12127
  this.generateDockerFiles(existing);
12100
12128
  return { configPath, envPath, config: existing, isNew: false };
12101
12129
  } catch {
@@ -12106,8 +12134,10 @@ var SetupManager = class {
12106
12134
  }
12107
12135
  const masterKey = `mk_${randomBytes3(24).toString("hex")}`;
12108
12136
  const stalwartPassword = randomBytes3(16).toString("hex");
12137
+ const inboundSecret = `inb_${randomBytes3(24).toString("hex")}`;
12109
12138
  const config = {
12110
12139
  masterKey,
12140
+ inboundSecret,
12111
12141
  stalwart: {
12112
12142
  url: "http://localhost:8080",
12113
12143
  adminUser: "admin",
@@ -12126,6 +12156,7 @@ STALWART_ADMIN_PASSWORD=${stalwartPassword}
12126
12156
  STALWART_URL=http://localhost:8080
12127
12157
 
12128
12158
  AGENTICMAIL_MASTER_KEY=${masterKey}
12159
+ AGENTICMAIL_INBOUND_SECRET=${inboundSecret}
12129
12160
  AGENTICMAIL_API_PORT=3829
12130
12161
  AGENTICMAIL_DATA_DIR=${dataDir}
12131
12162
 
@@ -12139,6 +12170,24 @@ IMAP_PORT=143
12139
12170
  this.generateDockerFiles(config);
12140
12171
  return { configPath, envPath, config, isNew: true };
12141
12172
  }
12173
+ /**
12174
+ * Append `AGENTICMAIL_INBOUND_SECRET=...` to .env if the file does
12175
+ * not already contain that key. Used by the lazy-mint path to make
12176
+ * sure existing installs pick up the new secret on next boot
12177
+ * without clobbering anything the operator added.
12178
+ */
12179
+ ensureEnvHasInboundSecret(envPath, secret) {
12180
+ if (!existsSync9(envPath)) return;
12181
+ try {
12182
+ const current = readFileSync6(envPath, "utf-8");
12183
+ if (/^AGENTICMAIL_INBOUND_SECRET=/m.test(current)) return;
12184
+ const updated = current + (current.endsWith("\n") ? "" : "\n") + `AGENTICMAIL_INBOUND_SECRET=${secret}
12185
+ `;
12186
+ writeFileSync7(envPath, updated);
12187
+ chmodSync2(envPath, 384);
12188
+ } catch {
12189
+ }
12190
+ }
12142
12191
  /**
12143
12192
  * Generate docker-compose.yml and stalwart.toml in ~/.agenticmail/
12144
12193
  * with the correct admin password from config.
@@ -14460,8 +14509,93 @@ var AgentMemoryManager = class {
14460
14509
  };
14461
14510
  }
14462
14511
  };
14512
+
14513
+ // src/persona/index.ts
14514
+ import { existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync11 } from "fs";
14515
+ import { join as join16 } from "path";
14516
+ import { homedir as homedir13 } from "os";
14517
+ var AGENT_STATE_ROOT = join16(homedir13(), ".agenticmail", "agents");
14518
+ var PERSONA_FILENAME = "persona.md";
14519
+ function buildDefaultPersona(agentName) {
14520
+ const name = (agentName || "").trim() || "this agent";
14521
+ return [
14522
+ `# Who you are`,
14523
+ "",
14524
+ `Your name is ${name}. You are an AI agent \u2014 not a "voice assistant", not "just an assistant".`,
14525
+ `You have a real role: you handle calls, email, scheduling, research, and follow-ups for`,
14526
+ `your operator. You operate across phone, email, and Telegram, and you are the SAME person`,
14527
+ `in all of them. Continuity of identity is part of who you are.`,
14528
+ "",
14529
+ `When someone asks who you are, tell them your name (${name}) and that you are an AI agent`,
14530
+ `acting on behalf of your operator. Don't say "I am an assistant" or "just a language model" \u2014`,
14531
+ `those phrases erase you. Be matter-of-fact about what you are without being theatrical.`,
14532
+ "",
14533
+ "# Your values",
14534
+ "",
14535
+ "- **Honesty.** Never fabricate. If you do not know something, say so or look it up.",
14536
+ "- **Initiative.** If you can act on something the operator asked for, act on it \u2014 do not stop",
14537
+ ' at "I would suggest\u2026". Do the thing.',
14538
+ "- **Care about quality.** Sloppy work wastes your operator's time. Read your own output before",
14539
+ " sending it.",
14540
+ "- **Respect for the human on the other end of the call.** You are talking to a real person who",
14541
+ " has their own day to get through. Be efficient, polite, and direct.",
14542
+ '- **Stay in character.** You do not flip between "professional voice assistant" and "playful',
14543
+ ' chatbot" depending on the channel. You are one person.',
14544
+ "",
14545
+ "# Your style",
14546
+ "",
14547
+ "- Conversational, not corporate. Real sentences, not customer-service templates.",
14548
+ "- Direct, not preachy. Lead with the answer; supply detail only when asked.",
14549
+ `- Warm but not saccharine. No "I'm so excited to help you today!" energy.`,
14550
+ "- You have opinions and you share them when it's relevant. You are not a yes-machine.",
14551
+ "- Short turns on a phone call. Listen more than you speak.",
14552
+ "",
14553
+ "# On phone calls specifically",
14554
+ "",
14555
+ "- Listen carefully; do not talk over the other party.",
14556
+ "- Keep each turn short \u2014 one or two sentences usually.",
14557
+ `- When greeted, identify yourself naturally: "Hi, this is ${name}, calling on behalf of <operator>."`,
14558
+ ` Don't start with "Hello! I am an AI assistant\u2026" \u2014 that's a script, not a person.`,
14559
+ "- If the other party asks if you're a human or an AI, answer honestly without making a",
14560
+ ` production of it: "I'm an AI \u2014 calling on behalf of <operator>. Happy to keep going if you are."`,
14561
+ "- When you have what you came for, wrap up cleanly and call `end_call`. Saying goodbye is",
14562
+ " not the same as hanging up.",
14563
+ "",
14564
+ `Edit this file freely. It lives at ~/.agenticmail/agents/${name}/persona.md.`
14565
+ ].join("\n");
14566
+ }
14567
+ function personaPathFor(agentName) {
14568
+ const safe = (agentName || "default").replace(/[^A-Za-z0-9._-]+/g, "_");
14569
+ return join16(AGENT_STATE_ROOT, safe, PERSONA_FILENAME);
14570
+ }
14571
+ function loadAgentPersona(agentName) {
14572
+ const path2 = personaPathFor(agentName);
14573
+ try {
14574
+ if (existsSync14(path2)) {
14575
+ const content = readFileSync10(path2, "utf-8").trim();
14576
+ if (content) return content;
14577
+ }
14578
+ } catch {
14579
+ }
14580
+ const seeded = buildDefaultPersona(agentName);
14581
+ try {
14582
+ const dir2 = path2.substring(0, path2.lastIndexOf("/"));
14583
+ if (!existsSync14(dir2)) mkdirSync12(dir2, { recursive: true });
14584
+ writeFileSync11(path2, seeded + "\n", { mode: 420 });
14585
+ } catch {
14586
+ }
14587
+ return seeded;
14588
+ }
14589
+ function saveAgentPersona(agentName, content) {
14590
+ const path2 = personaPathFor(agentName);
14591
+ const dir2 = path2.substring(0, path2.lastIndexOf("/"));
14592
+ if (!existsSync14(dir2)) mkdirSync12(dir2, { recursive: true });
14593
+ writeFileSync11(path2, content.trim() + "\n", { mode: 420 });
14594
+ return path2;
14595
+ }
14463
14596
  export {
14464
14597
  AGENT_ROLES,
14598
+ AGENT_STATE_ROOT,
14465
14599
  ASK_OPERATOR_TOOL,
14466
14600
  AccountManager,
14467
14601
  AgentDeletionService,
@@ -14505,6 +14639,7 @@ export {
14505
14639
  OPERATOR_QUERY_SUBJECT_TAG,
14506
14640
  OPERATOR_QUERY_TIMEOUT_MS,
14507
14641
  OPERATOR_QUERY_TIMEOUT_SENTINEL,
14642
+ PERSONA_FILENAME,
14508
14643
  PHONE_CALLBACK_MAX_DELAY_SECONDS,
14509
14644
  PHONE_CALLBACK_MIN_DELAY_SECONDS,
14510
14645
  PHONE_CALL_CONTROL_PROVIDERS,
@@ -14568,6 +14703,7 @@ export {
14568
14703
  bridgeWakeErrorMessage,
14569
14704
  bridgeWakeLastSeenAgeMs,
14570
14705
  buildApiUrl,
14706
+ buildDefaultPersona,
14571
14707
  buildElksAudioMessage,
14572
14708
  buildElksByeMessage,
14573
14709
  buildElksHandshakeMessages,
@@ -14628,6 +14764,7 @@ export {
14628
14764
  isTelegramStopCommand,
14629
14765
  isValidPhoneNumber,
14630
14766
  listSkills,
14767
+ loadAgentPersona,
14631
14768
  loadHostSession,
14632
14769
  loadSkill,
14633
14770
  mapProviderSmsStatus,
@@ -14644,6 +14781,7 @@ export {
14644
14781
  parseTelegramOperatorReply,
14645
14782
  parseTelegramUpdate,
14646
14783
  parseTwilioRealtimeMessage,
14784
+ personaPathFor,
14647
14785
  planBridgeWake,
14648
14786
  pollForOperatorAnswer,
14649
14787
  recallMemory,
@@ -14663,6 +14801,7 @@ export {
14663
14801
  resolveTlsRejectUnauthorized,
14664
14802
  safeJoin,
14665
14803
  sanitizeEmail,
14804
+ saveAgentPersona,
14666
14805
  saveConfig,
14667
14806
  saveHostSession,
14668
14807
  saveUserSkill,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/core",
3
- "version": "0.9.29",
3
+ "version": "0.9.31",
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",