@agenticmail/enterprise 0.5.378 → 0.5.379

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.
@@ -0,0 +1,510 @@
1
+ import "./chunk-KFQGP6VL.js";
2
+
3
+ // src/engine/agent-heartbeat.ts
4
+ var DEFAULT_SETTINGS = {
5
+ enabled: true,
6
+ baseIntervalMs: 5 * 6e4,
7
+ // 5 minutes
8
+ maxIntervalMs: 30 * 6e4,
9
+ // 30 minutes
10
+ dampingFactor: 0.5,
11
+ maxBatchSize: 5,
12
+ quietHoursStart: 23,
13
+ quietHoursEnd: 8
14
+ };
15
+ function createUnreadEmailCheck() {
16
+ return {
17
+ id: "unread_emails",
18
+ name: "Unread Emails",
19
+ intervalMs: 10 * 6e4,
20
+ // 10 minutes
21
+ priority: "high",
22
+ requiresClockIn: false,
23
+ // emails can be urgent outside hours
24
+ consecutiveNoOps: 0,
25
+ enabled: true,
26
+ check: async (ctx) => {
27
+ try {
28
+ const rows = await ctx.db.query(
29
+ `SELECT COUNT(*) as cnt FROM agent_memory
30
+ WHERE agent_id = $1
31
+ AND category = 'processed_email'
32
+ AND created_at > NOW() - INTERVAL '4 hours'`,
33
+ [ctx.agentId]
34
+ );
35
+ const processedRecently = parseInt(rows?.[0]?.cnt || "0");
36
+ const lastProcessed = await ctx.db.query(
37
+ `SELECT MAX(created_at) as last_at FROM agent_memory
38
+ WHERE agent_id = $1 AND category = 'processed_email'`,
39
+ [ctx.agentId]
40
+ );
41
+ const lastAt = lastProcessed?.[0]?.last_at;
42
+ if (ctx.isWorkHours && processedRecently === 0 && ctx.hour >= 10) {
43
+ return {
44
+ needsAction: true,
45
+ summary: "No emails processed in the last 4 hours during work hours. Check inbox.",
46
+ priority: "medium",
47
+ data: { lastProcessedAt: lastAt }
48
+ };
49
+ }
50
+ return { needsAction: false, priority: "low" };
51
+ } catch {
52
+ return { needsAction: false, priority: "low" };
53
+ }
54
+ }
55
+ };
56
+ }
57
+ function createUpcomingEventsCheck() {
58
+ return {
59
+ id: "upcoming_events",
60
+ name: "Upcoming Calendar Events",
61
+ intervalMs: 15 * 6e4,
62
+ // 15 minutes
63
+ priority: "high",
64
+ requiresClockIn: false,
65
+ consecutiveNoOps: 0,
66
+ enabled: true,
67
+ check: async (ctx) => {
68
+ try {
69
+ const _twoHoursFromNow = new Date(ctx.now.getTime() + 2 * 60 * 60 * 1e3).toISOString();
70
+ const rows = await ctx.db.query(
71
+ `SELECT content FROM agent_memory
72
+ WHERE agent_id = $1
73
+ AND category = 'context'
74
+ AND content LIKE '%meeting%'
75
+ AND created_at > NOW() - INTERVAL '24 hours'
76
+ ORDER BY created_at DESC LIMIT 5`,
77
+ [ctx.agentId]
78
+ );
79
+ const upcomingMeetings = (rows || []).filter((r) => {
80
+ const content = r.content || "";
81
+ return content.includes("meeting") || content.includes("event");
82
+ });
83
+ if (upcomingMeetings.length > 0) {
84
+ return {
85
+ needsAction: true,
86
+ summary: `${upcomingMeetings.length} potential upcoming event(s). Agent should check Google Calendar.`,
87
+ priority: "high",
88
+ data: { count: upcomingMeetings.length }
89
+ };
90
+ }
91
+ return { needsAction: false, priority: "low" };
92
+ } catch {
93
+ return { needsAction: false, priority: "low" };
94
+ }
95
+ }
96
+ };
97
+ }
98
+ function createStaleSessionsCheck() {
99
+ return {
100
+ id: "stale_sessions",
101
+ name: "Stale Sessions",
102
+ intervalMs: 30 * 6e4,
103
+ // 30 minutes
104
+ priority: "medium",
105
+ requiresClockIn: true,
106
+ consecutiveNoOps: 0,
107
+ enabled: true,
108
+ check: async (ctx) => {
109
+ try {
110
+ const rows = await ctx.db.query(
111
+ `SELECT COUNT(*) as cnt FROM agent_sessions
112
+ WHERE agent_id = $1
113
+ AND status = 'active'
114
+ AND updated_at < NOW() - INTERVAL '2 hours'`,
115
+ [ctx.agentId]
116
+ );
117
+ const staleCount = parseInt(rows?.[0]?.cnt || "0");
118
+ if (staleCount > 0) {
119
+ return {
120
+ needsAction: true,
121
+ summary: `${staleCount} stale session(s) detected (active > 2 hours with no updates). May need cleanup.`,
122
+ priority: "medium",
123
+ data: { staleCount }
124
+ };
125
+ }
126
+ return { needsAction: false, priority: "low" };
127
+ } catch {
128
+ return { needsAction: false, priority: "low" };
129
+ }
130
+ }
131
+ };
132
+ }
133
+ function createMemoryHealthCheck() {
134
+ return {
135
+ id: "memory_health",
136
+ name: "Memory Health",
137
+ intervalMs: 60 * 6e4,
138
+ // 1 hour
139
+ priority: "low",
140
+ requiresClockIn: true,
141
+ consecutiveNoOps: 0,
142
+ enabled: true,
143
+ check: async (ctx) => {
144
+ try {
145
+ const rows = await ctx.db.query(
146
+ `SELECT COUNT(*) as cnt FROM agent_memory
147
+ WHERE agent_id = $1 AND created_at > NOW() - INTERVAL '24 hours'`,
148
+ [ctx.agentId]
149
+ );
150
+ const recentCount = parseInt(rows?.[0]?.cnt || "0");
151
+ if (recentCount > 200) {
152
+ return {
153
+ needsAction: true,
154
+ summary: `Memory flood detected: ${recentCount} memories in 24h (threshold: 200). Consider pruning.`,
155
+ priority: "medium",
156
+ data: { recentCount }
157
+ };
158
+ }
159
+ return { needsAction: false, priority: "low" };
160
+ } catch {
161
+ return { needsAction: false, priority: "low" };
162
+ }
163
+ }
164
+ };
165
+ }
166
+ function createUnansweredChatCheck() {
167
+ return {
168
+ id: "unanswered_chat",
169
+ name: "Unanswered Chat Messages",
170
+ intervalMs: 5 * 6e4,
171
+ // 5 minutes
172
+ priority: "high",
173
+ requiresClockIn: false,
174
+ consecutiveNoOps: 0,
175
+ enabled: true,
176
+ check: async (ctx) => {
177
+ try {
178
+ const rows = await ctx.db.query(
179
+ `SELECT COUNT(*) as cnt FROM agent_sessions
180
+ WHERE agent_id = $1
181
+ AND status = 'failed'
182
+ AND metadata::text LIKE '%chat%'
183
+ AND created_at > NOW() - INTERVAL '1 hour'`,
184
+ [ctx.agentId]
185
+ );
186
+ const failedChats = parseInt(rows?.[0]?.cnt || "0");
187
+ if (failedChats > 0) {
188
+ return {
189
+ needsAction: true,
190
+ summary: `${failedChats} failed chat session(s) in the last hour. Messages may be unanswered.`,
191
+ priority: "urgent",
192
+ data: { failedChats }
193
+ };
194
+ }
195
+ return { needsAction: false, priority: "low" };
196
+ } catch {
197
+ return { needsAction: false, priority: "low" };
198
+ }
199
+ }
200
+ };
201
+ }
202
+ function createTaskDeadlineCheck() {
203
+ return {
204
+ id: "task_deadlines",
205
+ name: "Task Deadlines",
206
+ intervalMs: 60 * 6e4,
207
+ // 1 hour
208
+ priority: "medium",
209
+ requiresClockIn: true,
210
+ consecutiveNoOps: 0,
211
+ enabled: true,
212
+ check: async (ctx) => {
213
+ try {
214
+ const rows = await ctx.db.query(
215
+ `SELECT COUNT(*) as cnt FROM agent_memory
216
+ WHERE agent_id = $1
217
+ AND category = 'context'
218
+ AND importance = 'high'
219
+ AND content LIKE '%deadline%'
220
+ AND created_at > NOW() - INTERVAL '48 hours'`,
221
+ [ctx.agentId]
222
+ );
223
+ const urgentTasks = parseInt(rows?.[0]?.cnt || "0");
224
+ if (urgentTasks > 0) {
225
+ return {
226
+ needsAction: true,
227
+ summary: `${urgentTasks} task(s) with approaching deadlines. Agent should review and prioritize.`,
228
+ priority: "high",
229
+ data: { urgentTasks }
230
+ };
231
+ }
232
+ return { needsAction: false, priority: "low" };
233
+ } catch {
234
+ return { needsAction: false, priority: "low" };
235
+ }
236
+ }
237
+ };
238
+ }
239
+ function createErrorRateCheck() {
240
+ return {
241
+ id: "error_rate",
242
+ name: "Error Rate Monitor",
243
+ intervalMs: 15 * 6e4,
244
+ // 15 minutes
245
+ priority: "high",
246
+ requiresClockIn: false,
247
+ // errors can happen anytime
248
+ consecutiveNoOps: 0,
249
+ enabled: true,
250
+ check: async (ctx) => {
251
+ try {
252
+ const totalRows = await ctx.db.query(
253
+ `SELECT COUNT(*) as cnt FROM agent_sessions
254
+ WHERE agent_id = $1 AND created_at > NOW() - INTERVAL '1 hour'`,
255
+ [ctx.agentId]
256
+ );
257
+ const failedRows = await ctx.db.query(
258
+ `SELECT COUNT(*) as cnt FROM agent_sessions
259
+ WHERE agent_id = $1 AND status = 'failed' AND created_at > NOW() - INTERVAL '1 hour'`,
260
+ [ctx.agentId]
261
+ );
262
+ const total = parseInt(totalRows?.[0]?.cnt || "0");
263
+ const failed = parseInt(failedRows?.[0]?.cnt || "0");
264
+ if (total >= 3 && failed / total > 0.5) {
265
+ return {
266
+ needsAction: true,
267
+ summary: `High error rate: ${failed}/${total} sessions failed in the last hour (${Math.round(failed / total * 100)}%). Possible infrastructure issue.`,
268
+ priority: "urgent",
269
+ data: { total, failed, rate: failed / total }
270
+ };
271
+ }
272
+ return { needsAction: false, priority: "low" };
273
+ } catch {
274
+ return { needsAction: false, priority: "low" };
275
+ }
276
+ }
277
+ };
278
+ }
279
+ var AgentHeartbeatManager = class {
280
+ config;
281
+ settings;
282
+ checks = /* @__PURE__ */ new Map();
283
+ tickTimer = null;
284
+ globalConsecutiveNoOps = 0;
285
+ lastActionTimestamp = 0;
286
+ stats = {
287
+ totalTicks: 0,
288
+ totalChecksRun: 0,
289
+ totalActionsTriggered: 0,
290
+ totalTokensSaved: 0,
291
+ // estimated tokens NOT spent due to no-op ticks
292
+ startedAt: Date.now()
293
+ };
294
+ constructor(config, settings) {
295
+ this.config = config;
296
+ this.settings = { ...DEFAULT_SETTINGS, ...settings };
297
+ this.registerCheck(createUnreadEmailCheck());
298
+ this.registerCheck(createUpcomingEventsCheck());
299
+ this.registerCheck(createStaleSessionsCheck());
300
+ this.registerCheck(createMemoryHealthCheck());
301
+ this.registerCheck(createUnansweredChatCheck());
302
+ this.registerCheck(createTaskDeadlineCheck());
303
+ this.registerCheck(createErrorRateCheck());
304
+ if (config.enabledChecks) {
305
+ for (const [id, enabled] of Object.entries(config.enabledChecks)) {
306
+ const check = this.checks.get(id);
307
+ if (check) check.enabled = enabled;
308
+ }
309
+ }
310
+ }
311
+ registerCheck(check) {
312
+ this.checks.set(check.id, check);
313
+ }
314
+ async start() {
315
+ if (!this.settings.enabled) {
316
+ console.log("[heartbeat] Disabled, skipping");
317
+ return;
318
+ }
319
+ console.log(`[heartbeat] Starting with ${this.checks.size} checks, base interval ${this.settings.baseIntervalMs / 1e3}s`);
320
+ setTimeout(() => this.tick(), 6e4);
321
+ this.scheduleNextTick();
322
+ }
323
+ stop() {
324
+ if (this.tickTimer) {
325
+ clearTimeout(this.tickTimer);
326
+ this.tickTimer = null;
327
+ }
328
+ console.log(`[heartbeat] Stopped. Stats: ${this.stats.totalTicks} ticks, ${this.stats.totalChecksRun} checks, ${this.stats.totalActionsTriggered} actions, ~${this.stats.totalTokensSaved} tokens saved`);
329
+ }
330
+ getStats() {
331
+ return {
332
+ ...this.stats,
333
+ uptimeMs: Date.now() - this.stats.startedAt,
334
+ currentIntervalMs: this.calculateInterval(),
335
+ globalConsecutiveNoOps: this.globalConsecutiveNoOps,
336
+ checks: Array.from(this.checks.values()).map((c) => ({
337
+ id: c.id,
338
+ name: c.name,
339
+ enabled: c.enabled,
340
+ lastRunAt: c.lastRunAt,
341
+ lastActionAt: c.lastActionAt,
342
+ consecutiveNoOps: c.consecutiveNoOps
343
+ }))
344
+ };
345
+ }
346
+ // ─── Core Tick Logic ────────────────────────────────
347
+ async tick() {
348
+ this.stats.totalTicks++;
349
+ const now = /* @__PURE__ */ new Date();
350
+ const tz = this.config.timezone || "UTC";
351
+ const localTime = new Date(now.toLocaleString("en-US", { timeZone: tz }));
352
+ const hour = localTime.getHours();
353
+ const minute = localTime.getMinutes();
354
+ const dayOfWeek = localTime.getDay();
355
+ const isWorkHours = this.isWithinWorkHours(hour, minute, dayOfWeek);
356
+ const isQuietHours = this.isQuietHours(hour);
357
+ const isClockedIn = this.config.isClockedIn();
358
+ const ctx = {
359
+ agentId: this.config.agentId,
360
+ orgId: this.config.orgId,
361
+ agentName: this.config.agentName,
362
+ role: this.config.role,
363
+ managerEmail: this.config.managerEmail,
364
+ timezone: tz,
365
+ db: this.config.db,
366
+ now,
367
+ localTime,
368
+ hour,
369
+ minute,
370
+ dayOfWeek,
371
+ isWorkHours,
372
+ isClockedIn
373
+ };
374
+ const actionableItems = [];
375
+ for (const check of this.checks.values()) {
376
+ if (!check.enabled) continue;
377
+ if (check.requiresClockIn && !isClockedIn) continue;
378
+ if (isQuietHours && check.priority !== "high") continue;
379
+ const adaptiveInterval = Math.min(
380
+ check.intervalMs * (1 + this.settings.dampingFactor * check.consecutiveNoOps),
381
+ this.settings.maxIntervalMs
382
+ );
383
+ const timeSinceLastRun = now.getTime() - (check.lastRunAt || 0);
384
+ if (timeSinceLastRun < adaptiveInterval) continue;
385
+ this.stats.totalChecksRun++;
386
+ check.lastRunAt = now.getTime();
387
+ try {
388
+ const result = await check.check(ctx);
389
+ if (result.needsAction) {
390
+ actionableItems.push({ check, result });
391
+ check.consecutiveNoOps = 0;
392
+ check.lastActionAt = now.getTime();
393
+ } else {
394
+ check.consecutiveNoOps++;
395
+ this.stats.totalTokensSaved += 500;
396
+ }
397
+ } catch (err) {
398
+ console.warn(`[heartbeat] Check ${check.id} error: ${err.message}`);
399
+ check.consecutiveNoOps++;
400
+ }
401
+ }
402
+ if (actionableItems.length > 0) {
403
+ this.globalConsecutiveNoOps = 0;
404
+ this.lastActionTimestamp = now.getTime();
405
+ this.stats.totalActionsTriggered++;
406
+ const priorityOrder = { urgent: 0, high: 1, medium: 2, low: 3 };
407
+ actionableItems.sort((a, b) => priorityOrder[a.result.priority] - priorityOrder[b.result.priority]);
408
+ const batch = actionableItems.slice(0, this.settings.maxBatchSize);
409
+ await this.dispatchBatch(batch, ctx);
410
+ } else {
411
+ this.globalConsecutiveNoOps++;
412
+ }
413
+ this.scheduleNextTick();
414
+ }
415
+ /**
416
+ * Calculate next tick interval using damped oscillator model:
417
+ * interval = base * (1 + damping * consecutiveNoOps)
418
+ *
419
+ * With fibonacci-like acceleration:
420
+ * After 0 no-ops: 5min (base)
421
+ * After 1 no-op: 7.5min
422
+ * After 2 no-ops: 10min
423
+ * After 4 no-ops: 15min
424
+ * After 8 no-ops: 25min
425
+ * After 10 no-ops: 30min (max)
426
+ *
427
+ * Resets to base immediately when action is detected.
428
+ */
429
+ calculateInterval() {
430
+ const base = this.settings.baseIntervalMs;
431
+ const max = this.settings.maxIntervalMs;
432
+ const damping = this.settings.dampingFactor;
433
+ const noOps = this.globalConsecutiveNoOps;
434
+ return Math.min(base * (1 + damping * noOps), max);
435
+ }
436
+ scheduleNextTick() {
437
+ if (this.tickTimer) clearTimeout(this.tickTimer);
438
+ const interval = this.calculateInterval();
439
+ this.tickTimer = setTimeout(() => this.tick(), interval);
440
+ this.tickTimer.unref();
441
+ }
442
+ isWithinWorkHours(hour, minute, dayOfWeek) {
443
+ const schedule = this.config.schedule;
444
+ if (!schedule) return true;
445
+ const isWorkday = schedule.days.includes(dayOfWeek);
446
+ const timeStr = `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
447
+ const isWithinHours = timeStr >= schedule.start && timeStr < schedule.end;
448
+ return isWorkday && isWithinHours;
449
+ }
450
+ isQuietHours(hour) {
451
+ const start = this.settings.quietHoursStart;
452
+ const end = this.settings.quietHoursEnd;
453
+ if (start === void 0 || end === void 0) return false;
454
+ if (start > end) {
455
+ return hour >= start || hour < end;
456
+ }
457
+ return hour >= start && hour < end;
458
+ }
459
+ /**
460
+ * Dispatch a batch of actionable items to the agent via one LLM session.
461
+ * This is the ONLY place tokens are spent.
462
+ */
463
+ async dispatchBatch(items, ctx) {
464
+ if (!this.config.runtime) {
465
+ console.warn("[heartbeat] No runtime \u2014 cannot dispatch actions");
466
+ return;
467
+ }
468
+ try {
469
+ const { guardrails } = await import("./routes-K2GAVUXI.js");
470
+ const status = await guardrails.getStatus(ctx.agentId);
471
+ if (status.paused || status.offDuty) {
472
+ console.log(`[heartbeat] Skipping action dispatch \u2014 agent is ${status.offDuty ? "off duty" : "paused"}`);
473
+ return;
474
+ }
475
+ } catch {
476
+ }
477
+ const summaries = items.map(
478
+ (item, i) => `${i + 1}. [${item.result.priority.toUpperCase()}] ${item.check.name}: ${item.result.summary}`
479
+ ).join("\n");
480
+ const prompt = `HEARTBEAT ALERT \u2014 The following ${items.length} item(s) need your attention:
481
+
482
+ ${summaries}
483
+
484
+ For each item, take the appropriate action:
485
+ - For unread emails: Check your inbox with gmail_search and respond to any urgent ones.
486
+ - For upcoming events: Check google_calendar_list for the next 2 hours and prepare.
487
+ - For stale sessions: Review and close any stuck sessions.
488
+ - For unanswered chats: Check Google Chat and respond.
489
+ - For error rate issues: Investigate recent failures and notify your manager if critical.
490
+ - For task deadlines: Review google_tasks_list and prioritize.
491
+ - For memory health: Consider pruning old or low-importance memories.
492
+
493
+ Be efficient \u2014 handle what you can and note what needs human intervention.
494
+ If something needs your manager's attention, email ${ctx.managerEmail || "your manager"}.`;
495
+ const systemPrompt = `You are ${ctx.agentName}, a ${ctx.role}. This is an automated heartbeat check \u2014 items flagged as needing attention. Handle them efficiently. Don't create unnecessary work \u2014 only act on what's genuinely important.`;
496
+ try {
497
+ const session = await this.config.runtime.spawnSession({
498
+ agentId: ctx.agentId,
499
+ message: prompt,
500
+ systemPrompt
501
+ });
502
+ console.log(`[heartbeat] \u2705 Action session ${session.id} dispatched (${items.length} items: ${items.map((i) => i.check.id).join(", ")})`);
503
+ } catch (err) {
504
+ console.error(`[heartbeat] Failed to dispatch action: ${err.message}`);
505
+ }
506
+ }
507
+ };
508
+ export {
509
+ AgentHeartbeatManager
510
+ };
@@ -28,11 +28,11 @@ import {
28
28
  import {
29
29
  createTelegramTools,
30
30
  init_telegram
31
- } from "./chunk-EX6FQSEV.js";
31
+ } from "./chunk-REAJCMQE.js";
32
32
  import {
33
33
  createWhatsAppTools,
34
34
  init_whatsapp
35
- } from "./chunk-4WLIQQ5L.js";
35
+ } from "./chunk-BUKTZ35L.js";
36
36
  import {
37
37
  MemorySearchIndex,
38
38
  init_text_search
@@ -7103,7 +7103,7 @@ function createAgentRoutes(opts) {
7103
7103
  }
7104
7104
  const managedAgent = await lifecycle2.createAgent(orgId, config, actor);
7105
7105
  try {
7106
- const { knowledgeBase: kbEngine } = await import("./routes-NIQHEAV2.js");
7106
+ const { knowledgeBase: kbEngine } = await import("./routes-K2GAVUXI.js");
7107
7107
  const allKbs = kbEngine.getAllKnowledgeBases();
7108
7108
  const clientOrgId = managedAgent?.clientOrgId || config?.clientOrgId || null;
7109
7109
  let kbAssigned = 0;
@@ -8862,7 +8862,7 @@ function createAgentRoutes(opts) {
8862
8862
  try {
8863
8863
  const body = await c.req.json().catch(() => ({}));
8864
8864
  const mode = body.mode || "";
8865
- const { createWhatsAppTools } = await import("./whatsapp-32CNVRFX.js");
8865
+ const { createWhatsAppTools } = await import("./whatsapp-RAQUV6ZL.js");
8866
8866
  const dataDir = process.env.DATA_DIR || "/tmp/agenticmail-data";
8867
8867
  const connId = mode === "business" ? `biz-${agentId}` : agentId;
8868
8868
  const connDir = mode === "business" ? `${dataDir}/agents/${agentId}/whatsapp-business` : `${dataDir}/agents/${agentId}/whatsapp`;
@@ -8879,7 +8879,7 @@ function createAgentRoutes(opts) {
8879
8879
  const agentId = c.req.param("id");
8880
8880
  const mode = c.req.query("mode") || "";
8881
8881
  try {
8882
- const { getConnectionStatus } = await import("./whatsapp-32CNVRFX.js");
8882
+ const { getConnectionStatus } = await import("./whatsapp-RAQUV6ZL.js");
8883
8883
  const connId = mode === "business" ? `biz-${agentId}` : agentId;
8884
8884
  return c.json(getConnectionStatus(connId));
8885
8885
  } catch {
@@ -8892,7 +8892,7 @@ function createAgentRoutes(opts) {
8892
8892
  const body = await c.req.json().catch(() => ({}));
8893
8893
  const mode = body.mode || "";
8894
8894
  const connId = mode === "business" ? `biz-${agentId}` : agentId;
8895
- const { sendTestMessage } = await import("./whatsapp-32CNVRFX.js");
8895
+ const { sendTestMessage } = await import("./whatsapp-RAQUV6ZL.js");
8896
8896
  const result = await sendTestMessage(connId, body.to);
8897
8897
  return c.json(result);
8898
8898
  } catch (err) {
@@ -8903,7 +8903,7 @@ function createAgentRoutes(opts) {
8903
8903
  const agentId = c.req.param("id");
8904
8904
  try {
8905
8905
  const body = await c.req.json();
8906
- const { getConnection } = await import("./whatsapp-32CNVRFX.js");
8906
+ const { getConnection } = await import("./whatsapp-RAQUV6ZL.js");
8907
8907
  const conn = getConnection(agentId);
8908
8908
  if (!conn?.connected) return c.json({ error: "Not connected" }, 503);
8909
8909
  const toJid = (to) => to?.includes("@") ? to : (to || "").replace(/[^0-9]/g, "") + "@s.whatsapp.net";
@@ -8947,7 +8947,7 @@ function createAgentRoutes(opts) {
8947
8947
  try {
8948
8948
  const body = await c.req.json().catch(() => ({}));
8949
8949
  const mode = body.mode || "";
8950
- const { createWhatsAppTools } = await import("./whatsapp-32CNVRFX.js");
8950
+ const { createWhatsAppTools } = await import("./whatsapp-RAQUV6ZL.js");
8951
8951
  const dataDir = process.env.DATA_DIR || "/tmp/agenticmail-data";
8952
8952
  const connId = mode === "business" ? `biz-${agentId}` : agentId;
8953
8953
  const connDir = mode === "business" ? `${dataDir}/agents/${agentId}/whatsapp-business` : `${dataDir}/agents/${agentId}/whatsapp`;
@@ -22917,7 +22917,7 @@ var init_messaging_poller = __esm({
22917
22917
  await this.startWhatsApp(ep);
22918
22918
  }
22919
22919
  try {
22920
- var { autoStartConnections } = await import("./whatsapp-32CNVRFX.js");
22920
+ var { autoStartConnections } = await import("./whatsapp-RAQUV6ZL.js");
22921
22921
  await autoStartConnections(agentEndpoints.map((a) => ({ id: a.id, dataDir: a.dataDir })));
22922
22922
  } catch (err) {
22923
22923
  console.error("[messaging] WhatsApp auto-start failed:", err.message);
@@ -22995,7 +22995,7 @@ var init_messaging_poller = __esm({
22995
22995
  // ─── WhatsApp (event-driven — Baileys WebSocket) ──
22996
22996
  async startWhatsApp(agent) {
22997
22997
  try {
22998
- var { onWhatsAppMessage } = await import("./whatsapp-32CNVRFX.js");
22998
+ var { onWhatsAppMessage } = await import("./whatsapp-RAQUV6ZL.js");
22999
22999
  var unsub = onWhatsAppMessage(agent.id, (msg) => {
23000
23000
  var waMediaFiles;
23001
23001
  if (msg.mediaPath && msg.mediaType) {
@@ -23021,7 +23021,7 @@ var init_messaging_poller = __esm({
23021
23021
  }
23022
23022
  // ─── Telegram (webhook preferred, polling fallback) ─
23023
23023
  async startTelegram(botToken, agent) {
23024
- var { setTelegramWebhook, deleteTelegramWebhook, getTelegramWebhookInfo } = await import("./telegram-QRNGRT5M.js");
23024
+ var { setTelegramWebhook, deleteTelegramWebhook, getTelegramWebhookInfo } = await import("./telegram-NG7PNNIN.js");
23025
23025
  var { randomBytes: randomBytes2 } = await import("crypto");
23026
23026
  var webhookSecret = randomBytes2(32).toString("hex");
23027
23027
  if (this.config.publicUrl && this.config.app) {
@@ -23092,7 +23092,7 @@ var init_messaging_poller = __esm({
23092
23092
  offset = await loadOffset();
23093
23093
  while (running && this.running) {
23094
23094
  try {
23095
- var { pollTelegramUpdates } = await import("./telegram-QRNGRT5M.js");
23095
+ var { pollTelegramUpdates } = await import("./telegram-NG7PNNIN.js");
23096
23096
  var { updates, nextOffset } = await pollTelegramUpdates(botToken, offset, 25);
23097
23097
  if (nextOffset > offset) {
23098
23098
  offset = nextOffset;
@@ -23468,7 +23468,7 @@ ${desc}` : desc;
23468
23468
  var typingJson = await typingResp.json();
23469
23469
  console.log(`[messaging] Telegram typing sent to ${chatId}: ${JSON.stringify(typingJson)}`);
23470
23470
  } else if (ctx.source === "whatsapp") {
23471
- var { getConnection } = await import("./whatsapp-32CNVRFX.js");
23471
+ var { getConnection } = await import("./whatsapp-RAQUV6ZL.js");
23472
23472
  var conn = getConnection(agent.id);
23473
23473
  if (!conn?.connected) return;
23474
23474
  var jid = ctx.senderId.includes("@") ? ctx.senderId : ctx.senderId.replace(/[^0-9]/g, "") + "@s.whatsapp.net";
@@ -23483,7 +23483,7 @@ ${desc}` : desc;
23483
23483
  async sendDirectReply(agent, ctx, text) {
23484
23484
  try {
23485
23485
  if (ctx.source === "whatsapp") {
23486
- var { getConnection } = await import("./whatsapp-32CNVRFX.js");
23486
+ var { getConnection } = await import("./whatsapp-RAQUV6ZL.js");
23487
23487
  var conn = getConnection(agent.id);
23488
23488
  if (!conn?.connected) return;
23489
23489
  var jid = ctx.senderId.includes("@") ? ctx.senderId : ctx.senderId.replace(/[^0-9]/g, "") + "@s.whatsapp.net";
@@ -6,6 +6,10 @@ import {
6
6
  import { join } from "path";
7
7
  import { mkdir, readFile, stat } from "fs/promises";
8
8
  import { EventEmitter } from "events";
9
+ function stripMarkdown(text) {
10
+ if (!text) return text;
11
+ return text.replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/__(.+?)__/g, "$1").replace(/~~(.+?)~~/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/```[\s\S]*?```/g, (m) => m.replace(/```\w*\n?/g, "").trim()).replace(/`([^`]+)`/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").trim();
12
+ }
9
13
  async function hasAuthState(config) {
10
14
  try {
11
15
  var authDir = join(config.dataDir, "auth");
@@ -274,11 +278,12 @@ function createWhatsAppTools(config) {
274
278
  var conn = connections.get(config.agentId);
275
279
  if (conn?.connected) {
276
280
  var jid = toJid(input.to);
281
+ var cleanText = stripMarkdown(input.text);
277
282
  try {
278
283
  await conn?.sock?.sendPresenceUpdate("composing", jid);
279
284
  } catch {
280
285
  }
281
- var r = await conn.sock.sendMessage(jid, { text: input.text });
286
+ var r = await conn.sock.sendMessage(jid, { text: cleanText });
282
287
  try {
283
288
  await conn?.sock?.sendPresenceUpdate("paused", jid);
284
289
  } catch {
@@ -289,7 +294,7 @@ function createWhatsAppTools(config) {
289
294
  }
290
295
  return { ok: true, id: r?.key?.id };
291
296
  }
292
- return proxySend(config.agentId, { to: input.to, text: input.text });
297
+ return proxySend(config.agentId, { to: input.to, text: stripMarkdown(input.text) });
293
298
  }
294
299
  },
295
300
  {