@agenticmail/enterprise 0.5.441 → 0.5.443
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/CHANGELOG.md +34 -0
- package/README.md +3 -2
- package/dist/agent-heartbeat-QJ3WTWUK.js +518 -0
- package/dist/agent-status-CS5NNYIO.js +11 -0
- package/dist/agent-tools-3MD7EPO6.js +14629 -0
- package/dist/agent-tools-62HGQYDL.js +14629 -0
- package/dist/agent-tools-BTUVVOWT.js +14629 -0
- package/dist/agent-tools-BV3JMJPN.js +14629 -0
- package/dist/agent-tools-JVNQ4RPM.js +14629 -0
- package/dist/agent-tools-LD7LELVT.js +14629 -0
- package/dist/agent-tools-NRKQ5NMW.js +14629 -0
- package/dist/agent-tools-OXZJOD4D.js +14629 -0
- package/dist/agent-tools-PT2ES6G5.js +14629 -0
- package/dist/agent-tools-SS335E2E.js +14629 -0
- package/dist/chunk-2ACTQSPC.js +1728 -0
- package/dist/chunk-2XZE5NT3.js +5387 -0
- package/dist/chunk-325NTNE6.js +2180 -0
- package/dist/chunk-3AHKVWCO.js +5387 -0
- package/dist/chunk-3DM6QDVR.js +1728 -0
- package/dist/chunk-3L2N6LR2.js +7517 -0
- package/dist/chunk-3XP7VYIS.js +7437 -0
- package/dist/chunk-3ZD3XOV6.js +1728 -0
- package/dist/chunk-44VXWYPE.js +2570 -0
- package/dist/chunk-4UOSUXFR.js +7529 -0
- package/dist/chunk-54SHHX2S.js +2180 -0
- package/dist/chunk-5DVY3CNK.js +1728 -0
- package/dist/chunk-5F5DGV63.js +5596 -0
- package/dist/chunk-6IUUOWZY.js +7526 -0
- package/dist/chunk-77LFFLQX.js +7526 -0
- package/dist/chunk-7BKNDBSA.js +2191 -0
- package/dist/chunk-7BS2XPLW.js +5359 -0
- package/dist/chunk-7GCSGDXQ.js +1636 -0
- package/dist/chunk-7IAI45PR.js +4735 -0
- package/dist/chunk-7QPZGO27.js +4976 -0
- package/dist/chunk-7S5XAXRD.js +4747 -0
- package/dist/chunk-AD6ZR3QD.js +5357 -0
- package/dist/chunk-AO556OXZ.js +2570 -0
- package/dist/chunk-APUWQHXC.js +7437 -0
- package/dist/chunk-BKSSHV6C.js +1728 -0
- package/dist/chunk-BMUNQHLU.js +1208 -0
- package/dist/chunk-BPF5DKUM.js +392 -0
- package/dist/chunk-CFR5OSMI.js +1220 -0
- package/dist/chunk-CM4GUHXP.js +1728 -0
- package/dist/chunk-CVFIM72Q.js +501 -0
- package/dist/chunk-DFXVJNKW.js +4734 -0
- package/dist/chunk-DJ7LHRL7.js +2214 -0
- package/dist/chunk-DJFI6NR6.js +1624 -0
- package/dist/chunk-DJHYV5VY.js +1624 -0
- package/dist/chunk-DYM4PQO3.js +4727 -0
- package/dist/chunk-DZ75RF35.js +1728 -0
- package/dist/chunk-E5H64U5H.js +472 -0
- package/dist/chunk-EOD4EGFI.js +1728 -0
- package/dist/chunk-EP74QR5B.js +4980 -0
- package/dist/chunk-FE2M4FV5.js +5273 -0
- package/dist/chunk-FQWJMPKW.js +305 -0
- package/dist/chunk-FUH6NWIX.js +7540 -0
- package/dist/chunk-G5ADHHAD.js +1728 -0
- package/dist/chunk-GAYLPSM7.js +7529 -0
- package/dist/chunk-GDAFZJTJ.js +7540 -0
- package/dist/chunk-GLAN2JBA.js +1636 -0
- package/dist/chunk-GNAEBGU7.js +4812 -0
- package/dist/chunk-HDDA2Q3Q.js +1728 -0
- package/dist/chunk-HG62FWWQ.js +7437 -0
- package/dist/chunk-HV5VIS5K.js +1624 -0
- package/dist/chunk-IEVA23WK.js +4976 -0
- package/dist/chunk-IFMZ2IYC.js +7540 -0
- package/dist/chunk-IN7VIORK.js +2641 -0
- package/dist/chunk-KAX3ZDP2.js +7529 -0
- package/dist/chunk-KECO53GP.js +1728 -0
- package/dist/chunk-KGZ74UMA.js +1728 -0
- package/dist/chunk-M2ZLRUMX.js +7540 -0
- package/dist/chunk-MKQWC6KF.js +5374 -0
- package/dist/chunk-MQ3JBGLU.js +1636 -0
- package/dist/chunk-MVB6JARX.js +7529 -0
- package/dist/chunk-N37MOOFE.js +2210 -0
- package/dist/chunk-NELCAZUQ.js +5357 -0
- package/dist/chunk-NHLOKTUV.js +26305 -0
- package/dist/chunk-OPAO5QQS.js +1728 -0
- package/dist/chunk-OUHU3VW6.js +1728 -0
- package/dist/chunk-OWEXZVZ6.js +1728 -0
- package/dist/chunk-P4DHSJJY.js +7437 -0
- package/dist/chunk-Q7QA6MNJ.js +1728 -0
- package/dist/chunk-QKKTNPGV.js +7592 -0
- package/dist/chunk-REMMXZVU.js +7529 -0
- package/dist/chunk-RK3KATD4.js +4756 -0
- package/dist/chunk-RQ33L5T3.js +5374 -0
- package/dist/chunk-RU77F65Q.js +1728 -0
- package/dist/chunk-SAM3CVIU.js +5374 -0
- package/dist/chunk-SFMXIKWZ.js +1728 -0
- package/dist/chunk-SPZ5JBGW.js +1624 -0
- package/dist/chunk-TDOC6WSK.js +7529 -0
- package/dist/chunk-TPMT5WTW.js +5357 -0
- package/dist/chunk-TVXUR3PB.js +2180 -0
- package/dist/chunk-TZEEVEKG.js +5343 -0
- package/dist/chunk-U327O3ZR.js +7540 -0
- package/dist/chunk-ULD6C5DB.js +2180 -0
- package/dist/chunk-ULVRCJZV.js +5374 -0
- package/dist/chunk-UOCDOM2S.js +1624 -0
- package/dist/chunk-VINDZLLX.js +1636 -0
- package/dist/chunk-VODW5GJL.js +2180 -0
- package/dist/chunk-WEWL7Z3C.js +2180 -0
- package/dist/chunk-WG2MEMS6.js +5343 -0
- package/dist/chunk-WYV6QWOJ.js +1188 -0
- package/dist/chunk-X5AIAD77.js +1636 -0
- package/dist/chunk-XUETIRDV.js +2214 -0
- package/dist/chunk-XWSMX7RK.js +7529 -0
- package/dist/chunk-YUSYXHKB.js +1728 -0
- package/dist/chunk-ZC2RMHQD.js +5374 -0
- package/dist/chunk-ZDZQQGFG.js +5374 -0
- package/dist/chunk-ZJ2HCWKF.js +1728 -0
- package/dist/chunk-ZK4QCOJ5.js +5273 -0
- package/dist/chunk-ZMKVEJKR.js +392 -0
- package/dist/cli-agent-2UFGFO24.js +2761 -0
- package/dist/cli-agent-5FPUCFPG.js +2761 -0
- package/dist/cli-agent-7AB6NIYQ.js +2761 -0
- package/dist/cli-agent-7CAFSYOM.js +2761 -0
- package/dist/cli-agent-7OVOINHR.js +2757 -0
- package/dist/cli-agent-AWKBFIRS.js +2761 -0
- package/dist/cli-agent-ES3XOPHJ.js +2757 -0
- package/dist/cli-agent-FSO2N7I6.js +2757 -0
- package/dist/cli-agent-KPXZN5JK.js +2761 -0
- package/dist/cli-agent-LGTCFHGS.js +2757 -0
- package/dist/cli-agent-LLUYUHHF.js +2757 -0
- package/dist/cli-agent-NHZWYX5Q.js +2761 -0
- package/dist/cli-agent-TYUOTYCO.js +2757 -0
- package/dist/cli-agent-VQO6HI65.js +2757 -0
- package/dist/cli-agent-VV5JWRU7.js +2757 -0
- package/dist/cli-agent-Z5B23XED.js +2757 -0
- package/dist/cli-serve-2FLQXJW7.js +322 -0
- package/dist/cli-serve-34YFCCUX.js +322 -0
- package/dist/cli-serve-3NS6MNUS.js +322 -0
- package/dist/cli-serve-4PWFEPNA.js +322 -0
- package/dist/cli-serve-4VIBMXMT.js +322 -0
- package/dist/cli-serve-5ZUF5MGH.js +322 -0
- package/dist/cli-serve-6HGL56GB.js +322 -0
- package/dist/cli-serve-BBBWEKKW.js +322 -0
- package/dist/cli-serve-D2HQC4SB.js +322 -0
- package/dist/cli-serve-IKCMNUNM.js +322 -0
- package/dist/cli-serve-LTUKYMEF.js +322 -0
- package/dist/cli-serve-MIWI5PBE.js +322 -0
- package/dist/cli-serve-R6K4SZ3L.js +322 -0
- package/dist/cli-serve-RQIOBQGF.js +322 -0
- package/dist/cli-serve-S57ROYQ6.js +322 -0
- package/dist/cli-serve-WVSLOISY.js +322 -0
- package/dist/cli-serve-XDFSJIQV.js +322 -0
- package/dist/cli-serve-YKZSNR3P.js +322 -0
- package/dist/cli-serve-ZGKXWDMZ.js +322 -0
- package/dist/cli-serve-ZZOJWREY.js +322 -0
- package/dist/cli.js +3 -3
- package/dist/dashboard/components/utils.js +1 -1
- package/dist/dashboard/docs/polymarket.html +1 -1
- package/dist/dashboard/pages/polymarket.js +222 -80
- package/dist/index.js +12 -12
- package/dist/pipeline-C4C3ZF4X.js +15 -0
- package/dist/pipeline-DAF3EV7Q.js +15 -0
- package/dist/pipeline-MMESLRQG.js +15 -0
- package/dist/polymarket-3LGJSQZK.js +17 -0
- package/dist/polymarket-4OIWQFBO.js +17 -0
- package/dist/polymarket-AZEV7C6E.js +17 -0
- package/dist/polymarket-DBQYJC57.js +7 -0
- package/dist/polymarket-EVTKWLUO.js +7 -0
- package/dist/polymarket-GMKDVVQH.js +17 -0
- package/dist/polymarket-HZOAD4W4.js +17 -0
- package/dist/polymarket-PKGRF7ID.js +17 -0
- package/dist/polymarket-QUNR2H7U.js +17 -0
- package/dist/polymarket-TM624BN5.js +17 -0
- package/dist/polymarket-VT2EDGD7.js +17 -0
- package/dist/polymarket-W7B4TLP3.js +17 -0
- package/dist/polymarket-WS4VE6U7.js +7 -0
- package/dist/polymarket-runtime-772ADZJW.js +108 -0
- package/dist/polymarket-runtime-AIYHQKYQ.js +108 -0
- package/dist/polymarket-runtime-APJ5HW4Y.js +108 -0
- package/dist/polymarket-runtime-BX3ODZZD.js +108 -0
- package/dist/polymarket-runtime-ISD4CKKL.js +108 -0
- package/dist/polymarket-runtime-JU4PQZGJ.js +108 -0
- package/dist/polymarket-runtime-OFLBSPCK.js +108 -0
- package/dist/polymarket-runtime-POJRRWFS.js +108 -0
- package/dist/polymarket-runtime-XN5TVHU5.js +108 -0
- package/dist/polymarket-runtime-ZYFTKEJ4.js +108 -0
- package/dist/polymarket-watcher-2CKLTIXI.js +23 -0
- package/dist/polymarket-watcher-3C72X36B.js +23 -0
- package/dist/polymarket-watcher-IHRZ2URM.js +23 -0
- package/dist/polymarket-watcher-J7UWIN7I.js +23 -0
- package/dist/polymarket-watcher-M6CDW63Y.js +23 -0
- package/dist/polymarket-watcher-OSI73EDX.js +23 -0
- package/dist/polymarket-watcher-PN4JJV3V.js +23 -0
- package/dist/polymarket-watcher-PXK4NS5F.js +23 -0
- package/dist/polymarket-watcher-VDJ4SVHP.js +23 -0
- package/dist/polymarket-watcher-W4BV6JTG.js +23 -0
- package/dist/routes-PRBWZ4MQ.js +94 -0
- package/dist/runtime-22E2WCL6.js +46 -0
- package/dist/runtime-7GYS4FQU.js +46 -0
- package/dist/runtime-7OVDHKNW.js +46 -0
- package/dist/runtime-BR6K3Q3N.js +46 -0
- package/dist/runtime-CTTRDVJ6.js +46 -0
- package/dist/runtime-GIIPTHK5.js +46 -0
- package/dist/runtime-HYAKLZWI.js +46 -0
- package/dist/runtime-IQ2KIV2L.js +50 -0
- package/dist/runtime-ISXECIAB.js +46 -0
- package/dist/runtime-IV4BY7S4.js +46 -0
- package/dist/runtime-O65GGHL2.js +46 -0
- package/dist/runtime-PKHEGQYK.js +50 -0
- package/dist/runtime-RFKPIFK4.js +46 -0
- package/dist/runtime-S35B6PIY.js +46 -0
- package/dist/runtime-WEZJ4YRK.js +46 -0
- package/dist/runtime-WLWB62ZI.js +46 -0
- package/dist/screener-FB47G4YX.js +26 -0
- package/dist/screener-WQVQO4WF.js +26 -0
- package/dist/server-6GWGIGBH.js +36 -0
- package/dist/server-7VZ6XXBC.js +36 -0
- package/dist/server-7XBTD3FW.js +36 -0
- package/dist/server-BN56IMC4.js +36 -0
- package/dist/server-GD6SPDER.js +36 -0
- package/dist/server-IJHU2FIK.js +36 -0
- package/dist/server-J5WZGZX3.js +36 -0
- package/dist/server-JVUH2E3H.js +36 -0
- package/dist/server-MYXWTXSE.js +36 -0
- package/dist/server-ORGV7O7L.js +36 -0
- package/dist/server-QPE3WVUQ.js +36 -0
- package/dist/server-SUBGS5BJ.js +36 -0
- package/dist/server-SWAYJTFF.js +36 -0
- package/dist/server-TFIWDU2H.js +36 -0
- package/dist/server-VH4W6LWW.js +36 -0
- package/dist/server-WQXRTEKF.js +36 -0
- package/dist/server-X5UMJJ3J.js +36 -0
- package/dist/server-XOK5LHNU.js +36 -0
- package/dist/server-ZLK24KFY.js +36 -0
- package/dist/server-ZNSQGCRM.js +36 -0
- package/dist/setup-32ZRMW7R.js +20 -0
- package/dist/setup-3WF7PBIS.js +20 -0
- package/dist/setup-4TM64QG4.js +20 -0
- package/dist/setup-5SGUMKN7.js +20 -0
- package/dist/setup-7ENTPINX.js +20 -0
- package/dist/setup-AGYKOCIU.js +20 -0
- package/dist/setup-EIP4IHZN.js +20 -0
- package/dist/setup-F5SAGQJJ.js +20 -0
- package/dist/setup-LMF76UUM.js +20 -0
- package/dist/setup-MA5QR3J4.js +20 -0
- package/dist/setup-MLIPR2U3.js +20 -0
- package/dist/setup-MLIZYTT6.js +20 -0
- package/dist/setup-OPVZ3GM7.js +20 -0
- package/dist/setup-PWFHUXOK.js +20 -0
- package/dist/setup-QF5GCTPE.js +20 -0
- package/dist/setup-SGF4OX3A.js +20 -0
- package/dist/setup-TLWKGWC6.js +20 -0
- package/dist/setup-TYCRH63P.js +20 -0
- package/dist/setup-USUBKTVX.js +20 -0
- package/dist/setup-VMNTNEB4.js +20 -0
- package/dist/shared-S5ROHYCX.js +69 -0
- package/dist/shared-TLWZZZSK.js +69 -0
- package/dist/system-prompts-7ZRL27FN.js +69 -0
- package/dist/system-prompts-CNXUF2AV.js +69 -0
- package/dist/system-prompts-SYGQRBRG.js +69 -0
- package/logs/cloudflared-error.log +4 -57
- package/logs/cloudflared-error__2026-03-11_00-00-00.log +289 -0
- package/package.json +1 -1
- package/logs/cloudflared-error__2026-03-06_00-00-00.log +0 -245
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to AgenticMail Enterprise are documented here.
|
|
4
4
|
|
|
5
|
+
## [0.5.443] - 2026-03-11
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Trading Optimizer Suite** — 6 new high-frequency trading tools (`polymarket-optimizer` skill):
|
|
9
|
+
- `poly_daily_scorecard` — Real-time P&L vs daily target, win rate, capital utilization, trading status (AHEAD/ON_TRACK/BEHIND/TARGET_HIT/STOP_TRADING)
|
|
10
|
+
- `poly_momentum_scanner` — Find markets with significant price movement in real-time; replaces static search for discovering active opportunities
|
|
11
|
+
- `poly_quick_edge` — One-call GO/NO-GO trade decision with edge %, Kelly size, and action (STRONG_BUY/BUY/MARGINAL/NO_TRADE/SELL); replaces 6+ separate tool calls
|
|
12
|
+
- `poly_position_heatmap` — All positions ranked by urgency (CRITICAL/HIGH/MEDIUM/LOW) with specific action needed for each
|
|
13
|
+
- `poly_profit_lock` — Auto-conservative mode after hitting daily target; returns adjusted position sizes and trading mode
|
|
14
|
+
- `poly_capital_recycler` — Redeploy freed capital to best opportunities after position closes; keeps capital working
|
|
15
|
+
- **Daily Scorecard Dashboard** — New section in Polymarket Overview tab showing real-time daily P&L progress bar, target tracking, realized/unrealized P&L, trade count, win rate, and available capital
|
|
16
|
+
- **Daily Scorecard API** — `GET /polymarket/:agentId/daily-scorecard` endpoint returning comprehensive daily trading metrics
|
|
17
|
+
- **Browser Market Discovery** — Agents can browse polymarket.com to find market IDs when API returns stale results (system prompt guidance, no login required)
|
|
18
|
+
- **Universal Message Trimmer** — Extracted stale aging + inline truncation into standalone `message-trimmer.ts` module; applies to ALL tools (web, browser, email, polymarket) not just polymarket
|
|
19
|
+
- **Market Freshness Tracking** — Per-agent tracking of recently-analyzed markets with 30-min TTL; prevents agents from repeatedly analyzing the same stale markets
|
|
20
|
+
- **Dead Market Filtering** — Markets with all-zero prices, zero liquidity, or resolved status are automatically filtered from search/screen results
|
|
21
|
+
- **CLOB Rate Limit Resilience** — Gamma API fallbacks for orderbook depth, whale tracking, flow analysis, and price discovery when CLOB API is rate-limited
|
|
22
|
+
- **Cross-DB Date Helpers** — `dateAgo()`, `dateAgoMin()`, `dateAhead()` for watcher SQL queries; replaces PostgreSQL-specific `::timestamptz`/`INTERVAL` syntax
|
|
23
|
+
- **Comprehensive Topic Extraction** — `extractTopics()` expanded from 6 patterns to 25+ groups covering US/global politics, crypto, sports, AI, regulation, and more
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- **PostgreSQL-only SQL in watcher** — Fixed 15+ queries using `::timestamptz`, `NOW()`, `INTERVAL` that failed on SQLite; all now use parameterized ISO date strings
|
|
27
|
+
- **PostgreSQL DDL in portfolio** — Fixed `SERIAL PRIMARY KEY` → `INTEGER PRIMARY KEY AUTOINCREMENT` and `TIMESTAMPTZ` → `TEXT`
|
|
28
|
+
- **Dead CLOB endpoints** — Replaced 3 dead `CLOB_API/markets/` calls with working `GAMMA_API/markets?clob_token_ids=` in watcher
|
|
29
|
+
- **`poly_approve_trade`** — Fixed trade fetching AFTER resolution (trade disappeared); now fetches BEFORE resolving
|
|
30
|
+
- **`poly_place_batch_orders`** — Fixed tool that validated but never executed orders; now creates pending trades and executes in autonomous mode
|
|
31
|
+
- **`poly_resolution_risk` "Market not found"** — Auto-detects 0x condition IDs passed as slug parameter; added Gamma search fallback
|
|
32
|
+
- **`poly_quick_analysis` null values** — Added fallback data when CLOB is rate-limited instead of returning null for orderbook/regime/kelly
|
|
33
|
+
- **`poly_get_open_orders` / `poly_get_order`** — Fixed to check database as fallback, not just in-memory Map
|
|
34
|
+
- **`poly_leaderboard` / `poly_top_holders`** — Fixed dead Gamma endpoints; now uses data-api fallback
|
|
35
|
+
- **Proactive wake channel routing** — Uses manager's configured communication channel (telegram/whatsapp/email) instead of hardcoded values
|
|
36
|
+
- **Hardcoded identity in proactive wake** — Replaced hardcoded `senderName: 'Ope'` with dynamic manager info
|
|
37
|
+
- **Unused code cleanup** — Removed `_TradingConfig`, `PriceAlert`, `PaperPosition` interfaces, `priceAlerts`/`paperPositions`/`autoApproveRules` Maps, `getConfig()`/`checkAutoApprove()` functions, `_pricingCache` from agent-loop
|
|
38
|
+
|
|
5
39
|
## [0.5.320] - 2026-03-05
|
|
6
40
|
|
|
7
41
|
### Added
|
package/README.md
CHANGED
|
@@ -575,11 +575,12 @@ Gmail · Calendar · Drive · Docs · Sheets · Slides · Forms · Meet · Chat
|
|
|
575
575
|
### Microsoft 365 Suite (13 services, 90+ tools)
|
|
576
576
|
Outlook Mail (20 tools) · Outlook Calendar (7) · Teams (15) · OneDrive (12) · Excel (16) · SharePoint (10) · OneNote (6) · Planner (6) · To Do (6) · PowerPoint (5) · Power BI (8) · Contacts (5) · Each with dedicated system prompts and Graph API integration with retry, rate-limit handling, pagination, and batch support.
|
|
577
577
|
|
|
578
|
-
### Polymarket Trading Suite (
|
|
578
|
+
### Polymarket Trading Suite (10 skills, 114+ tools)
|
|
579
579
|
Institutional-grade prediction market trading on [Polymarket](https://polymarket.com):
|
|
580
580
|
- **polymarket** (63 tools) — Trading infrastructure, orders, wallet, risk controls, learning system
|
|
581
581
|
- **polymarket-quant** (14) — Kelly criterion, Black-Scholes, Bayesian, Monte Carlo, RSI/MACD/Bollinger, VaR
|
|
582
582
|
- **polymarket-onchain** (6) — Whale tracking, orderbook depth, on-chain flow, wallet profiling, liquidity mapping
|
|
583
|
+
- **polymarket-optimizer** (6) — Daily scorecard, momentum scanner, quick edge, position heatmap, profit lock, capital recycler
|
|
583
584
|
- **polymarket-social** (5) — Twitter/Reddit/Telegram sentiment, Polymarket comments, social velocity
|
|
584
585
|
- **polymarket-feeds** (5) — Event calendar, official sources (SCOTUS/SEC/Fed/ESPN), odds aggregation, breaking news
|
|
585
586
|
- **polymarket-analytics** (5) — Market correlation, arbitrage scanning, regime detection, smart money index
|
|
@@ -587,7 +588,7 @@ Institutional-grade prediction market trading on [Polymarket](https://polymarket
|
|
|
587
588
|
- **polymarket-counterintel** (3) — Manipulation detection, resolution risk scoring, counterparty analysis
|
|
588
589
|
- **polymarket-portfolio** (3) — Portfolio optimization, drawdown monitoring, P&L attribution
|
|
589
590
|
|
|
590
|
-
Full dashboard with
|
|
591
|
+
Full dashboard with daily scorecard, 22 tabs, dedicated system prompt, auto-SDK install, 25+ DB tables, SSE real-time updates.
|
|
591
592
|
|
|
592
593
|
### Enterprise Custom Suite (16+)
|
|
593
594
|
Calendar · Code Sandbox · Database · Diff · Documents · Finance · HTTP · Knowledge Search · Logs · Notifications · Security Scan · Spreadsheet · Translation · Vision · Web Research · Workflow
|
|
@@ -0,0 +1,518 @@
|
|
|
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-PRBWZ4MQ.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
|
+
try {
|
|
478
|
+
const activeCount = this.config.runtime.getActiveSessionCount?.() ?? 0;
|
|
479
|
+
if (activeCount > 0) {
|
|
480
|
+
console.log(`[heartbeat] Deferring action dispatch \u2014 ${activeCount} active session(s) running`);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
} catch {
|
|
484
|
+
}
|
|
485
|
+
const summaries = items.map(
|
|
486
|
+
(item, i) => `${i + 1}. [${item.result.priority.toUpperCase()}] ${item.check.name}: ${item.result.summary}`
|
|
487
|
+
).join("\n");
|
|
488
|
+
const prompt = `HEARTBEAT ALERT \u2014 The following ${items.length} item(s) need your attention:
|
|
489
|
+
|
|
490
|
+
${summaries}
|
|
491
|
+
|
|
492
|
+
For each item, take the appropriate action:
|
|
493
|
+
- For unread emails: Check your inbox with gmail_search and respond to any urgent ones.
|
|
494
|
+
- For upcoming events: Check google_calendar_list for the next 2 hours and prepare.
|
|
495
|
+
- For stale sessions: Review and close any stuck sessions.
|
|
496
|
+
- For unanswered chats: Check Google Chat and respond.
|
|
497
|
+
- For error rate issues: Investigate recent failures and notify your manager if critical.
|
|
498
|
+
- For task deadlines: Review google_tasks_list and prioritize.
|
|
499
|
+
- For memory health: Consider pruning old or low-importance memories.
|
|
500
|
+
|
|
501
|
+
Be efficient \u2014 handle what you can and note what needs human intervention.
|
|
502
|
+
If something needs your manager's attention, email ${ctx.managerEmail || "your manager"}.`;
|
|
503
|
+
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.`;
|
|
504
|
+
try {
|
|
505
|
+
const session = await this.config.runtime.spawnSession({
|
|
506
|
+
agentId: ctx.agentId,
|
|
507
|
+
message: prompt,
|
|
508
|
+
systemPrompt
|
|
509
|
+
});
|
|
510
|
+
console.log(`[heartbeat] \u2705 Action session ${session.id} dispatched (${items.length} items: ${items.map((i) => i.check.id).join(", ")})`);
|
|
511
|
+
} catch (err) {
|
|
512
|
+
console.error(`[heartbeat] Failed to dispatch action: ${err.message}`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
export {
|
|
517
|
+
AgentHeartbeatManager
|
|
518
|
+
};
|