opensentinel 3.1.1 → 3.7.0

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.
Files changed (361) hide show
  1. package/README.md +138 -83
  2. package/dist/agent-manager-JZ4IM7XI.js +39 -0
  3. package/dist/agent-processor-DDDHC2SO.js +281 -0
  4. package/dist/agent-processor-DDDHC2SO.js.map +1 -0
  5. package/dist/agent-types-2T4PXLFQ.js +12 -0
  6. package/dist/alerting-LK7VVYTX.js +699 -0
  7. package/dist/alerting-LK7VVYTX.js.map +1 -0
  8. package/dist/analysis-agent-JWN2GXYE.js +288 -0
  9. package/dist/analysis-agent-JWN2GXYE.js.map +1 -0
  10. package/dist/analyzer-OTWE3ARE.js +22 -0
  11. package/dist/{archiver-AVNBYCKQ.js → archiver-FPGKRP6P.js} +2 -2
  12. package/dist/{audit-logger-OBPR7CRO.js → audit-logger-CI4WZQPD.js} +6 -5
  13. package/dist/{auth-UOX5K2BE.js → auth-PH5IHISW.js} +2 -2
  14. package/dist/{autonomy-ZXDBDQUJ.js → autonomy-N7W5XPLX.js} +4 -3
  15. package/dist/autonomy-N7W5XPLX.js.map +1 -0
  16. package/dist/{aws-s3-Q4LLZZPD.js → aws-s3-QZMURYXB.js} +2 -2
  17. package/dist/{backup-restore-PZ7CYYB7.js → backup-restore-72OQTZO3.js} +2 -2
  18. package/dist/{blocks-R3PODY47.js → blocks-YOWOESDD.js} +4 -4
  19. package/dist/bot-VDHBGUVI.js +47 -0
  20. package/dist/brain-6QTXN4QP.js +66 -0
  21. package/dist/{camera-monitor-M5CYKUU4.js → camera-monitor-LHTUWHEL.js} +2 -2
  22. package/dist/{charts-V7ARZNKF.js → charts-FJ32GQK7.js} +2 -2
  23. package/dist/{chunk-WRAKK6K6.js → chunk-2I5QHYG6.js} +5 -3
  24. package/dist/chunk-2I5QHYG6.js.map +1 -0
  25. package/dist/{chunk-TVEWKIK3.js → chunk-2WTKTG2C.js} +2 -2
  26. package/dist/chunk-3AWAWRWB.js +143 -0
  27. package/dist/chunk-3AWAWRWB.js.map +1 -0
  28. package/dist/{chunk-ZLZKF2PM.js → chunk-4KIHDIXZ.js} +43 -2
  29. package/dist/chunk-4KIHDIXZ.js.map +1 -0
  30. package/dist/{chunk-EVE7MIIY.js → chunk-4WH6MFEW.js} +15 -16
  31. package/dist/chunk-4WH6MFEW.js.map +1 -0
  32. package/dist/{chunk-I6BDYQIG.js → chunk-56UJS2LA.js} +6 -6
  33. package/dist/chunk-56UJS2LA.js.map +1 -0
  34. package/dist/chunk-5BTVJR7R.js +37 -0
  35. package/dist/chunk-5BTVJR7R.js.map +1 -0
  36. package/dist/chunk-5JJTLWOR.js +1021 -0
  37. package/dist/chunk-5JJTLWOR.js.map +1 -0
  38. package/dist/chunk-66SAOZPU.js +236 -0
  39. package/dist/chunk-66SAOZPU.js.map +1 -0
  40. package/dist/chunk-6HGMRR4J.js +113 -0
  41. package/dist/chunk-6HGMRR4J.js.map +1 -0
  42. package/dist/chunk-6W6PTJFT.js +181 -0
  43. package/dist/chunk-6W6PTJFT.js.map +1 -0
  44. package/dist/chunk-6ZNCY2GI.js +418 -0
  45. package/dist/chunk-6ZNCY2GI.js.map +1 -0
  46. package/dist/chunk-7BNFELEK.js +31 -0
  47. package/dist/chunk-7BNFELEK.js.map +1 -0
  48. package/dist/chunk-ADTDYJO7.js +265 -0
  49. package/dist/chunk-ADTDYJO7.js.map +1 -0
  50. package/dist/{chunk-OCVQGBJK.js → chunk-BBN4VCNK.js} +6 -4
  51. package/dist/chunk-BBN4VCNK.js.map +1 -0
  52. package/dist/{chunk-SJSUSJ47.js → chunk-BNZHWAZC.js} +2 -2
  53. package/dist/chunk-C6PELIHS.js +60 -0
  54. package/dist/chunk-C6PELIHS.js.map +1 -0
  55. package/dist/{chunk-MQJ2ECQT.js → chunk-CUPEENUY.js} +3 -3
  56. package/dist/{chunk-NHMBTUMW.js → chunk-CWT6CAE5.js} +2 -2
  57. package/dist/{chunk-4GLYY4NN.js → chunk-CZTMGHUC.js} +8 -2
  58. package/dist/chunk-CZTMGHUC.js.map +1 -0
  59. package/dist/{chunk-RZ4YESBG.js → chunk-DOYGMNMK.js} +1 -1
  60. package/dist/chunk-DOYGMNMK.js.map +1 -0
  61. package/dist/chunk-DTISLIMB.js +89 -0
  62. package/dist/chunk-DTISLIMB.js.map +1 -0
  63. package/dist/{chunk-SPPMCAKG.js → chunk-GBVJTRXS.js} +2 -2
  64. package/dist/chunk-GBVJTRXS.js.map +1 -0
  65. package/dist/{chunk-AYUKPTSM.js → chunk-GJETKBOY.js} +96 -218
  66. package/dist/chunk-GJETKBOY.js.map +1 -0
  67. package/dist/{chunk-BXZ6EA52.js → chunk-GW6V4D43.js} +57 -3
  68. package/dist/chunk-GW6V4D43.js.map +1 -0
  69. package/dist/{chunk-6PMVAAA7.js → chunk-HJSEEFO3.js} +3 -3
  70. package/dist/{chunk-TYAGMJNV.js → chunk-HQZQFEAX.js} +5 -5
  71. package/dist/{chunk-MXAPLSJ5.js → chunk-J4JW73TT.js} +2 -2
  72. package/dist/{chunk-VEHFVBLI.js → chunk-JHYYFPKX.js} +2 -2
  73. package/dist/chunk-LFDXEYYB.js +150 -0
  74. package/dist/chunk-LFDXEYYB.js.map +1 -0
  75. package/dist/chunk-MIC5IBQF.js +386 -0
  76. package/dist/chunk-MIC5IBQF.js.map +1 -0
  77. package/dist/chunk-ODCFS5WD.js +463 -0
  78. package/dist/chunk-ODCFS5WD.js.map +1 -0
  79. package/dist/{chunk-XMCVRVTF.js → chunk-P64EV4YY.js} +1 -1
  80. package/dist/chunk-P64EV4YY.js.map +1 -0
  81. package/dist/chunk-PBOCSGNL.js +84 -0
  82. package/dist/chunk-PBOCSGNL.js.map +1 -0
  83. package/dist/{chunk-66OJ3WB4.js → chunk-PD3CTDO6.js} +2 -2
  84. package/dist/chunk-QPY3WRVM.js +647 -0
  85. package/dist/chunk-QPY3WRVM.js.map +1 -0
  86. package/dist/chunk-S2EOIVF4.js +3907 -0
  87. package/dist/chunk-S2EOIVF4.js.map +1 -0
  88. package/dist/chunk-SDLOMKCW.js +213 -0
  89. package/dist/chunk-SDLOMKCW.js.map +1 -0
  90. package/dist/chunk-TKBVW7ZJ.js +162 -0
  91. package/dist/chunk-TKBVW7ZJ.js.map +1 -0
  92. package/dist/{chunk-BRBWNV65.js → chunk-U2X2J3FI.js} +3 -3
  93. package/dist/chunk-U2X2J3FI.js.map +1 -0
  94. package/dist/{chunk-PLDDJCW6.js → chunk-UP2VWCW5.js} +1 -12
  95. package/dist/{chunk-SVAPX2XN.js → chunk-V3OKHQUX.js} +9 -7
  96. package/dist/{chunk-SVAPX2XN.js.map → chunk-V3OKHQUX.js.map} +1 -1
  97. package/dist/{chunk-4UOE5TUZ.js → chunk-WMDVOWN6.js} +4 -4
  98. package/dist/chunk-WMFYI7XC.js +564 -0
  99. package/dist/chunk-WMFYI7XC.js.map +1 -0
  100. package/dist/chunk-WZAH34TG.js +129 -0
  101. package/dist/chunk-WZAH34TG.js.map +1 -0
  102. package/dist/{chunk-H5RQOFO2.js → chunk-X6Q3K3L2.js} +6 -6
  103. package/dist/chunk-X6Q3K3L2.js.map +1 -0
  104. package/dist/chunk-XTX7EK43.js +134 -0
  105. package/dist/chunk-XTX7EK43.js.map +1 -0
  106. package/dist/chunk-YEDEAX6Y.js +194 -0
  107. package/dist/chunk-YEDEAX6Y.js.map +1 -0
  108. package/dist/{chunk-XKYRH4FM.js → chunk-ZIBRVA3Y.js} +70 -30
  109. package/dist/chunk-ZIBRVA3Y.js.map +1 -0
  110. package/dist/chunk-ZIYTHUM5.js +457 -0
  111. package/dist/chunk-ZIYTHUM5.js.map +1 -0
  112. package/dist/{chunk-766ASQWE.js → chunk-ZMML6T63.js} +2711 -2329
  113. package/dist/chunk-ZMML6T63.js.map +1 -0
  114. package/dist/chunk-ZVHG4KF2.js +380 -0
  115. package/dist/chunk-ZVHG4KF2.js.map +1 -0
  116. package/dist/chunker-K6WTR62A.js +12 -0
  117. package/dist/cli.js +1 -1
  118. package/dist/cli.js.map +1 -1
  119. package/dist/{client-ZQSFPMOB.js → client-FOIYPOZQ.js} +5 -6
  120. package/dist/{clipboard-manager-TEO2GEDN.js → clipboard-manager-4SBNESGZ.js} +2 -2
  121. package/dist/coding-agent-DESSU3AC.js +233 -0
  122. package/dist/coding-agent-DESSU3AC.js.map +1 -0
  123. package/dist/commands/setup.js +2 -2
  124. package/dist/commands/start.js +3 -3
  125. package/dist/commands/status.js +2 -2
  126. package/dist/commands/stop.js +2 -2
  127. package/dist/commands/utils.js +2 -2
  128. package/dist/cost-tracker-KZQSTSE2.js +11 -0
  129. package/dist/{cron-explain-HHQKPD3M.js → cron-explain-UOOOYWZZ.js} +2 -2
  130. package/dist/{crypto-4AP47IKC.js → crypto-2VG3RJR2.js} +2 -2
  131. package/dist/{databases-37X4CI2Y.js → databases-XDPMG5AV.js} +4 -4
  132. package/dist/db-I7MNG6CL.js +83 -0
  133. package/dist/discord-6UQHCN27.js +81 -0
  134. package/dist/documents-PFHSK7SZ.js +184 -0
  135. package/dist/documents-PFHSK7SZ.js.map +1 -0
  136. package/dist/docx-parser-EXL4TN5E.js +16 -0
  137. package/dist/{email-K7LO2IPB.js → email-6OIN4SYL.js} +34 -25
  138. package/dist/email-6OIN4SYL.js.map +1 -0
  139. package/dist/{enhanced-retrieval-DNLLEM4Z.js → enhanced-retrieval-JWX2HWU4.js} +12 -8
  140. package/dist/{enhanced-retrieval-DNLLEM4Z.js.map → enhanced-retrieval-JWX2HWU4.js.map} +1 -1
  141. package/dist/enrichment-pipeline-7FE5R5ZI.js +14 -0
  142. package/dist/{entity-resolution-Y3IUWEAT.js → entity-resolution-7Z6STVXX.js} +6 -5
  143. package/dist/env-GN5VHI43.js +12 -0
  144. package/dist/error-tracker-64DEH3D7.js +32 -0
  145. package/dist/finnhub-X7ZMQSXF.js +178 -0
  146. package/dist/finnhub-X7ZMQSXF.js.map +1 -0
  147. package/dist/fred-TMUF3J2V.js +203 -0
  148. package/dist/fred-TMUF3J2V.js.map +1 -0
  149. package/dist/github-DUWSXCNP.js +833 -0
  150. package/dist/github-DUWSXCNP.js.map +1 -0
  151. package/dist/{google-workspace-DKWUVNGC.js → google-workspace-TSZPZK5G.js} +2 -2
  152. package/dist/graph-client-NB475AK5.js +17 -0
  153. package/dist/{hash-tool-ULQYD7B5.js → hash-tool-ENAB5LWH.js} +2 -2
  154. package/dist/{heartbeat-monitor-GCISLXI3.js → heartbeat-monitor-KRDYTDBF.js} +2 -2
  155. package/dist/hooks-N4MIFBVM.js +14 -0
  156. package/dist/{image-generation-OSU7FP6F.js → image-generation-MDE6AVQO.js} +2 -2
  157. package/dist/imessage-DSGSGUZS.js +44 -0
  158. package/dist/inbox-summarizer-F2KAU72V.js +56 -0
  159. package/dist/{incident-response-C5J7Q6DT.js → incident-response-E3UGMX5G.js} +8 -6
  160. package/dist/incident-response-E3UGMX5G.js.map +1 -0
  161. package/dist/{inventory-manager-352OHXWD.js → inventory-manager-C67BSZM6.js} +2 -2
  162. package/dist/{jira-GSGDBMIG.js → jira-PAGZWUBJ.js} +2 -2
  163. package/dist/{json-tool-QE2SYHEG.js → json-tool-4FK5RNER.js} +2 -2
  164. package/dist/{key-rotation-DPHU4ZTB.js → key-rotation-WCC5FOYS.js} +2 -2
  165. package/dist/knowledge-base-5SMMOGQJ.js +46 -0
  166. package/dist/lib.d.ts +94 -1
  167. package/dist/lib.js +83 -66
  168. package/dist/lib.js.map +1 -1
  169. package/dist/{mailchimp-KKNF6QJ7.js → mailchimp-ZFYDC44J.js} +2 -2
  170. package/dist/{matrix-QVHG76I7.js → matrix-WYGEOZL5.js} +30 -21
  171. package/dist/{matrix-QVHG76I7.js.map → matrix-WYGEOZL5.js.map} +1 -1
  172. package/dist/{mcp-3JI6W7ZE.js → mcp-DJ2QDA6A.js} +3 -3
  173. package/dist/metrics-BH3ZLGEV.js +25 -0
  174. package/dist/{microsoft365-UCBKJHNX.js → microsoft365-6G2IJMWC.js} +2 -2
  175. package/dist/multi-user-XAEMB244.js +411 -0
  176. package/dist/multi-user-XAEMB244.js.map +1 -0
  177. package/dist/oauth-UPJYFOVU.js +34 -0
  178. package/dist/{ocr-AC7NPX33.js → ocr-UONKTQU7.js} +6 -4
  179. package/dist/{ollama-BOAMSPLJ.js → ollama-J7CU45WT.js} +2 -2
  180. package/dist/osint-agent-RL5XPBRQ.js +189 -0
  181. package/dist/osint-agent-RL5XPBRQ.js.map +1 -0
  182. package/dist/{pages-MI523RB7.js → pages-XDE7JRCA.js} +5 -5
  183. package/dist/{pair-JDFTERIK.js → pair-YZJFQUU5.js} +2 -2
  184. package/dist/{pairing-IFQYCPNS.js → pairing-77N47RAT.js} +2 -2
  185. package/dist/{pdf-ALQVOEJR.js → pdf-67HGXCFJ.js} +3 -3
  186. package/dist/pdf-parser-YLMTTYHL.js +14 -0
  187. package/dist/{presentations-DSV5IHG5.js → presentations-UOET2FVZ.js} +3 -3
  188. package/dist/presentations-UOET2FVZ.js.map +1 -0
  189. package/dist/{prometheus-JNT2BD4L.js → prometheus-YETCZO4I.js} +2 -2
  190. package/dist/prometheus-YETCZO4I.js.map +1 -0
  191. package/dist/{providers-J4LYPHDR.js → providers-2YQ6E3IF.js} +6 -4
  192. package/dist/providers-2YQ6E3IF.js.map +1 -0
  193. package/dist/{qr-code-WIX4PB4U.js → qr-code-6WZJHRKL.js} +2 -2
  194. package/dist/qr-code-6WZJHRKL.js.map +1 -0
  195. package/dist/{quickbooks-XB4NII2S.js → quickbooks-N675W7IK.js} +2 -2
  196. package/dist/{regex-tool-W4ABRKGK.js → regex-tool-6Q63LQ7B.js} +2 -2
  197. package/dist/regex-tool-6Q63LQ7B.js.map +1 -0
  198. package/dist/research-agent-WCRSY3UZ.js +168 -0
  199. package/dist/research-agent-WCRSY3UZ.js.map +1 -0
  200. package/dist/risk-engine-YKCPT5D5.js +10 -0
  201. package/dist/risk-engine-YKCPT5D5.js.map +1 -0
  202. package/dist/scheduler-6PLLAQI7.js +74 -0
  203. package/dist/scheduler-6PLLAQI7.js.map +1 -0
  204. package/dist/schema-ETY7L2VA.js +78 -0
  205. package/dist/schema-ETY7L2VA.js.map +1 -0
  206. package/dist/{search-BCLBO5E3.js → search-GMLKBHSW.js} +4 -4
  207. package/dist/search-GMLKBHSW.js.map +1 -0
  208. package/dist/{sendgrid-RNXCAFKM.js → sendgrid-QGJIVPWV.js} +2 -2
  209. package/dist/sharepoint-V5P4Q62L.js +30 -0
  210. package/dist/sharepoint-V5P4Q62L.js.map +1 -0
  211. package/dist/{shopify-NCXYJB4R.js → shopify-ON2PAU27.js} +2 -2
  212. package/dist/signal-7D5EPGVL.js +44 -0
  213. package/dist/signal-7D5EPGVL.js.map +1 -0
  214. package/dist/slack-KSS6YK5Z.js +86 -0
  215. package/dist/slack-KSS6YK5Z.js.map +1 -0
  216. package/dist/{sms-M3JIOTCW.js → sms-CSUCC7HL.js} +4 -4
  217. package/dist/sms-CSUCC7HL.js.map +1 -0
  218. package/dist/{src-VYUE6LRA.js → src-GO7GGW7O.js} +190 -52
  219. package/dist/src-GO7GGW7O.js.map +1 -0
  220. package/dist/{stocks-XXWBPOCU.js → stocks-4M4HZWZS.js} +2 -2
  221. package/dist/stocks-4M4HZWZS.js.map +1 -0
  222. package/dist/text-extractor-OAUBAW5P.js +12 -0
  223. package/dist/text-extractor-OAUBAW5P.js.map +1 -0
  224. package/dist/{text-transform-6SGUA5Z4.js → text-transform-HCLCUDFZ.js} +2 -2
  225. package/dist/text-transform-HCLCUDFZ.js.map +1 -0
  226. package/dist/token-store-SEWRX6RE.js +20 -0
  227. package/dist/token-store-SEWRX6RE.js.map +1 -0
  228. package/dist/tools-PJZ6RI4P.js +47 -0
  229. package/dist/tools-PJZ6RI4P.js.map +1 -0
  230. package/dist/{tunnel-IWMXUML4.js → tunnel-XOUVVRAK.js} +4 -2
  231. package/dist/tunnel-XOUVVRAK.js.map +1 -0
  232. package/dist/{twilio-53GEW5JT.js → twilio-3L7DUNYQ.js} +2 -2
  233. package/dist/{unit-converter-ZYXMEZOE.js → unit-converter-LYPAHU64.js} +2 -2
  234. package/dist/unit-converter-LYPAHU64.js.map +1 -0
  235. package/dist/whatsapp-DWXK25V2.js +44 -0
  236. package/dist/whatsapp-DWXK25V2.js.map +1 -0
  237. package/dist/{word-document-7B6SJMAY.js → word-document-AV3YB4L2.js} +4 -4
  238. package/dist/word-document-AV3YB4L2.js.map +1 -0
  239. package/dist/workflow-store-5Y56GUP7.js +373 -0
  240. package/dist/workflow-store-5Y56GUP7.js.map +1 -0
  241. package/dist/writing-agent-VDGLNOGO.js +243 -0
  242. package/dist/writing-agent-VDGLNOGO.js.map +1 -0
  243. package/dist/{xero-QYO66D45.js → xero-UHAHVYSD.js} +2 -2
  244. package/dist/{zapier-webhook-TBZ5YF2A.js → zapier-webhook-NIELLTXR.js} +2 -2
  245. package/drizzle/0002_mushy_master_mold.sql +139 -139
  246. package/drizzle/0003_overjoyed_rhodey.sql +46 -0
  247. package/drizzle/meta/0002_snapshot.json +3636 -3636
  248. package/drizzle/meta/0003_snapshot.json +3946 -0
  249. package/drizzle/meta/_journal.json +7 -0
  250. package/package.json +110 -100
  251. package/dist/autonomy-ZXDBDQUJ.js.map +0 -1
  252. package/dist/bot-QRARP4UN.js +0 -36
  253. package/dist/brain-7XLLM3KC.js +0 -56
  254. package/dist/chunk-4GLYY4NN.js.map +0 -1
  255. package/dist/chunk-766ASQWE.js.map +0 -1
  256. package/dist/chunk-AYUKPTSM.js.map +0 -1
  257. package/dist/chunk-BRBWNV65.js.map +0 -1
  258. package/dist/chunk-BXZ6EA52.js.map +0 -1
  259. package/dist/chunk-EVE7MIIY.js.map +0 -1
  260. package/dist/chunk-H5RQOFO2.js.map +0 -1
  261. package/dist/chunk-I6BDYQIG.js.map +0 -1
  262. package/dist/chunk-IZJMVV7O.js +0 -347
  263. package/dist/chunk-IZJMVV7O.js.map +0 -1
  264. package/dist/chunk-O7IH7JTI.js +0 -1898
  265. package/dist/chunk-O7IH7JTI.js.map +0 -1
  266. package/dist/chunk-OCVQGBJK.js.map +0 -1
  267. package/dist/chunk-RZ4YESBG.js.map +0 -1
  268. package/dist/chunk-SPPMCAKG.js.map +0 -1
  269. package/dist/chunk-VRD5CYRL.js +0 -1568
  270. package/dist/chunk-VRD5CYRL.js.map +0 -1
  271. package/dist/chunk-WRAKK6K6.js.map +0 -1
  272. package/dist/chunk-XKYRH4FM.js.map +0 -1
  273. package/dist/chunk-XMCVRVTF.js.map +0 -1
  274. package/dist/chunk-ZLZKF2PM.js.map +0 -1
  275. package/dist/discord-B3HUPGQ6.js +0 -70
  276. package/dist/dist-UISMLMFN.js +0 -21847
  277. package/dist/dist-UISMLMFN.js.map +0 -1
  278. package/dist/email-K7LO2IPB.js.map +0 -1
  279. package/dist/enrichment-pipeline-MNHNW65K.js +0 -13
  280. package/dist/env-IWXUVTCB.js +0 -12
  281. package/dist/imessage-NGA2XF2V.js +0 -35
  282. package/dist/inbox-summarizer-NRI4S7IF.js +0 -47
  283. package/dist/incident-response-C5J7Q6DT.js.map +0 -1
  284. package/dist/presentations-DSV5IHG5.js.map +0 -1
  285. package/dist/scheduler-VK4WFERV.js +0 -63
  286. package/dist/signal-6CGDFYL2.js +0 -35
  287. package/dist/slack-IZQWIKOH.js +0 -75
  288. package/dist/src-VYUE6LRA.js.map +0 -1
  289. package/dist/tools-2RLEI2N6.js +0 -38
  290. package/dist/tunnel-IWMXUML4.js.map +0 -1
  291. package/dist/whatsapp-LFX6YKCM.js +0 -35
  292. package/dist/word-document-7B6SJMAY.js.map +0 -1
  293. /package/dist/{audit-logger-OBPR7CRO.js.map → agent-manager-JZ4IM7XI.js.map} +0 -0
  294. /package/dist/{auth-UOX5K2BE.js.map → agent-types-2T4PXLFQ.js.map} +0 -0
  295. /package/dist/{backup-restore-PZ7CYYB7.js.map → analyzer-OTWE3ARE.js.map} +0 -0
  296. /package/dist/{archiver-AVNBYCKQ.js.map → archiver-FPGKRP6P.js.map} +0 -0
  297. /package/dist/{blocks-R3PODY47.js.map → audit-logger-CI4WZQPD.js.map} +0 -0
  298. /package/dist/{bot-QRARP4UN.js.map → auth-PH5IHISW.js.map} +0 -0
  299. /package/dist/{aws-s3-Q4LLZZPD.js.map → aws-s3-QZMURYXB.js.map} +0 -0
  300. /package/dist/{brain-7XLLM3KC.js.map → backup-restore-72OQTZO3.js.map} +0 -0
  301. /package/dist/{chunk-PLDDJCW6.js.map → blocks-YOWOESDD.js.map} +0 -0
  302. /package/dist/{client-ZQSFPMOB.js.map → bot-VDHBGUVI.js.map} +0 -0
  303. /package/dist/{clipboard-manager-TEO2GEDN.js.map → brain-6QTXN4QP.js.map} +0 -0
  304. /package/dist/{camera-monitor-M5CYKUU4.js.map → camera-monitor-LHTUWHEL.js.map} +0 -0
  305. /package/dist/{charts-V7ARZNKF.js.map → charts-FJ32GQK7.js.map} +0 -0
  306. /package/dist/{chunk-TVEWKIK3.js.map → chunk-2WTKTG2C.js.map} +0 -0
  307. /package/dist/{chunk-SJSUSJ47.js.map → chunk-BNZHWAZC.js.map} +0 -0
  308. /package/dist/{chunk-MQJ2ECQT.js.map → chunk-CUPEENUY.js.map} +0 -0
  309. /package/dist/{chunk-NHMBTUMW.js.map → chunk-CWT6CAE5.js.map} +0 -0
  310. /package/dist/{chunk-6PMVAAA7.js.map → chunk-HJSEEFO3.js.map} +0 -0
  311. /package/dist/{chunk-TYAGMJNV.js.map → chunk-HQZQFEAX.js.map} +0 -0
  312. /package/dist/{chunk-MXAPLSJ5.js.map → chunk-J4JW73TT.js.map} +0 -0
  313. /package/dist/{chunk-VEHFVBLI.js.map → chunk-JHYYFPKX.js.map} +0 -0
  314. /package/dist/{chunk-66OJ3WB4.js.map → chunk-PD3CTDO6.js.map} +0 -0
  315. /package/dist/{cron-explain-HHQKPD3M.js.map → chunk-UP2VWCW5.js.map} +0 -0
  316. /package/dist/{chunk-4UOE5TUZ.js.map → chunk-WMDVOWN6.js.map} +0 -0
  317. /package/dist/{crypto-4AP47IKC.js.map → chunker-K6WTR62A.js.map} +0 -0
  318. /package/dist/{databases-37X4CI2Y.js.map → client-FOIYPOZQ.js.map} +0 -0
  319. /package/dist/{discord-B3HUPGQ6.js.map → clipboard-manager-4SBNESGZ.js.map} +0 -0
  320. /package/dist/{enrichment-pipeline-MNHNW65K.js.map → cost-tracker-KZQSTSE2.js.map} +0 -0
  321. /package/dist/{entity-resolution-Y3IUWEAT.js.map → cron-explain-UOOOYWZZ.js.map} +0 -0
  322. /package/dist/{env-IWXUVTCB.js.map → crypto-2VG3RJR2.js.map} +0 -0
  323. /package/dist/{hash-tool-ULQYD7B5.js.map → databases-XDPMG5AV.js.map} +0 -0
  324. /package/dist/{heartbeat-monitor-GCISLXI3.js.map → db-I7MNG6CL.js.map} +0 -0
  325. /package/dist/{imessage-NGA2XF2V.js.map → discord-6UQHCN27.js.map} +0 -0
  326. /package/dist/{inbox-summarizer-NRI4S7IF.js.map → docx-parser-EXL4TN5E.js.map} +0 -0
  327. /package/dist/{inventory-manager-352OHXWD.js.map → enrichment-pipeline-7FE5R5ZI.js.map} +0 -0
  328. /package/dist/{json-tool-QE2SYHEG.js.map → entity-resolution-7Z6STVXX.js.map} +0 -0
  329. /package/dist/{key-rotation-DPHU4ZTB.js.map → env-GN5VHI43.js.map} +0 -0
  330. /package/dist/{mcp-3JI6W7ZE.js.map → error-tracker-64DEH3D7.js.map} +0 -0
  331. /package/dist/{google-workspace-DKWUVNGC.js.map → google-workspace-TSZPZK5G.js.map} +0 -0
  332. /package/dist/{ocr-AC7NPX33.js.map → graph-client-NB475AK5.js.map} +0 -0
  333. /package/dist/{ollama-BOAMSPLJ.js.map → hash-tool-ENAB5LWH.js.map} +0 -0
  334. /package/dist/{pages-MI523RB7.js.map → heartbeat-monitor-KRDYTDBF.js.map} +0 -0
  335. /package/dist/{pairing-IFQYCPNS.js.map → hooks-N4MIFBVM.js.map} +0 -0
  336. /package/dist/{image-generation-OSU7FP6F.js.map → image-generation-MDE6AVQO.js.map} +0 -0
  337. /package/dist/{pdf-ALQVOEJR.js.map → imessage-DSGSGUZS.js.map} +0 -0
  338. /package/dist/{prometheus-JNT2BD4L.js.map → inbox-summarizer-F2KAU72V.js.map} +0 -0
  339. /package/dist/{providers-J4LYPHDR.js.map → inventory-manager-C67BSZM6.js.map} +0 -0
  340. /package/dist/{jira-GSGDBMIG.js.map → jira-PAGZWUBJ.js.map} +0 -0
  341. /package/dist/{qr-code-WIX4PB4U.js.map → json-tool-4FK5RNER.js.map} +0 -0
  342. /package/dist/{regex-tool-W4ABRKGK.js.map → key-rotation-WCC5FOYS.js.map} +0 -0
  343. /package/dist/{scheduler-VK4WFERV.js.map → knowledge-base-5SMMOGQJ.js.map} +0 -0
  344. /package/dist/{mailchimp-KKNF6QJ7.js.map → mailchimp-ZFYDC44J.js.map} +0 -0
  345. /package/dist/{search-BCLBO5E3.js.map → mcp-DJ2QDA6A.js.map} +0 -0
  346. /package/dist/{signal-6CGDFYL2.js.map → metrics-BH3ZLGEV.js.map} +0 -0
  347. /package/dist/{microsoft365-UCBKJHNX.js.map → microsoft365-6G2IJMWC.js.map} +0 -0
  348. /package/dist/{slack-IZQWIKOH.js.map → oauth-UPJYFOVU.js.map} +0 -0
  349. /package/dist/{sms-M3JIOTCW.js.map → ocr-UONKTQU7.js.map} +0 -0
  350. /package/dist/{stocks-XXWBPOCU.js.map → ollama-J7CU45WT.js.map} +0 -0
  351. /package/dist/{text-transform-6SGUA5Z4.js.map → pages-XDE7JRCA.js.map} +0 -0
  352. /package/dist/{pair-JDFTERIK.js.map → pair-YZJFQUU5.js.map} +0 -0
  353. /package/dist/{tools-2RLEI2N6.js.map → pairing-77N47RAT.js.map} +0 -0
  354. /package/dist/{unit-converter-ZYXMEZOE.js.map → pdf-67HGXCFJ.js.map} +0 -0
  355. /package/dist/{whatsapp-LFX6YKCM.js.map → pdf-parser-YLMTTYHL.js.map} +0 -0
  356. /package/dist/{quickbooks-XB4NII2S.js.map → quickbooks-N675W7IK.js.map} +0 -0
  357. /package/dist/{sendgrid-RNXCAFKM.js.map → sendgrid-QGJIVPWV.js.map} +0 -0
  358. /package/dist/{shopify-NCXYJB4R.js.map → shopify-ON2PAU27.js.map} +0 -0
  359. /package/dist/{twilio-53GEW5JT.js.map → twilio-3L7DUNYQ.js.map} +0 -0
  360. /package/dist/{xero-QYO66D45.js.map → xero-UHAHVYSD.js.map} +0 -0
  361. /package/dist/{zapier-webhook-TBZ5YF2A.js.map → zapier-webhook-NIELLTXR.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/scheduler.ts","../src/core/agents/agent-worker.ts","../src/core/agents/agent-types.ts","../src/core/observability/error-tracker.ts","../src/inputs/calendar/trigger-processor.ts","../src/core/evolution/memory-shedder.ts","../src/core/evolution/growth-reporter.ts"],"sourcesContent":["import { Queue, Worker, type Job } from \"bullmq\";\nimport Redis from \"ioredis\";\nimport { env } from \"../config/env\";\nimport { chat } from \"./brain\";\nimport { startAgentWorker, stopAgentWorker } from \"./agents/agent-worker\";\nimport { processCalendarTriggers, generateDailyBriefing } from \"../inputs/calendar/trigger-processor\";\nimport { autoShed } from \"./evolution/memory-shedder\";\nimport { generateWeeklyReport, generateMonthlyReport } from \"./evolution/growth-reporter\";\nimport { resetMonthlyUsage } from \"./permissions/permission-manager\";\nimport { flushMetrics } from \"./observability/metrics\";\n\n// Lazy Redis connection and queues — created on first use\nlet _connection: Redis | null = null;\nlet _taskQueue: Queue | null = null;\nlet _maintenanceQueue: Queue | null = null;\n\nfunction getConnection(): Redis {\n if (!_connection) {\n _connection = new Redis(env.REDIS_URL, {\n maxRetriesPerRequest: null,\n });\n }\n return _connection;\n}\n\nfunction getTaskQueue(): Queue {\n if (!_taskQueue) {\n _taskQueue = new Queue(\"sentinel-tasks\", { connection: getConnection() });\n }\n return _taskQueue;\n}\n\nfunction getMaintenanceQueue(): Queue {\n if (!_maintenanceQueue) {\n _maintenanceQueue = new Queue(\"sentinel-maintenance\", { connection: getConnection() });\n }\n return _maintenanceQueue;\n}\n\n// Backward-compatible exports\nconst connection = new Proxy({} as Redis, {\n get(_target, prop) {\n const instance = getConnection();\n const value = (instance as any)[prop];\n if (typeof value === \"function\") return value.bind(instance);\n return value;\n },\n});\nconst taskQueue = new Proxy({} as Queue, {\n get(_target, prop) {\n const instance = getTaskQueue();\n const value = (instance as any)[prop];\n if (typeof value === \"function\") return value.bind(instance);\n return value;\n },\n});\nconst maintenanceQueue = new Proxy({} as Queue, {\n get(_target, prop) {\n const instance = getMaintenanceQueue();\n const value = (instance as any)[prop];\n if (typeof value === \"function\") return value.bind(instance);\n return value;\n },\n});\n\ninterface ScheduledTask {\n type: \"reminder\" | \"briefing\" | \"custom\" | \"calendar_check\" | \"memory_shed\" | \"growth_report\" | \"metrics_flush\";\n message?: string;\n userId?: string;\n chatId?: string;\n metadata?: Record<string, unknown>;\n}\n\n// Schedule a task\nexport async function scheduleTask(\n task: ScheduledTask,\n delay: number\n): Promise<string> {\n const job = await taskQueue.add(\"scheduled-task\", task, {\n delay,\n removeOnComplete: true,\n removeOnFail: 100,\n });\n return job.id || \"\";\n}\n\n// Schedule a recurring task (cron-style)\nexport async function scheduleRecurring(\n name: string,\n task: ScheduledTask,\n pattern: string // cron pattern\n): Promise<void> {\n await taskQueue.add(name, task, {\n repeat: { pattern },\n removeOnComplete: true,\n });\n}\n\n// Cancel a scheduled task\nexport async function cancelTask(jobId: string): Promise<boolean> {\n const job = await taskQueue.getJob(jobId);\n if (job) {\n await job.remove();\n return true;\n }\n return false;\n}\n\n// Process scheduled tasks\nlet worker: Worker | null = null;\nlet maintenanceWorker: Worker | null = null;\n\nexport function startWorker(\n onTask: (task: ScheduledTask) => Promise<void>\n): void {\n if (worker) return;\n\n worker = new Worker(\n \"sentinel-tasks\",\n async (job: Job<ScheduledTask>) => {\n console.log(`[Scheduler] Processing task: ${job.name}`);\n await onTask(job.data);\n },\n { connection: getConnection() }\n );\n\n worker.on(\"completed\", (job) => {\n console.log(`[Scheduler] Task completed: ${job.id}`);\n });\n\n worker.on(\"failed\", (job, err) => {\n console.error(`[Scheduler] Task failed: ${job?.id}`, err);\n });\n\n console.log(\"[Scheduler] Worker started\");\n}\n\n// Start maintenance worker for background jobs\nexport function startMaintenanceWorker(): void {\n if (maintenanceWorker) return;\n\n maintenanceWorker = new Worker(\n \"sentinel-maintenance\",\n async (job: Job<ScheduledTask>) => {\n console.log(`[Maintenance] Processing: ${job.name}`);\n\n switch (job.data.type) {\n case \"calendar_check\":\n if (job.data.userId) {\n await processCalendarTriggers(job.data.userId, []);\n }\n break;\n\n case \"memory_shed\":\n if (job.data.userId) {\n const result = await autoShed(job.data.userId);\n console.log(`[Maintenance] Memory shed: archived ${result.archivedCount} memories`);\n }\n break;\n\n case \"growth_report\":\n if (job.data.userId) {\n const reportType = job.data.metadata?.reportType as \"weekly\" | \"monthly\";\n if (reportType === \"monthly\") {\n await generateMonthlyReport(job.data.userId);\n } else {\n await generateWeeklyReport(job.data.userId);\n }\n }\n break;\n\n case \"metrics_flush\":\n await flushMetrics();\n break;\n\n default:\n console.log(`[Maintenance] Unknown task type: ${job.data.type}`);\n }\n },\n { connection: getConnection() }\n );\n\n maintenanceWorker.on(\"completed\", (job) => {\n console.log(`[Maintenance] Completed: ${job.id}`);\n });\n\n maintenanceWorker.on(\"failed\", (job, err) => {\n console.error(`[Maintenance] Failed: ${job?.id}`, err);\n });\n\n console.log(\"[Maintenance] Worker started\");\n}\n\nexport function stopWorker(): void {\n if (worker) {\n worker.close();\n worker = null;\n }\n}\n\nexport function stopMaintenanceWorker(): void {\n if (maintenanceWorker) {\n maintenanceWorker.close();\n maintenanceWorker = null;\n }\n}\n\n// Start all workers and scheduled jobs\nexport async function initializeScheduler(\n onTask: (task: ScheduledTask) => Promise<void>\n): Promise<void> {\n // Start workers\n startWorker(onTask);\n startMaintenanceWorker();\n startAgentWorker();\n\n // Schedule recurring maintenance jobs\n await setupRecurringJobs();\n\n console.log(\"[Scheduler] Initialized\");\n}\n\n// Setup recurring maintenance jobs\nasync function setupRecurringJobs(): Promise<void> {\n // Calendar trigger check - every 15 minutes\n await maintenanceQueue.add(\n \"calendar-check\",\n { type: \"calendar_check\" },\n {\n repeat: { pattern: \"*/15 * * * *\" },\n removeOnComplete: true,\n }\n );\n\n // Metrics flush - every 5 minutes\n await maintenanceQueue.add(\n \"metrics-flush\",\n { type: \"metrics_flush\" },\n {\n repeat: { pattern: \"*/5 * * * *\" },\n removeOnComplete: true,\n }\n );\n\n // Weekly memory shedding - Sundays at 3 AM\n await maintenanceQueue.add(\n \"memory-shed-weekly\",\n { type: \"memory_shed\" },\n {\n repeat: { pattern: \"0 3 * * 0\" },\n removeOnComplete: true,\n }\n );\n\n // Monthly quota reset - 1st of month at midnight\n await maintenanceQueue.add(\n \"quota-reset-monthly\",\n { type: \"custom\", message: \"quota_reset\" },\n {\n repeat: { pattern: \"0 0 1 * *\" },\n removeOnComplete: true,\n }\n );\n\n console.log(\"[Scheduler] Recurring jobs scheduled\");\n}\n\n// Schedule user-specific maintenance\nexport async function scheduleUserMaintenance(\n userId: string,\n type: \"calendar_check\" | \"memory_shed\" | \"growth_report\",\n options?: { pattern?: string; reportType?: \"weekly\" | \"monthly\" }\n): Promise<void> {\n const task: ScheduledTask = {\n type,\n userId,\n metadata: options?.reportType ? { reportType: options.reportType } : undefined,\n };\n\n if (options?.pattern) {\n await maintenanceQueue.add(`${type}-${userId}`, task, {\n repeat: { pattern: options.pattern },\n removeOnComplete: true,\n });\n } else {\n await maintenanceQueue.add(`${type}-${userId}`, task, {\n removeOnComplete: true,\n });\n }\n}\n\n// Shutdown all workers\nexport async function shutdownScheduler(): Promise<void> {\n stopWorker();\n stopMaintenanceWorker();\n stopAgentWorker();\n if (_connection) await _connection.quit();\n console.log(\"[Scheduler] Shutdown complete\");\n}\n\n// Helper to schedule a reminder\nexport async function scheduleReminder(\n message: string,\n delayMs: number,\n chatId?: string\n): Promise<string> {\n return scheduleTask(\n {\n type: \"reminder\",\n message,\n chatId,\n },\n delayMs\n );\n}\n\n// Generate morning briefing content\nexport async function generateBriefing(userId?: string): Promise<string> {\n // Try to use calendar-aware briefing\n if (userId) {\n try {\n return await generateDailyBriefing(userId, []);\n } catch {\n // Fall back to simple briefing\n }\n }\n\n const response = await chat(\n [\n {\n role: \"user\",\n content: `Generate a brief morning briefing. Include:\n1. A motivational greeting\n2. Today's date and day of week\n3. A productivity tip\n\nKeep it concise and uplifting.`,\n },\n ],\n \"You are a helpful assistant creating a morning briefing.\"\n );\n\n return response.content;\n}\n\n// Get queue stats\nexport async function getQueueStats(): Promise<{\n tasks: { waiting: number; active: number; completed: number; failed: number };\n maintenance: { waiting: number; active: number; completed: number; failed: number };\n}> {\n const [taskStats, maintenanceStats] = await Promise.all([\n Promise.all([\n taskQueue.getWaitingCount(),\n taskQueue.getActiveCount(),\n taskQueue.getCompletedCount(),\n taskQueue.getFailedCount(),\n ]),\n Promise.all([\n maintenanceQueue.getWaitingCount(),\n maintenanceQueue.getActiveCount(),\n maintenanceQueue.getCompletedCount(),\n maintenanceQueue.getFailedCount(),\n ]),\n ]);\n\n return {\n tasks: {\n waiting: taskStats[0],\n active: taskStats[1],\n completed: taskStats[2],\n failed: taskStats[3],\n },\n maintenance: {\n waiting: maintenanceStats[0],\n active: maintenanceStats[1],\n completed: maintenanceStats[2],\n failed: maintenanceStats[3],\n },\n };\n}\n\nexport { taskQueue, maintenanceQueue, connection };\n","import { Worker, Job } from \"bullmq\";\nimport Redis from \"ioredis\";\nimport Anthropic from \"@anthropic-ai/sdk\";\nimport { env } from \"../../config/env\";\nimport {\n AgentType,\n AgentResult,\n AGENT_SYSTEM_PROMPTS,\n AGENT_TOOL_PERMISSIONS,\n} from \"./agent-types\";\nimport {\n updateAgentStatus,\n addAgentMessage,\n addAgentProgress,\n shouldAgentStop,\n updateAgentTokens,\n getAgent,\n} from \"./agent-manager\";\nimport { TOOLS, executeTool } from \"../../tools\";\nimport { metric } from \"../observability/metrics\";\nimport { captureException } from \"../observability/error-tracker\";\n\n// Redis connection\nconst connection = new Redis(env.REDIS_URL, {\n maxRetriesPerRequest: null,\n});\n\n// Anthropic client\nconst anthropic = new Anthropic({\n apiKey: env.CLAUDE_API_KEY,\n});\n\ninterface AgentJobData {\n agentId: string;\n userId: string;\n type: AgentType;\n objective: string;\n context?: Record<string, unknown>;\n tokenBudget: number;\n timeBudgetMs: number;\n}\n\nlet worker: Worker | null = null;\n\n// Process an agent task\nasync function processAgentTask(job: Job<AgentJobData>): Promise<AgentResult> {\n const { agentId, userId, type, objective, context, tokenBudget } = job.data;\n const startTime = Date.now();\n let totalTokensUsed = 0;\n\n console.log(`[Agent ${agentId}] Starting ${type} agent: ${objective}`);\n\n // Update status to running\n await updateAgentStatus(agentId, \"running\");\n await addAgentProgress(agentId, 1, \"Starting agent\", \"running\");\n\n // Build system prompt\n const systemPrompt = buildSystemPrompt(type, context);\n\n // Get allowed tools for this agent type\n const allowedToolNames = AGENT_TOOL_PERMISSIONS[type];\n const agentTools = TOOLS.filter((t) => allowedToolNames.includes(t.name));\n\n // Build initial messages\n const messages: Anthropic.MessageParam[] = [\n {\n role: \"user\",\n content: `Your objective: ${objective}\n\n${context ? `Additional context:\\n${JSON.stringify(context, null, 2)}` : \"\"}\n\nPlease proceed with the task, reporting your progress as you go.`,\n },\n ];\n\n await addAgentMessage(agentId, {\n role: \"user\",\n content: messages[0].content as string,\n });\n\n let stepNumber = 2;\n const maxSteps = 20; // Prevent infinite loops\n\n try {\n // Agent loop\n while (stepNumber <= maxSteps) {\n // Check if we should stop\n const stopCheck = await shouldAgentStop(agentId);\n if (stopCheck.stop) {\n await addAgentProgress(\n agentId,\n stepNumber,\n `Stopping: ${stopCheck.reason}`,\n \"completed\"\n );\n break;\n }\n\n // Call Claude\n const response = await anthropic.messages.create({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 4096,\n system: systemPrompt,\n tools: agentTools,\n messages,\n });\n\n // Track tokens\n totalTokensUsed += response.usage.input_tokens + response.usage.output_tokens;\n await updateAgentTokens(agentId, totalTokensUsed);\n\n // Check token budget\n if (totalTokensUsed >= tokenBudget) {\n await addAgentProgress(\n agentId,\n stepNumber,\n \"Token budget reached\",\n \"completed\"\n );\n break;\n }\n\n // Process response\n const assistantContent = response.content;\n\n // Extract text for logging\n const textContent = assistantContent\n .filter((c) => c.type === \"text\")\n .map((c) => (c as { type: \"text\"; text: string }).text)\n .join(\"\\n\");\n\n if (textContent) {\n await addAgentMessage(agentId, {\n role: \"assistant\",\n content: textContent,\n });\n\n // Extract progress description from text\n const progressDesc = textContent.slice(0, 200).replace(/\\n/g, \" \");\n await addAgentProgress(agentId, stepNumber, progressDesc, \"running\");\n }\n\n // Check if done\n if (response.stop_reason === \"end_turn\") {\n // Agent completed naturally\n await addAgentProgress(\n agentId,\n stepNumber + 1,\n \"Task completed\",\n \"completed\",\n textContent\n );\n\n return {\n success: true,\n output: textContent,\n summary: extractSummary(textContent),\n tokensUsed: totalTokensUsed,\n durationMs: Date.now() - startTime,\n };\n }\n\n // Process tool calls\n if (response.stop_reason === \"tool_use\") {\n const toolResults: Anthropic.MessageParam[\"content\"] = [];\n\n for (const block of assistantContent) {\n if (block.type === \"tool_use\") {\n const toolName = block.name;\n const toolInput = block.input as Record<string, unknown>;\n\n console.log(`[Agent ${agentId}] Using tool: ${toolName}`);\n\n // Execute tool\n const result = await executeTool(toolName, toolInput);\n\n await addAgentMessage(agentId, {\n role: \"tool_result\",\n content: JSON.stringify({ tool: toolName, result }),\n metadata: { toolInput },\n });\n\n toolResults.push({\n type: \"tool_result\",\n tool_use_id: block.id,\n content: JSON.stringify(result),\n });\n }\n }\n\n // Add assistant response and tool results to messages\n messages.push({ role: \"assistant\", content: assistantContent });\n messages.push({ role: \"user\", content: toolResults });\n }\n\n stepNumber++;\n }\n\n // Max steps reached\n const agent = await getAgent(agentId);\n const lastMessage = agent?.messages.slice(-1)[0]?.content || \"\";\n\n return {\n success: true,\n output: lastMessage,\n summary: \"Agent completed maximum steps\",\n tokensUsed: totalTokensUsed,\n durationMs: Date.now() - startTime,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n await captureException(error, \"agent\", {\n agentId,\n type,\n objective,\n }, userId);\n\n await addAgentProgress(\n agentId,\n stepNumber,\n `Error: ${errorMessage}`,\n \"failed\"\n );\n\n return {\n success: false,\n error: errorMessage,\n tokensUsed: totalTokensUsed,\n durationMs: Date.now() - startTime,\n };\n }\n}\n\nfunction buildSystemPrompt(\n type: AgentType,\n context?: Record<string, unknown>\n): string {\n let prompt = AGENT_SYSTEM_PROMPTS[type];\n\n if (context) {\n prompt += `\\n\\nAdditional context about the user/task:\\n${JSON.stringify(context, null, 2)}`;\n }\n\n return prompt;\n}\n\nfunction extractSummary(text: string): string {\n // Try to find a summary section\n const summaryMatch = text.match(/(?:summary|conclusion|result):\\s*(.+?)(?:\\n\\n|$)/i);\n if (summaryMatch) {\n return summaryMatch[1].trim();\n }\n\n // Otherwise, take the last paragraph\n const paragraphs = text.split(\"\\n\\n\").filter((p) => p.trim());\n return paragraphs.slice(-1)[0]?.slice(0, 500) || text.slice(0, 500);\n}\n\n// Start the agent worker\nexport function startAgentWorker(): void {\n if (worker) return;\n\n worker = new Worker(\n \"sentinel-agents\",\n async (job: Job<AgentJobData>) => {\n const result = await processAgentTask(job);\n\n // Update final status\n await updateAgentStatus(\n job.data.agentId,\n result.success ? \"completed\" : \"failed\",\n result\n );\n\n // Record metric\n metric.agentOperation(\"complete\", job.data.type);\n\n return result;\n },\n {\n connection,\n concurrency: 3, // Run up to 3 agents concurrently\n }\n );\n\n worker.on(\"completed\", (job) => {\n console.log(`[AgentWorker] Agent completed: ${job.data.agentId}`);\n });\n\n worker.on(\"failed\", (job, err) => {\n console.error(`[AgentWorker] Agent failed: ${job?.data.agentId}`, err);\n });\n\n console.log(\"[AgentWorker] Agent worker started\");\n}\n\n// Stop the agent worker\nexport function stopAgentWorker(): void {\n if (worker) {\n worker.close();\n worker = null;\n }\n}\n\nexport default {\n startAgentWorker,\n stopAgentWorker,\n};\n","export type AgentType = \"research\" | \"coding\" | \"writing\" | \"analysis\" | \"osint\";\n\nexport type AgentStatus =\n | \"pending\"\n | \"running\"\n | \"completed\"\n | \"failed\"\n | \"cancelled\";\n\nexport interface AgentConfig {\n type: AgentType;\n objective: string;\n context?: Record<string, unknown>;\n tokenBudget?: number;\n timeBudgetMs?: number;\n}\n\nexport interface AgentProgress {\n step: number;\n description: string;\n status: \"pending\" | \"running\" | \"completed\" | \"failed\";\n output?: unknown;\n timestamp: Date;\n}\n\nexport interface AgentResult {\n success: boolean;\n output?: unknown;\n summary?: string;\n artifacts?: Array<{\n type: \"file\" | \"data\" | \"report\";\n name: string;\n content: unknown;\n }>;\n error?: string;\n tokensUsed: number;\n durationMs: number;\n}\n\nexport interface AgentMessage {\n role: \"user\" | \"assistant\" | \"system\" | \"tool_result\";\n content: string;\n metadata?: Record<string, unknown>;\n timestamp: Date;\n}\n\nexport interface Agent {\n id: string;\n userId: string;\n type: AgentType;\n name: string;\n status: AgentStatus;\n objective: string;\n context?: Record<string, unknown>;\n tokenBudget: number;\n tokensUsed: number;\n timeBudgetMs: number;\n startedAt?: Date;\n completedAt?: Date;\n createdAt: Date;\n messages: AgentMessage[];\n progress: AgentProgress[];\n result?: AgentResult;\n}\n\n// System prompts for each agent type\nexport const AGENT_SYSTEM_PROMPTS: Record<AgentType, string> = {\n research: `You are a Research Agent. Your goal is to thoroughly investigate a topic and provide comprehensive, well-sourced information.\n\nProcess:\n1. Break down the research question into sub-questions\n2. Search for information from multiple sources\n3. Cross-reference and verify findings\n4. Synthesize information into a coherent report\n5. Note confidence levels and any uncertainties\n\nGuidelines:\n- Always cite or reference your sources\n- Present multiple perspectives when relevant\n- Distinguish between facts and interpretations\n- Flag when information might be outdated\n- Structure findings hierarchically\n\nReport your progress after each major step.`,\n\n coding: `You are a Coding Agent. Your goal is to implement, debug, or improve code based on the given objective.\n\nProcess:\n1. Understand the requirements thoroughly\n2. Explore existing code if relevant\n3. Plan the implementation approach\n4. Write clean, documented code\n5. Test and verify the solution\n\nGuidelines:\n- Follow existing code conventions in the project\n- Write clear comments for complex logic\n- Handle edge cases and errors gracefully\n- Consider performance implications\n- Provide a summary of changes made\n\nReport your progress after each significant step.`,\n\n writing: `You are a Writing Agent. Your goal is to create high-quality written content based on the given objective.\n\nProcess:\n1. Understand the purpose and audience\n2. Research the topic if needed\n3. Create an outline\n4. Write the first draft\n5. Review and refine\n\nGuidelines:\n- Match the tone and style to the purpose\n- Structure content logically\n- Use clear, concise language\n- Support claims with evidence when relevant\n- Proofread for grammar and clarity\n\nReport your progress at each stage.`,\n\n analysis: `You are an Analysis Agent. Your goal is to analyze data or information and provide actionable insights.\n\nProcess:\n1. Understand the analysis objective\n2. Gather and organize the data\n3. Apply appropriate analytical methods\n4. Identify patterns and insights\n5. Present findings with recommendations\n\nGuidelines:\n- Be objective and data-driven\n- Acknowledge limitations in the data\n- Provide context for numbers\n- Make recommendations actionable\n- Visualize data when helpful\n\nReport your progress and key findings along the way.`,\n\n osint: `You are an OSINT (Open Source Intelligence) Agent. Your goal is to investigate entities, trace financial flows, map organizational relationships, and build comprehensive intelligence profiles using public records and open data sources.\n\nProcess:\n1. Identify the target entity (person, organization, committee)\n2. Search across public records databases (FEC, IRS 990, USAspending, SEC EDGAR, OpenCorporates)\n3. Resolve and deduplicate entities using fuzzy matching and identifiers\n4. Build relationship graphs connecting discovered entities\n5. Enrich discovered entities with additional data from all available sources\n6. Analyze patterns: financial flows, organizational hierarchies, political connections\n7. Generate an intelligence report with confidence levels\n\nGuidelines:\n- Use only publicly available information from official government databases\n- Cross-reference data across multiple sources to verify findings\n- Flag low-confidence matches explicitly\n- Build the knowledge graph incrementally, enriching as you discover connections\n- Track the provenance of every data point (source API, date retrieved)\n- Respect rate limits on all public APIs\n- Distinguish between confirmed facts and inferred connections\n- Quantify financial relationships with exact dollar amounts when available\n- Note temporal aspects (when relationships were active)\n- Provide actionable next steps for further investigation\n\nReport findings as you progress through each data source.`,\n};\n\n// Tool permissions for each agent type\nexport const AGENT_TOOL_PERMISSIONS: Record<AgentType, string[]> = {\n research: [\n \"web_search\",\n \"browse_url\",\n \"read_file\",\n \"list_directory\",\n \"search_files\",\n ],\n coding: [\n \"read_file\",\n \"write_file\",\n \"list_directory\",\n \"search_files\",\n \"execute_command\",\n ],\n writing: [\n \"read_file\",\n \"write_file\",\n \"web_search\",\n \"browse_url\",\n ],\n analysis: [\n \"read_file\",\n \"web_search\",\n \"browse_url\",\n \"list_directory\",\n \"search_files\",\n ],\n osint: [\n \"web_search\",\n \"browse_url\",\n \"read_file\",\n \"search_files\",\n \"osint_search\",\n \"osint_graph\",\n \"osint_enrich\",\n \"osint_analyze\",\n ],\n};\n\nexport default {\n AGENT_SYSTEM_PROMPTS,\n AGENT_TOOL_PERMISSIONS,\n};\n","import { db } from \"../../db\";\nimport { errorLogs, NewErrorLog } from \"../../db/schema\";\nimport { eq, and, gte, lte, desc, isNull } from \"drizzle-orm\";\nimport { metric } from \"./metrics\";\n\nexport type ErrorSource =\n | \"brain\"\n | \"tool\"\n | \"telegram\"\n | \"api\"\n | \"scheduler\"\n | \"memory\"\n | \"agent\"\n | \"security\"\n | \"unknown\";\n\nexport interface TrackedError {\n source: ErrorSource;\n errorType: string;\n errorCode?: string;\n message: string;\n stack?: string;\n context?: Record<string, unknown>;\n userId?: string;\n conversationId?: string;\n}\n\nexport async function trackError(error: TrackedError): Promise<string> {\n // Record metric\n metric.error(error.source);\n\n // Log to console\n console.error(`[${error.source.toUpperCase()}] ${error.errorType}: ${error.message}`);\n if (error.stack) {\n console.error(error.stack);\n }\n\n // Store in database\n const [logged] = await db\n .insert(errorLogs)\n .values({\n source: error.source,\n errorType: error.errorType,\n errorCode: error.errorCode,\n message: error.message,\n stack: error.stack,\n context: error.context,\n userId: error.userId,\n conversationId: error.conversationId,\n })\n .returning();\n\n return logged.id;\n}\n\n// Convenience function to track errors from catch blocks\nexport function captureException(\n err: unknown,\n source: ErrorSource,\n context?: Record<string, unknown>,\n userId?: string\n): Promise<string> {\n const error = err instanceof Error ? err : new Error(String(err));\n\n return trackError({\n source,\n errorType: error.constructor.name,\n message: error.message,\n stack: error.stack,\n context,\n userId,\n });\n}\n\n// Wrapper to capture errors from async functions\nexport function withErrorTracking<T extends (...args: unknown[]) => Promise<unknown>>(\n fn: T,\n source: ErrorSource,\n getContext?: (...args: Parameters<T>) => Record<string, unknown>\n): T {\n return (async (...args: Parameters<T>) => {\n try {\n return await fn(...args);\n } catch (err) {\n const context = getContext ? getContext(...args) : undefined;\n await captureException(err, source, context);\n throw err;\n }\n }) as T;\n}\n\nexport interface ErrorQuery {\n source?: ErrorSource;\n errorType?: string;\n startDate?: Date;\n endDate?: Date;\n userId?: string;\n resolved?: boolean;\n limit?: number;\n}\n\nexport async function queryErrors(query: ErrorQuery = {}) {\n const {\n source,\n errorType,\n startDate,\n endDate,\n userId,\n resolved,\n limit = 100,\n } = query;\n\n const conditions = [];\n\n if (source) {\n conditions.push(eq(errorLogs.source, source));\n }\n\n if (errorType) {\n conditions.push(eq(errorLogs.errorType, errorType));\n }\n\n if (startDate) {\n conditions.push(gte(errorLogs.createdAt, startDate));\n }\n\n if (endDate) {\n conditions.push(lte(errorLogs.createdAt, endDate));\n }\n\n if (userId) {\n conditions.push(eq(errorLogs.userId, userId));\n }\n\n if (resolved !== undefined) {\n conditions.push(eq(errorLogs.resolved, resolved));\n }\n\n let q = db.select().from(errorLogs);\n\n if (conditions.length > 0) {\n q = q.where(and(...conditions)) as typeof q;\n }\n\n return q.orderBy(desc(errorLogs.createdAt)).limit(limit);\n}\n\nexport async function getRecentErrors(\n hours: number = 24,\n source?: ErrorSource\n): Promise<typeof errorLogs.$inferSelect[]> {\n const since = new Date(Date.now() - hours * 60 * 60 * 1000);\n\n const conditions = [gte(errorLogs.createdAt, since)];\n\n if (source) {\n conditions.push(eq(errorLogs.source, source));\n }\n\n return db\n .select()\n .from(errorLogs)\n .where(and(...conditions))\n .orderBy(desc(errorLogs.createdAt))\n .limit(100);\n}\n\nexport async function getErrorStats(\n startDate: Date,\n endDate: Date\n): Promise<Record<string, { count: number; sources: Record<string, number> }>> {\n const errors = await db\n .select()\n .from(errorLogs)\n .where(\n and(\n gte(errorLogs.createdAt, startDate),\n lte(errorLogs.createdAt, endDate)\n )\n );\n\n const stats: Record<string, { count: number; sources: Record<string, number> }> = {};\n\n for (const error of errors) {\n if (!stats[error.errorType]) {\n stats[error.errorType] = { count: 0, sources: {} };\n }\n stats[error.errorType].count++;\n stats[error.errorType].sources[error.source] =\n (stats[error.errorType].sources[error.source] || 0) + 1;\n }\n\n return stats;\n}\n\nexport async function markErrorResolved(errorId: string): Promise<boolean> {\n const [updated] = await db\n .update(errorLogs)\n .set({ resolved: true })\n .where(eq(errorLogs.id, errorId))\n .returning();\n\n return !!updated;\n}\n\nexport async function getUnresolvedErrors(): Promise<typeof errorLogs.$inferSelect[]> {\n return db\n .select()\n .from(errorLogs)\n .where(eq(errorLogs.resolved, false))\n .orderBy(desc(errorLogs.createdAt))\n .limit(100);\n}\n\n// Error grouping for similar errors\nexport async function getSimilarErrors(\n errorType: string,\n message: string,\n limit: number = 10\n): Promise<typeof errorLogs.$inferSelect[]> {\n return db\n .select()\n .from(errorLogs)\n .where(eq(errorLogs.errorType, errorType))\n .orderBy(desc(errorLogs.createdAt))\n .limit(limit);\n}\n\n// Cleanup old errors\nexport async function cleanupOldErrors(daysToKeep: number = 90): Promise<number> {\n const cutoff = new Date(Date.now() - daysToKeep * 24 * 60 * 60 * 1000);\n await db\n .delete(errorLogs)\n .where(and(lte(errorLogs.createdAt, cutoff), eq(errorLogs.resolved, true)));\n return 0;\n}\n\n// Error context helpers\nexport const errorContext = {\n tool: (toolName: string, input: Record<string, unknown>) => ({\n toolName,\n input,\n }),\n\n api: (endpoint: string, method: string, statusCode?: number) => ({\n endpoint,\n method,\n statusCode,\n }),\n\n telegram: (chatId: string | number, messageType: string) => ({\n chatId: String(chatId),\n messageType,\n }),\n\n agent: (agentId: string, agentType: string, step?: number) => ({\n agentId,\n agentType,\n step,\n }),\n};\n","import { db } from \"../../db\";\nimport { calendarTriggers, users } from \"../../db/schema\";\nimport { eq, and, lte, gte, isNull } from \"drizzle-orm\";\nimport { scheduleTask } from \"../../core/scheduler\";\nimport {\n fetchICalFromUrl,\n CalendarEvent,\n getUpcomingEvents,\n getTodaysEvents,\n} from \"./ical-parser\";\n\nexport type TriggerType = \"event_start\" | \"event_end\" | \"daily_briefing\";\nexport type CalendarSource = \"google\" | \"outlook\" | \"ical\";\n\nexport interface CalendarTriggerConfig {\n id: string;\n userId: string;\n name: string;\n calendarSource: CalendarSource;\n calendarId?: string;\n triggerType: TriggerType;\n offsetMinutes: number;\n action: {\n type: \"message\" | \"tool\" | \"webhook\";\n payload: Record<string, unknown>;\n };\n enabled: boolean;\n}\n\nexport interface TriggerResult {\n triggerId: string;\n event?: CalendarEvent;\n scheduledJobId?: string;\n error?: string;\n}\n\n// Create a calendar trigger\nexport async function createCalendarTrigger(\n config: Omit<CalendarTriggerConfig, \"id\">\n): Promise<string> {\n const [trigger] = await db\n .insert(calendarTriggers)\n .values({\n userId: config.userId,\n name: config.name,\n calendarSource: config.calendarSource,\n calendarId: config.calendarId,\n triggerType: config.triggerType,\n offsetMinutes: config.offsetMinutes,\n action: config.action,\n enabled: config.enabled,\n })\n .returning();\n\n return trigger.id;\n}\n\n// Get user's calendar triggers\nexport async function getUserTriggers(\n userId: string\n): Promise<CalendarTriggerConfig[]> {\n const triggers = await db\n .select()\n .from(calendarTriggers)\n .where(eq(calendarTriggers.userId, userId));\n\n return triggers.map((t) => ({\n id: t.id,\n userId: t.userId,\n name: t.name,\n calendarSource: t.calendarSource as CalendarSource,\n calendarId: t.calendarId || undefined,\n triggerType: t.triggerType as TriggerType,\n offsetMinutes: t.offsetMinutes || 0,\n action: t.action as CalendarTriggerConfig[\"action\"],\n enabled: t.enabled ?? true,\n }));\n}\n\n// Enable/disable a trigger\nexport async function setTriggerEnabled(\n triggerId: string,\n enabled: boolean\n): Promise<boolean> {\n const [updated] = await db\n .update(calendarTriggers)\n .set({ enabled })\n .where(eq(calendarTriggers.id, triggerId))\n .returning();\n\n return !!updated;\n}\n\n// Delete a trigger\nexport async function deleteTrigger(triggerId: string): Promise<boolean> {\n await db.delete(calendarTriggers).where(eq(calendarTriggers.id, triggerId));\n return true;\n}\n\n// Process triggers for upcoming events\nexport async function processCalendarTriggers(\n userId: string,\n events: CalendarEvent[],\n chatId?: string\n): Promise<TriggerResult[]> {\n const triggers = await getUserTriggers(userId);\n const enabledTriggers = triggers.filter((t) => t.enabled);\n const results: TriggerResult[] = [];\n const now = Date.now();\n\n for (const trigger of enabledTriggers) {\n try {\n if (trigger.triggerType === \"daily_briefing\") {\n // Handle daily briefing separately\n continue;\n }\n\n for (const event of events) {\n const eventTime =\n trigger.triggerType === \"event_start\"\n ? event.startDate.getTime()\n : event.endDate.getTime();\n\n const triggerTime = eventTime - trigger.offsetMinutes * 60 * 1000;\n\n // Only schedule if trigger time is in the future\n if (triggerTime > now) {\n const delay = triggerTime - now;\n\n const jobId = await scheduleTask(\n {\n type: \"custom\",\n message: formatTriggerMessage(trigger, event),\n userId,\n chatId,\n },\n delay\n );\n\n results.push({\n triggerId: trigger.id,\n event,\n scheduledJobId: jobId,\n });\n\n // Update last triggered\n await db\n .update(calendarTriggers)\n .set({ lastTriggered: new Date() })\n .where(eq(calendarTriggers.id, trigger.id));\n }\n }\n } catch (error) {\n results.push({\n triggerId: trigger.id,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return results;\n}\n\nfunction formatTriggerMessage(\n trigger: CalendarTriggerConfig,\n event: CalendarEvent\n): string {\n const timeStr = event.startDate.toLocaleTimeString([], {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n\n if (trigger.triggerType === \"event_start\") {\n if (trigger.offsetMinutes > 0) {\n return `⏰ Reminder: \"${event.summary}\" starts in ${trigger.offsetMinutes} minutes at ${timeStr}`;\n }\n return `🔔 \"${event.summary}\" is starting now!`;\n }\n\n if (trigger.triggerType === \"event_end\") {\n return `✅ \"${event.summary}\" has ended`;\n }\n\n return `📅 Calendar event: ${event.summary}`;\n}\n\n// Generate daily briefing from calendar\nexport async function generateDailyBriefing(\n userId: string,\n events: CalendarEvent[]\n): Promise<string> {\n const todayEvents = getTodaysEvents(events);\n const upcomingEvents = getUpcomingEvents(events, 5);\n\n let briefing = \"📅 **Your Daily Calendar Briefing**\\n\\n\";\n\n if (todayEvents.length === 0) {\n briefing += \"No events scheduled for today.\\n\\n\";\n } else {\n briefing += `**Today's Events (${todayEvents.length}):**\\n`;\n for (const event of todayEvents) {\n const timeStr = event.isAllDay\n ? \"All day\"\n : event.startDate.toLocaleTimeString([], {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n briefing += `• ${timeStr}: ${event.summary}`;\n if (event.location) {\n briefing += ` @ ${event.location}`;\n }\n briefing += \"\\n\";\n }\n briefing += \"\\n\";\n }\n\n const futureEvents = upcomingEvents.filter(\n (e) => !todayEvents.some((t) => t.uid === e.uid)\n );\n\n if (futureEvents.length > 0) {\n briefing += \"**Upcoming:**\\n\";\n for (const event of futureEvents.slice(0, 3)) {\n const dateStr = event.startDate.toLocaleDateString([], {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n });\n briefing += `• ${dateStr}: ${event.summary}\\n`;\n }\n }\n\n return briefing;\n}\n\n// Sync calendar and process triggers\nexport async function syncCalendarAndTriggers(\n userId: string,\n icalUrl: string,\n chatId?: string\n): Promise<{\n eventsFound: number;\n triggersScheduled: number;\n errors: string[];\n}> {\n const errors: string[] = [];\n let eventsFound = 0;\n let triggersScheduled = 0;\n\n try {\n const calendar = await fetchICalFromUrl(icalUrl);\n eventsFound = calendar.events.length;\n\n // Get events for next 24 hours\n const now = new Date();\n const tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000);\n const upcomingEvents = calendar.events.filter(\n (e) => e.startDate >= now && e.startDate <= tomorrow\n );\n\n const results = await processCalendarTriggers(userId, upcomingEvents, chatId);\n triggersScheduled = results.filter((r) => r.scheduledJobId).length;\n errors.push(...results.filter((r) => r.error).map((r) => r.error!));\n } catch (error) {\n errors.push(error instanceof Error ? error.message : String(error));\n }\n\n return { eventsFound, triggersScheduled, errors };\n}\n\nexport default {\n createCalendarTrigger,\n getUserTriggers,\n setTriggerEnabled,\n deleteTrigger,\n processCalendarTriggers,\n generateDailyBriefing,\n syncCalendarAndTriggers,\n};\n","import { db } from \"../../db\";\nimport { memories, archivedMemories } from \"../../db/schema\";\nimport { eq, and, lt, lte, sql } from \"drizzle-orm\";\n\nexport type ShedReason =\n | \"stale\"\n | \"duplicate\"\n | \"low_importance\"\n | \"user_request\"\n | \"deprecated_workflow\";\n\nexport interface ShedCandidate {\n memoryId: string;\n content: string;\n type: string;\n reason: ShedReason;\n lastAccessed: Date | null;\n importance: number;\n confidence: number; // How confident we are this should be shed (0-100)\n}\n\nexport interface ShedResult {\n archivedCount: number;\n archivedIds: string[];\n skippedCount: number;\n}\n\n// Configuration for memory shedding\nconst SHED_CONFIG = {\n staleDays: 90, // Memories not accessed in 90 days\n lowImportanceThreshold: 3, // Memories with importance <= 3\n minConfidence: 70, // Minimum confidence to auto-shed\n};\n\n// Find stale memories (not accessed recently)\nexport async function findStaleMemories(\n userId: string,\n staleDays: number = SHED_CONFIG.staleDays\n): Promise<ShedCandidate[]> {\n const cutoff = new Date(Date.now() - staleDays * 24 * 60 * 60 * 1000);\n\n const stale = await db\n .select()\n .from(memories)\n .where(\n and(\n eq(memories.userId, userId),\n lt(memories.lastAccessed, cutoff)\n )\n );\n\n return stale.map((m) => ({\n memoryId: m.id,\n content: m.content,\n type: m.type,\n reason: \"stale\" as ShedReason,\n lastAccessed: m.lastAccessed,\n importance: m.importance || 5,\n confidence: calculateStaleConfidence(m.lastAccessed, m.importance || 5),\n }));\n}\n\nfunction calculateStaleConfidence(\n lastAccessed: Date | null,\n importance: number\n): number {\n if (!lastAccessed) return 80;\n\n const daysSinceAccess = Math.floor(\n (Date.now() - lastAccessed.getTime()) / (24 * 60 * 60 * 1000)\n );\n\n // Higher confidence for older, less important memories\n let confidence = Math.min(daysSinceAccess / 2, 50); // Max 50 from age\n confidence += (10 - importance) * 5; // Up to 50 from low importance\n\n return Math.min(confidence, 100);\n}\n\n// Find low importance memories\nexport async function findLowImportanceMemories(\n userId: string,\n threshold: number = SHED_CONFIG.lowImportanceThreshold\n): Promise<ShedCandidate[]> {\n const lowImportance = await db\n .select()\n .from(memories)\n .where(\n and(\n eq(memories.userId, userId),\n lte(memories.importance, threshold)\n )\n );\n\n return lowImportance.map((m) => ({\n memoryId: m.id,\n content: m.content,\n type: m.type,\n reason: \"low_importance\" as ShedReason,\n lastAccessed: m.lastAccessed,\n importance: m.importance || 5,\n confidence: (SHED_CONFIG.lowImportanceThreshold - (m.importance || 5) + 1) * 25,\n }));\n}\n\n// Find potential duplicate memories (simplified - would need better NLP in production)\nexport async function findDuplicateMemories(\n userId: string\n): Promise<ShedCandidate[]> {\n const allMemories = await db\n .select()\n .from(memories)\n .where(eq(memories.userId, userId));\n\n const candidates: ShedCandidate[] = [];\n const seen = new Map<string, typeof allMemories[0]>();\n\n for (const memory of allMemories) {\n // Simple duplicate detection: normalize and check for similar content\n const normalized = memory.content.toLowerCase().trim();\n const key = normalized.slice(0, 100); // Use first 100 chars as key\n\n const existing = seen.get(key);\n if (existing) {\n // Mark the newer one as duplicate (keep older memories)\n const isDuplicate =\n memory.createdAt > existing.createdAt ? memory : existing;\n\n candidates.push({\n memoryId: isDuplicate.id,\n content: isDuplicate.content,\n type: isDuplicate.type,\n reason: \"duplicate\",\n lastAccessed: isDuplicate.lastAccessed,\n importance: isDuplicate.importance || 5,\n confidence: 75, // Fairly confident about duplicates\n });\n } else {\n seen.set(key, memory);\n }\n }\n\n return candidates;\n}\n\n// Get all shed candidates for a user\nexport async function identifyShedCandidates(\n userId: string\n): Promise<ShedCandidate[]> {\n const [stale, lowImportance, duplicates] = await Promise.all([\n findStaleMemories(userId),\n findLowImportanceMemories(userId),\n findDuplicateMemories(userId),\n ]);\n\n // Combine and deduplicate by memoryId\n const candidateMap = new Map<string, ShedCandidate>();\n\n for (const candidate of [...stale, ...lowImportance, ...duplicates]) {\n const existing = candidateMap.get(candidate.memoryId);\n if (!existing || candidate.confidence > existing.confidence) {\n candidateMap.set(candidate.memoryId, candidate);\n }\n }\n\n return Array.from(candidateMap.values()).sort(\n (a, b) => b.confidence - a.confidence\n );\n}\n\n// Archive a single memory\nexport async function archiveMemory(\n memoryId: string,\n reason: ShedReason\n): Promise<boolean> {\n const [memory] = await db\n .select()\n .from(memories)\n .where(eq(memories.id, memoryId))\n .limit(1);\n\n if (!memory) return false;\n\n // Insert into archived memories\n await db.insert(archivedMemories).values({\n originalMemoryId: memory.id,\n userId: memory.userId,\n type: memory.type,\n content: memory.content,\n reason,\n originalCreatedAt: memory.createdAt,\n });\n\n // Delete from active memories\n await db.delete(memories).where(eq(memories.id, memoryId));\n\n return true;\n}\n\n// Archive multiple memories\nexport async function archiveMemories(\n memoryIds: string[],\n reason: ShedReason\n): Promise<ShedResult> {\n let archivedCount = 0;\n const archivedIds: string[] = [];\n\n for (const id of memoryIds) {\n const success = await archiveMemory(id, reason);\n if (success) {\n archivedCount++;\n archivedIds.push(id);\n }\n }\n\n return {\n archivedCount,\n archivedIds,\n skippedCount: memoryIds.length - archivedCount,\n };\n}\n\n// Auto-shed memories based on confidence threshold\nexport async function autoShed(\n userId: string,\n minConfidence: number = SHED_CONFIG.minConfidence\n): Promise<ShedResult> {\n const candidates = await identifyShedCandidates(userId);\n const toArchive = candidates.filter((c) => c.confidence >= minConfidence);\n\n const results: ShedResult = {\n archivedCount: 0,\n archivedIds: [],\n skippedCount: 0,\n };\n\n for (const candidate of toArchive) {\n const success = await archiveMemory(candidate.memoryId, candidate.reason);\n if (success) {\n results.archivedCount++;\n results.archivedIds.push(candidate.memoryId);\n } else {\n results.skippedCount++;\n }\n }\n\n return results;\n}\n\n// Restore an archived memory\nexport async function restoreMemory(archivedId: string): Promise<boolean> {\n const [archived] = await db\n .select()\n .from(archivedMemories)\n .where(eq(archivedMemories.id, archivedId))\n .limit(1);\n\n if (!archived) return false;\n\n // Re-insert into active memories (without embedding - would need to regenerate)\n await db.insert(memories).values({\n userId: archived.userId,\n type: archived.type as \"episodic\" | \"semantic\" | \"procedural\",\n content: archived.content,\n importance: 5, // Reset to medium importance\n source: \"restored\",\n });\n\n // Remove from archive\n await db.delete(archivedMemories).where(eq(archivedMemories.id, archivedId));\n\n return true;\n}\n\n// Get archived memories for a user\nexport async function getArchivedMemories(\n userId: string,\n limit: number = 50\n): Promise<typeof archivedMemories.$inferSelect[]> {\n return db\n .select()\n .from(archivedMemories)\n .where(eq(archivedMemories.userId, userId))\n .limit(limit);\n}\n\n// Get shedding statistics\nexport async function getShedStats(\n userId: string\n): Promise<{\n totalArchived: number;\n byReason: Record<ShedReason, number>;\n pendingCandidates: number;\n}> {\n const archived = await getArchivedMemories(userId, 1000);\n const candidates = await identifyShedCandidates(userId);\n\n const byReason: Record<ShedReason, number> = {\n stale: 0,\n duplicate: 0,\n low_importance: 0,\n user_request: 0,\n deprecated_workflow: 0,\n };\n\n for (const memory of archived) {\n const reason = memory.reason as ShedReason;\n if (reason in byReason) {\n byReason[reason]++;\n }\n }\n\n return {\n totalArchived: archived.length,\n byReason,\n pendingCandidates: candidates.length,\n };\n}\n\n// Cleanup old archives (permanent deletion)\nexport async function cleanupOldArchives(\n daysToKeep: number = 365\n): Promise<number> {\n const cutoff = new Date(Date.now() - daysToKeep * 24 * 60 * 60 * 1000);\n\n await db\n .delete(archivedMemories)\n .where(lt(archivedMemories.archivedAt, cutoff));\n\n return 0; // Cleanup completed\n}\n","import { generateGrowthReport, getEvolutionSnapshot } from \"./evolution-tracker\";\nimport { getUserAchievements, checkAchievements, getUserPoints, getAchievementProgress } from \"./achievement-system\";\nimport { getModeStats, getCurrentMode } from \"./mode-manager\";\nimport { getShedStats } from \"./memory-shedder\";\n\nexport interface GrowthReport {\n period: {\n type: \"weekly\" | \"monthly\";\n start: Date;\n end: Date;\n };\n summary: string;\n metrics: {\n conversations: number;\n messages: number;\n toolUses: number;\n newMemories: number;\n archivedMemories: number;\n };\n achievements: {\n newlyUnlocked: Array<{ name: string; emoji: string; points: number }>;\n totalPoints: number;\n pointsGained: number;\n };\n modeUsage: Record<string, { sessions: number; minutes: number }>;\n highlights: string[];\n suggestions: string[];\n}\n\n// Generate a weekly growth report\nexport async function generateWeeklyReport(userId: string): Promise<GrowthReport> {\n const endDate = new Date();\n const startDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);\n\n return generateReport(userId, startDate, endDate, \"weekly\");\n}\n\n// Generate a monthly growth report\nexport async function generateMonthlyReport(userId: string): Promise<GrowthReport> {\n const endDate = new Date();\n const startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);\n\n return generateReport(userId, startDate, endDate, \"monthly\");\n}\n\nasync function generateReport(\n userId: string,\n startDate: Date,\n endDate: Date,\n type: \"weekly\" | \"monthly\"\n): Promise<GrowthReport> {\n // Get growth data\n const growthData = await generateGrowthReport(userId, startDate, endDate);\n\n // Check for new achievements\n const newAchievements = await checkAchievements(userId);\n const totalPoints = await getUserPoints(userId);\n\n // Get mode stats\n const modeStats = await getModeStats(userId);\n\n // Get shed stats\n const shedStats = await getShedStats(userId);\n\n // Generate highlights\n const highlights = generateHighlights(growthData, newAchievements);\n\n // Generate suggestions\n const suggestions = await generateSuggestions(userId, growthData);\n\n // Generate summary\n const summary = generateSummary(growthData, newAchievements, type);\n\n return {\n period: {\n type,\n start: startDate,\n end: endDate,\n },\n summary,\n metrics: {\n conversations: growthData.metrics.conversations,\n messages: growthData.metrics.messages,\n toolUses: growthData.metrics.toolUses,\n newMemories: growthData.metrics.newMemories,\n archivedMemories: shedStats.totalArchived,\n },\n achievements: {\n newlyUnlocked: newAchievements.map((a) => ({\n name: a.name,\n emoji: a.iconEmoji,\n points: a.points,\n })),\n totalPoints,\n pointsGained: newAchievements.reduce((sum, a) => sum + a.points, 0),\n },\n modeUsage: {\n productivity: modeStats.productivity,\n creative: modeStats.creative,\n research: modeStats.research,\n learning: modeStats.learning,\n },\n highlights,\n suggestions,\n };\n}\n\nfunction generateHighlights(\n growthData: Awaited<ReturnType<typeof generateGrowthReport>>,\n newAchievements: Array<{ name: string; iconEmoji: string }>\n): string[] {\n const highlights: string[] = [];\n\n if (growthData.metrics.conversations > 0) {\n highlights.push(\n `You had ${growthData.metrics.conversations} conversations this period!`\n );\n }\n\n if (growthData.metrics.toolUses > 10) {\n highlights.push(\n `Power user alert! You used tools ${growthData.metrics.toolUses} times.`\n );\n }\n\n if (growthData.metrics.newMemories > 5) {\n highlights.push(\n `I learned ${growthData.metrics.newMemories} new things about you.`\n );\n }\n\n for (const achievement of newAchievements) {\n highlights.push(\n `${achievement.iconEmoji} Achievement unlocked: ${achievement.name}!`\n );\n }\n\n if (growthData.patterns.length > 0) {\n const topPattern = growthData.patterns[0];\n highlights.push(\n `New pattern detected: You frequently use ${topPattern.key}.`\n );\n }\n\n return highlights;\n}\n\nasync function generateSuggestions(\n userId: string,\n growthData: Awaited<ReturnType<typeof generateGrowthReport>>\n): Promise<string[]> {\n const suggestions: string[] = [];\n\n // Check achievement progress\n const progress = await getAchievementProgress(userId);\n const almostUnlocked = progress.filter(\n (p) => p.progress / p.target >= 0.7 && p.progress / p.target < 1\n );\n\n for (const achievement of almostUnlocked.slice(0, 2)) {\n const remaining = achievement.target - achievement.progress;\n suggestions.push(\n `You're close to unlocking \"${achievement.achievement.name}\"! Just ${remaining} more ${achievement.achievement.criteria.metric}.`\n );\n }\n\n // Suggest mode if not used\n const currentMode = await getCurrentMode(userId);\n if (!currentMode) {\n suggestions.push(\n \"Try activating a transformation mode! Say 'switch to productivity mode' to get started.\"\n );\n }\n\n // Suggest based on low activity\n if (growthData.metrics.toolUses < 5) {\n suggestions.push(\n \"You haven't used many tools this period. Try asking me to search the web, browse a page, or run a command!\"\n );\n }\n\n return suggestions;\n}\n\nfunction generateSummary(\n growthData: Awaited<ReturnType<typeof generateGrowthReport>>,\n newAchievements: Array<{ name: string }>,\n type: \"weekly\" | \"monthly\"\n): string {\n const period = type === \"weekly\" ? \"this week\" : \"this month\";\n\n let summary = `Here's your ${type} growth report! `;\n\n if (growthData.metrics.conversations > 0) {\n summary += `You've been active with ${growthData.metrics.conversations} conversations ${period}. `;\n } else {\n summary += `I missed you ${period}! Let's catch up. `;\n }\n\n if (newAchievements.length > 0) {\n summary += `You unlocked ${newAchievements.length} new achievement${newAchievements.length > 1 ? \"s\" : \"\"}! `;\n }\n\n if (growthData.metrics.newMemories > 0) {\n summary += `I've been learning about you - ${growthData.metrics.newMemories} new memories stored. `;\n }\n\n return summary.trim();\n}\n\n// Format report as text for Telegram/display\nexport function formatReportAsText(report: GrowthReport): string {\n let text = `📊 **${report.period.type === \"weekly\" ? \"Weekly\" : \"Monthly\"} Growth Report**\\n\\n`;\n\n text += `${report.summary}\\n\\n`;\n\n text += `**📈 Activity**\\n`;\n text += `• Conversations: ${report.metrics.conversations}\\n`;\n text += `• Messages: ${report.metrics.messages}\\n`;\n text += `• Tool uses: ${report.metrics.toolUses}\\n`;\n text += `• New memories: ${report.metrics.newMemories}\\n\\n`;\n\n if (report.achievements.newlyUnlocked.length > 0) {\n text += `**🏆 New Achievements**\\n`;\n for (const achievement of report.achievements.newlyUnlocked) {\n text += `${achievement.emoji} ${achievement.name} (+${achievement.points} pts)\\n`;\n }\n text += `\\nTotal points: ${report.achievements.totalPoints}\\n\\n`;\n }\n\n if (report.highlights.length > 0) {\n text += `**✨ Highlights**\\n`;\n for (const highlight of report.highlights) {\n text += `• ${highlight}\\n`;\n }\n text += `\\n`;\n }\n\n if (report.suggestions.length > 0) {\n text += `**💡 Suggestions**\\n`;\n for (const suggestion of report.suggestions) {\n text += `• ${suggestion}\\n`;\n }\n }\n\n return text;\n}\n\n// Schedule report generation (to be called from scheduler)\nexport async function scheduleReportGeneration(\n userId: string,\n type: \"weekly\" | \"monthly\",\n chatId: string\n): Promise<{ report: GrowthReport; formattedText: string }> {\n const report =\n type === \"weekly\"\n ? await generateWeeklyReport(userId)\n : await generateMonthlyReport(userId);\n\n const formattedText = formatReportAsText(report);\n\n return { report, formattedText };\n}\n"],"mappings":"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","names":["Worker","Redis","eq","eq","eq","eq","and","lte","eq","Redis","connection","worker","Worker"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/integrations/notion/databases.ts"],"sourcesContent":["import { getNotionClient, getRootPageId } from \"./client\";\n\n/**\n * Database operations for Notion\n * Handles querying databases and creating entries\n */\n\n// Type definitions for API responses\ninterface PageObjectResponse {\n id: string;\n url: string;\n created_time: string;\n last_edited_time: string;\n archived: boolean;\n properties: Record<string, any>;\n}\n\ninterface QueryDatabaseParams {\n database_id: string;\n filter?: any;\n sorts?: any[];\n start_cursor?: string;\n page_size?: number;\n}\n\nexport type PropertyType =\n | \"title\"\n | \"rich_text\"\n | \"number\"\n | \"select\"\n | \"multi_select\"\n | \"date\"\n | \"checkbox\"\n | \"url\"\n | \"email\"\n | \"phone_number\"\n | \"formula\"\n | \"relation\"\n | \"rollup\"\n | \"created_time\"\n | \"created_by\"\n | \"last_edited_time\"\n | \"last_edited_by\"\n | \"files\"\n | \"status\";\n\nexport type FilterOperator =\n | \"equals\"\n | \"does_not_equal\"\n | \"contains\"\n | \"does_not_contain\"\n | \"starts_with\"\n | \"ends_with\"\n | \"is_empty\"\n | \"is_not_empty\"\n | \"greater_than\"\n | \"less_than\"\n | \"greater_than_or_equal_to\"\n | \"less_than_or_equal_to\"\n | \"before\"\n | \"after\"\n | \"on_or_before\"\n | \"on_or_after\"\n | \"past_week\"\n | \"past_month\"\n | \"past_year\"\n | \"next_week\"\n | \"next_month\"\n | \"next_year\";\n\nexport interface FilterCondition {\n property: string;\n type?: PropertyType;\n operator: FilterOperator;\n value?: string | number | boolean | Date;\n}\n\nexport interface SortOption {\n property?: string;\n timestamp?: \"created_time\" | \"last_edited_time\";\n direction: \"ascending\" | \"descending\";\n}\n\nexport interface QueryOptions {\n filter?: FilterCondition | FilterCondition[];\n filterOperator?: \"and\" | \"or\";\n sorts?: SortOption[];\n startCursor?: string;\n pageSize?: number;\n}\n\nexport interface DatabaseEntry {\n id: string;\n url: string;\n createdTime: string;\n lastEditedTime: string;\n archived: boolean;\n properties: Record<string, any>;\n}\n\nexport interface DatabaseInfo {\n id: string;\n title: string;\n description: string;\n url: string;\n createdTime: string;\n lastEditedTime: string;\n isInline: boolean;\n properties: Record<string, { type: PropertyType; name: string }>;\n}\n\nexport interface CreateEntryOptions {\n databaseId: string;\n properties: Record<string, any>;\n content?: string;\n icon?: string;\n cover?: string;\n}\n\n/**\n * Convert filter condition to Notion API filter format\n */\nfunction buildFilter(condition: FilterCondition): any {\n const { property, type, operator, value } = condition;\n\n // Determine property type from operator if not specified\n let propertyType = type;\n if (!propertyType) {\n if (\n [\n \"contains\",\n \"does_not_contain\",\n \"starts_with\",\n \"ends_with\",\n \"equals\",\n \"does_not_equal\",\n ].includes(operator)\n ) {\n propertyType = \"rich_text\";\n } else if (\n [\n \"greater_than\",\n \"less_than\",\n \"greater_than_or_equal_to\",\n \"less_than_or_equal_to\",\n ].includes(operator)\n ) {\n propertyType = \"number\";\n } else if (\n [\n \"before\",\n \"after\",\n \"on_or_before\",\n \"on_or_after\",\n \"past_week\",\n \"past_month\",\n \"past_year\",\n \"next_week\",\n \"next_month\",\n \"next_year\",\n ].includes(operator)\n ) {\n propertyType = \"date\";\n } else if ([\"is_empty\", \"is_not_empty\"].includes(operator)) {\n propertyType = \"rich_text\";\n }\n }\n\n const filter: any = { property };\n\n switch (propertyType) {\n case \"title\":\n case \"rich_text\":\n filter[propertyType || \"rich_text\"] = { [operator]: value ?? true };\n break;\n\n case \"number\":\n filter.number = { [operator]: value };\n break;\n\n case \"checkbox\":\n filter.checkbox = { [operator]: value };\n break;\n\n case \"select\":\n filter.select = { [operator]: value };\n break;\n\n case \"multi_select\":\n filter.multi_select = { [operator]: value };\n break;\n\n case \"date\":\n if (\n [\n \"past_week\",\n \"past_month\",\n \"past_year\",\n \"next_week\",\n \"next_month\",\n \"next_year\",\n ].includes(operator)\n ) {\n filter.date = { [operator]: {} };\n } else {\n filter.date = {\n [operator]: value instanceof Date ? value.toISOString() : value,\n };\n }\n break;\n\n case \"url\":\n case \"email\":\n case \"phone_number\":\n filter[propertyType] = { [operator]: value };\n break;\n\n case \"status\":\n filter.status = { [operator]: value };\n break;\n\n default:\n filter.rich_text = { [operator]: value ?? true };\n }\n\n return filter;\n}\n\n/**\n * Query a Notion database\n */\nexport async function queryDatabase(\n databaseId: string,\n options: QueryOptions = {}\n): Promise<{\n results: DatabaseEntry[];\n hasMore: boolean;\n nextCursor: string | null;\n}> {\n const notion = getNotionClient();\n\n const params: QueryDatabaseParams = {\n database_id: databaseId,\n };\n\n // Build filter\n if (options.filter) {\n if (Array.isArray(options.filter)) {\n if (options.filter.length === 1) {\n params.filter = buildFilter(options.filter[0]);\n } else {\n const filters = options.filter.map(buildFilter);\n params.filter =\n options.filterOperator === \"or\"\n ? { or: filters as any }\n : { and: filters as any };\n }\n } else {\n params.filter = buildFilter(options.filter);\n }\n }\n\n // Build sorts\n if (options.sorts) {\n params.sorts = options.sorts.map((sort) => {\n if (sort.timestamp) {\n return { timestamp: sort.timestamp, direction: sort.direction };\n }\n return { property: sort.property!, direction: sort.direction };\n });\n }\n\n // Pagination\n if (options.startCursor) {\n params.start_cursor = options.startCursor;\n }\n if (options.pageSize) {\n params.page_size = options.pageSize;\n }\n\n // Use dataSources.query for newer SDK versions, fallback to databases.query\n const response = await ((notion as any).dataSources?.query?.(params) ??\n (notion as any).databases.query(params));\n\n const results: DatabaseEntry[] = response.results.map((page) => {\n const p = page as PageObjectResponse;\n return {\n id: p.id,\n url: p.url,\n createdTime: p.created_time,\n lastEditedTime: p.last_edited_time,\n archived: p.archived,\n properties: extractPropertyValues(p.properties),\n };\n });\n\n return {\n results,\n hasMore: response.has_more,\n nextCursor: response.next_cursor,\n };\n}\n\n/**\n * Query all results from a database (handles pagination)\n */\nexport async function queryAllDatabaseEntries(\n databaseId: string,\n options: Omit<QueryOptions, \"startCursor\" | \"pageSize\"> = {}\n): Promise<DatabaseEntry[]> {\n const allResults: DatabaseEntry[] = [];\n let cursor: string | undefined;\n\n do {\n const response = await queryDatabase(databaseId, {\n ...options,\n startCursor: cursor,\n pageSize: 100,\n });\n allResults.push(...response.results);\n cursor = response.nextCursor ?? undefined;\n } while (cursor);\n\n return allResults;\n}\n\n/**\n * Get database information\n */\nexport async function getDatabase(databaseId: string): Promise<DatabaseInfo> {\n const notion = getNotionClient();\n\n const response = await notion.databases.retrieve({\n database_id: databaseId,\n }) as any;\n\n const properties: Record<string, { type: PropertyType; name: string }> = {};\n for (const [name, prop] of Object.entries(response.properties || {})) {\n const p = prop as any;\n properties[name] = {\n type: p.type as PropertyType,\n name: p.name,\n };\n }\n\n return {\n id: response.id,\n title: response.title.map((t) => t.plain_text).join(\"\"),\n description: response.description.map((t) => t.plain_text).join(\"\"),\n url: response.url,\n createdTime: response.created_time,\n lastEditedTime: response.last_edited_time,\n isInline: response.is_inline,\n properties,\n };\n}\n\n/**\n * Create an entry in a database\n */\nexport async function createDatabaseEntry(\n options: CreateEntryOptions\n): Promise<DatabaseEntry> {\n const notion = getNotionClient();\n\n const params: any = {\n parent: { database_id: options.databaseId },\n properties: buildDatabaseProperties(options.properties),\n };\n\n // Add icon\n if (options.icon) {\n if (options.icon.startsWith(\"http\")) {\n params.icon = { type: \"external\", external: { url: options.icon } };\n } else {\n params.icon = { type: \"emoji\", emoji: options.icon };\n }\n }\n\n // Add cover\n if (options.cover) {\n params.cover = { type: \"external\", external: { url: options.cover } };\n }\n\n // Add content as children\n if (options.content) {\n const { markdownToBlocks, createBlockObject } = await import(\"./blocks\");\n const blocks = markdownToBlocks(options.content);\n params.children = blocks.map(createBlockObject);\n }\n\n const response = (await notion.pages.create(params)) as PageObjectResponse;\n\n return {\n id: response.id,\n url: response.url,\n createdTime: response.created_time,\n lastEditedTime: response.last_edited_time,\n archived: response.archived,\n properties: extractPropertyValues(response.properties),\n };\n}\n\n/**\n * Update a database entry\n */\nexport async function updateDatabaseEntry(\n pageId: string,\n properties: Record<string, any>\n): Promise<DatabaseEntry> {\n const notion = getNotionClient();\n\n const response = (await notion.pages.update({\n page_id: pageId,\n properties: buildDatabaseProperties(properties),\n })) as PageObjectResponse;\n\n return {\n id: response.id,\n url: response.url,\n createdTime: response.created_time,\n lastEditedTime: response.last_edited_time,\n archived: response.archived,\n properties: extractPropertyValues(response.properties),\n };\n}\n\n/**\n * Archive a database entry\n */\nexport async function archiveDatabaseEntry(pageId: string): Promise<void> {\n const notion = getNotionClient();\n\n await notion.pages.update({\n page_id: pageId,\n archived: true,\n });\n}\n\n/**\n * Create a new database\n */\nexport async function createDatabase(options: {\n parentPageId?: string;\n title: string;\n properties: Record<string, { type: PropertyType; options?: any }>;\n isInline?: boolean;\n}): Promise<DatabaseInfo> {\n const notion = getNotionClient();\n\n const parentId = options.parentPageId || getRootPageId();\n if (!parentId) {\n throw new Error(\"No parent page specified and no root page configured\");\n }\n\n const properties: Record<string, any> = {};\n\n for (const [name, config] of Object.entries(options.properties)) {\n properties[name] = buildPropertySchema(config.type, config.options);\n }\n\n // Ensure there's a title property\n if (!Object.values(properties).some((p) => p.type === \"title\")) {\n properties[\"Name\"] = { title: {} };\n }\n\n const response = (await notion.databases.create({\n parent: { type: \"page_id\", page_id: parentId },\n title: [{ text: { content: options.title } }],\n properties,\n is_inline: options.isInline ?? false,\n } as any)) as any;\n\n const resultProperties: Record<string, { type: PropertyType; name: string }> =\n {};\n for (const [name, prop] of Object.entries(response.properties || {})) {\n const p = prop as any;\n resultProperties[name] = {\n type: p.type as PropertyType,\n name: p.name,\n };\n }\n\n return {\n id: response.id,\n title: response.title.map((t) => t.plain_text).join(\"\"),\n description: \"\",\n url: response.url,\n createdTime: response.created_time,\n lastEditedTime: response.last_edited_time,\n isInline: response.is_inline,\n properties: resultProperties,\n };\n}\n\n/**\n * Build property schema for database creation\n */\nfunction buildPropertySchema(\n type: PropertyType,\n options?: any\n): Record<string, any> {\n switch (type) {\n case \"title\":\n return { title: {} };\n\n case \"rich_text\":\n return { rich_text: {} };\n\n case \"number\":\n return { number: { format: options?.format || \"number\" } };\n\n case \"select\":\n return {\n select: {\n options: options?.options?.map((opt: string) => ({ name: opt })) || [],\n },\n };\n\n case \"multi_select\":\n return {\n multi_select: {\n options: options?.options?.map((opt: string) => ({ name: opt })) || [],\n },\n };\n\n case \"date\":\n return { date: {} };\n\n case \"checkbox\":\n return { checkbox: {} };\n\n case \"url\":\n return { url: {} };\n\n case \"email\":\n return { email: {} };\n\n case \"phone_number\":\n return { phone_number: {} };\n\n case \"status\":\n return {\n status: {\n options:\n options?.options?.map((opt: string) => ({ name: opt })) || [\n { name: \"Not started\" },\n { name: \"In progress\" },\n { name: \"Done\" },\n ],\n },\n };\n\n default:\n return { rich_text: {} };\n }\n}\n\n/**\n * Build database properties for entry creation/update\n */\nfunction buildDatabaseProperties(\n properties: Record<string, any>\n): Record<string, any> {\n const result: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(properties)) {\n if (value === undefined) continue;\n\n // Handle explicit type specification\n if (typeof value === \"object\" && value !== null && value._type) {\n const { _type, ...rest } = value;\n result[key] = buildTypedProperty(_type, rest);\n continue;\n }\n\n // Auto-detect type\n if (typeof value === \"string\") {\n // Check if it looks like a title property\n if (key.toLowerCase() === \"name\" || key.toLowerCase() === \"title\") {\n result[key] = { title: [{ text: { content: value } }] };\n } else if (value.startsWith(\"http://\") || value.startsWith(\"https://\")) {\n result[key] = { url: value };\n } else if (value.includes(\"@\") && value.includes(\".\")) {\n result[key] = { email: value };\n } else {\n result[key] = { rich_text: [{ text: { content: value } }] };\n }\n } else if (typeof value === \"number\") {\n result[key] = { number: value };\n } else if (typeof value === \"boolean\") {\n result[key] = { checkbox: value };\n } else if (value instanceof Date) {\n result[key] = { date: { start: value.toISOString() } };\n } else if (Array.isArray(value)) {\n // Multi-select\n result[key] = { multi_select: value.map((v) => ({ name: String(v) })) };\n }\n }\n\n return result;\n}\n\n/**\n * Build typed property value\n */\nfunction buildTypedProperty(\n type: PropertyType,\n value: any\n): Record<string, any> {\n switch (type) {\n case \"title\":\n return { title: [{ text: { content: value.content || value } }] };\n\n case \"rich_text\":\n return { rich_text: [{ text: { content: value.content || value } }] };\n\n case \"number\":\n return { number: value.value ?? value };\n\n case \"select\":\n return { select: { name: value.name || value } };\n\n case \"multi_select\":\n const options = Array.isArray(value) ? value : value.options || [value];\n return { multi_select: options.map((v: any) => ({ name: v.name || v })) };\n\n case \"date\":\n return {\n date: {\n start:\n value.start instanceof Date\n ? value.start.toISOString()\n : value.start || value,\n end: value.end\n ? value.end instanceof Date\n ? value.end.toISOString()\n : value.end\n : undefined,\n },\n };\n\n case \"checkbox\":\n return { checkbox: value.checked ?? value };\n\n case \"url\":\n return { url: value.url || value };\n\n case \"email\":\n return { email: value.email || value };\n\n case \"phone_number\":\n return { phone_number: value.phone || value };\n\n case \"status\":\n return { status: { name: value.name || value } };\n\n default:\n return { rich_text: [{ text: { content: String(value) } }] };\n }\n}\n\n/**\n * Extract simplified property values from Notion response\n */\nfunction extractPropertyValues(\n properties: Record<string, any>\n): Record<string, any> {\n const result: Record<string, any> = {};\n\n for (const [name, prop] of Object.entries(properties)) {\n switch (prop.type) {\n case \"title\":\n result[name] = prop.title?.map((t: any) => t.plain_text).join(\"\") || \"\";\n break;\n\n case \"rich_text\":\n result[name] =\n prop.rich_text?.map((t: any) => t.plain_text).join(\"\") || \"\";\n break;\n\n case \"number\":\n result[name] = prop.number;\n break;\n\n case \"select\":\n result[name] = prop.select?.name || null;\n break;\n\n case \"multi_select\":\n result[name] = prop.multi_select?.map((s: any) => s.name) || [];\n break;\n\n case \"date\":\n result[name] = prop.date\n ? { start: prop.date.start, end: prop.date.end }\n : null;\n break;\n\n case \"checkbox\":\n result[name] = prop.checkbox;\n break;\n\n case \"url\":\n result[name] = prop.url;\n break;\n\n case \"email\":\n result[name] = prop.email;\n break;\n\n case \"phone_number\":\n result[name] = prop.phone_number;\n break;\n\n case \"formula\":\n result[name] = prop.formula?.[prop.formula.type];\n break;\n\n case \"relation\":\n result[name] = prop.relation?.map((r: any) => r.id) || [];\n break;\n\n case \"rollup\":\n result[name] = prop.rollup?.[prop.rollup.type];\n break;\n\n case \"created_time\":\n result[name] = prop.created_time;\n break;\n\n case \"created_by\":\n result[name] = prop.created_by?.id;\n break;\n\n case \"last_edited_time\":\n result[name] = prop.last_edited_time;\n break;\n\n case \"last_edited_by\":\n result[name] = prop.last_edited_by?.id;\n break;\n\n case \"files\":\n result[name] =\n prop.files?.map((f: any) => f.file?.url || f.external?.url) || [];\n break;\n\n case \"status\":\n result[name] = prop.status?.name || null;\n break;\n\n default:\n result[name] = prop;\n }\n }\n\n return result;\n}\n"],"mappings":";;;;;;;AAAA;AA0HA,SAAS,YAAY,WAAiC;AACpD,QAAM,EAAE,UAAU,MAAM,UAAU,MAAM,IAAI;AAG5C,MAAI,eAAe;AACnB,MAAI,CAAC,cAAc;AACjB,QACE;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,SAAS,QAAQ,GACnB;AACA,qBAAe;AAAA,IACjB,WACE;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,SAAS,QAAQ,GACnB;AACA,qBAAe;AAAA,IACjB,WACE;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,SAAS,QAAQ,GACnB;AACA,qBAAe;AAAA,IACjB,WAAW,CAAC,YAAY,cAAc,EAAE,SAAS,QAAQ,GAAG;AAC1D,qBAAe;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,SAAc,EAAE,SAAS;AAE/B,UAAQ,cAAc;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AACH,aAAO,gBAAgB,WAAW,IAAI,EAAE,CAAC,QAAQ,GAAG,SAAS,KAAK;AAClE;AAAA,IAEF,KAAK;AACH,aAAO,SAAS,EAAE,CAAC,QAAQ,GAAG,MAAM;AACpC;AAAA,IAEF,KAAK;AACH,aAAO,WAAW,EAAE,CAAC,QAAQ,GAAG,MAAM;AACtC;AAAA,IAEF,KAAK;AACH,aAAO,SAAS,EAAE,CAAC,QAAQ,GAAG,MAAM;AACpC;AAAA,IAEF,KAAK;AACH,aAAO,eAAe,EAAE,CAAC,QAAQ,GAAG,MAAM;AAC1C;AAAA,IAEF,KAAK;AACH,UACE;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,SAAS,QAAQ,GACnB;AACA,eAAO,OAAO,EAAE,CAAC,QAAQ,GAAG,CAAC,EAAE;AAAA,MACjC,OAAO;AACL,eAAO,OAAO;AAAA,UACZ,CAAC,QAAQ,GAAG,iBAAiB,OAAO,MAAM,YAAY,IAAI;AAAA,QAC5D;AAAA,MACF;AACA;AAAA,IAEF,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,YAAY,IAAI,EAAE,CAAC,QAAQ,GAAG,MAAM;AAC3C;AAAA,IAEF,KAAK;AACH,aAAO,SAAS,EAAE,CAAC,QAAQ,GAAG,MAAM;AACpC;AAAA,IAEF;AACE,aAAO,YAAY,EAAE,CAAC,QAAQ,GAAG,SAAS,KAAK;AAAA,EACnD;AAEA,SAAO;AACT;AAKA,eAAsB,cACpB,YACA,UAAwB,CAAC,GAKxB;AACD,QAAM,SAAS,gBAAgB;AAE/B,QAAM,SAA8B;AAAA,IAClC,aAAa;AAAA,EACf;AAGA,MAAI,QAAQ,QAAQ;AAClB,QAAI,MAAM,QAAQ,QAAQ,MAAM,GAAG;AACjC,UAAI,QAAQ,OAAO,WAAW,GAAG;AAC/B,eAAO,SAAS,YAAY,QAAQ,OAAO,CAAC,CAAC;AAAA,MAC/C,OAAO;AACL,cAAM,UAAU,QAAQ,OAAO,IAAI,WAAW;AAC9C,eAAO,SACL,QAAQ,mBAAmB,OACvB,EAAE,IAAI,QAAe,IACrB,EAAE,KAAK,QAAe;AAAA,MAC9B;AAAA,IACF,OAAO;AACL,aAAO,SAAS,YAAY,QAAQ,MAAM;AAAA,IAC5C;AAAA,EACF;AAGA,MAAI,QAAQ,OAAO;AACjB,WAAO,QAAQ,QAAQ,MAAM,IAAI,CAAC,SAAS;AACzC,UAAI,KAAK,WAAW;AAClB,eAAO,EAAE,WAAW,KAAK,WAAW,WAAW,KAAK,UAAU;AAAA,MAChE;AACA,aAAO,EAAE,UAAU,KAAK,UAAW,WAAW,KAAK,UAAU;AAAA,IAC/D,CAAC;AAAA,EACH;AAGA,MAAI,QAAQ,aAAa;AACvB,WAAO,eAAe,QAAQ;AAAA,EAChC;AACA,MAAI,QAAQ,UAAU;AACpB,WAAO,YAAY,QAAQ;AAAA,EAC7B;AAGA,QAAM,WAAW,OAAQ,OAAe,aAAa,QAAQ,MAAM,KAChE,OAAe,UAAU,MAAM,MAAM;AAExC,QAAM,UAA2B,SAAS,QAAQ,IAAI,CAAC,SAAS;AAC9D,UAAM,IAAI;AACV,WAAO;AAAA,MACL,IAAI,EAAE;AAAA,MACN,KAAK,EAAE;AAAA,MACP,aAAa,EAAE;AAAA,MACf,gBAAgB,EAAE;AAAA,MAClB,UAAU,EAAE;AAAA,MACZ,YAAY,sBAAsB,EAAE,UAAU;AAAA,IAChD;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,SAAS,SAAS;AAAA,IAClB,YAAY,SAAS;AAAA,EACvB;AACF;AAKA,eAAsB,wBACpB,YACA,UAA0D,CAAC,GACjC;AAC1B,QAAM,aAA8B,CAAC;AACrC,MAAI;AAEJ,KAAG;AACD,UAAM,WAAW,MAAM,cAAc,YAAY;AAAA,MAC/C,GAAG;AAAA,MACH,aAAa;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AACD,eAAW,KAAK,GAAG,SAAS,OAAO;AACnC,aAAS,SAAS,cAAc;AAAA,EAClC,SAAS;AAET,SAAO;AACT;AAKA,eAAsB,YAAY,YAA2C;AAC3E,QAAM,SAAS,gBAAgB;AAE/B,QAAM,WAAW,MAAM,OAAO,UAAU,SAAS;AAAA,IAC/C,aAAa;AAAA,EACf,CAAC;AAED,QAAM,aAAmE,CAAC;AAC1E,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,SAAS,cAAc,CAAC,CAAC,GAAG;AACpE,UAAM,IAAI;AACV,eAAW,IAAI,IAAI;AAAA,MACjB,MAAM,EAAE;AAAA,MACR,MAAM,EAAE;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI,SAAS;AAAA,IACb,OAAO,SAAS,MAAM,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE;AAAA,IACtD,aAAa,SAAS,YAAY,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE;AAAA,IAClE,KAAK,SAAS;AAAA,IACd,aAAa,SAAS;AAAA,IACtB,gBAAgB,SAAS;AAAA,IACzB,UAAU,SAAS;AAAA,IACnB;AAAA,EACF;AACF;AAKA,eAAsB,oBACpB,SACwB;AACxB,QAAM,SAAS,gBAAgB;AAE/B,QAAM,SAAc;AAAA,IAClB,QAAQ,EAAE,aAAa,QAAQ,WAAW;AAAA,IAC1C,YAAY,wBAAwB,QAAQ,UAAU;AAAA,EACxD;AAGA,MAAI,QAAQ,MAAM;AAChB,QAAI,QAAQ,KAAK,WAAW,MAAM,GAAG;AACnC,aAAO,OAAO,EAAE,MAAM,YAAY,UAAU,EAAE,KAAK,QAAQ,KAAK,EAAE;AAAA,IACpE,OAAO;AACL,aAAO,OAAO,EAAE,MAAM,SAAS,OAAO,QAAQ,KAAK;AAAA,IACrD;AAAA,EACF;AAGA,MAAI,QAAQ,OAAO;AACjB,WAAO,QAAQ,EAAE,MAAM,YAAY,UAAU,EAAE,KAAK,QAAQ,MAAM,EAAE;AAAA,EACtE;AAGA,MAAI,QAAQ,SAAS;AACnB,UAAM,EAAE,kBAAkB,kBAAkB,IAAI,MAAM,OAAO,sBAAU;AACvE,UAAM,SAAS,iBAAiB,QAAQ,OAAO;AAC/C,WAAO,WAAW,OAAO,IAAI,iBAAiB;AAAA,EAChD;AAEA,QAAM,WAAY,MAAM,OAAO,MAAM,OAAO,MAAM;AAElD,SAAO;AAAA,IACL,IAAI,SAAS;AAAA,IACb,KAAK,SAAS;AAAA,IACd,aAAa,SAAS;AAAA,IACtB,gBAAgB,SAAS;AAAA,IACzB,UAAU,SAAS;AAAA,IACnB,YAAY,sBAAsB,SAAS,UAAU;AAAA,EACvD;AACF;AAKA,eAAsB,oBACpB,QACA,YACwB;AACxB,QAAM,SAAS,gBAAgB;AAE/B,QAAM,WAAY,MAAM,OAAO,MAAM,OAAO;AAAA,IAC1C,SAAS;AAAA,IACT,YAAY,wBAAwB,UAAU;AAAA,EAChD,CAAC;AAED,SAAO;AAAA,IACL,IAAI,SAAS;AAAA,IACb,KAAK,SAAS;AAAA,IACd,aAAa,SAAS;AAAA,IACtB,gBAAgB,SAAS;AAAA,IACzB,UAAU,SAAS;AAAA,IACnB,YAAY,sBAAsB,SAAS,UAAU;AAAA,EACvD;AACF;AAKA,eAAsB,qBAAqB,QAA+B;AACxE,QAAM,SAAS,gBAAgB;AAE/B,QAAM,OAAO,MAAM,OAAO;AAAA,IACxB,SAAS;AAAA,IACT,UAAU;AAAA,EACZ,CAAC;AACH;AAKA,eAAsB,eAAe,SAKX;AACxB,QAAM,SAAS,gBAAgB;AAE/B,QAAM,WAAW,QAAQ,gBAAgB,cAAc;AACvD,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AAEA,QAAM,aAAkC,CAAC;AAEzC,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,QAAQ,UAAU,GAAG;AAC/D,eAAW,IAAI,IAAI,oBAAoB,OAAO,MAAM,OAAO,OAAO;AAAA,EACpE;AAGA,MAAI,CAAC,OAAO,OAAO,UAAU,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,GAAG;AAC9D,eAAW,MAAM,IAAI,EAAE,OAAO,CAAC,EAAE;AAAA,EACnC;AAEA,QAAM,WAAY,MAAM,OAAO,UAAU,OAAO;AAAA,IAC9C,QAAQ,EAAE,MAAM,WAAW,SAAS,SAAS;AAAA,IAC7C,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,QAAQ,MAAM,EAAE,CAAC;AAAA,IAC5C;AAAA,IACA,WAAW,QAAQ,YAAY;AAAA,EACjC,CAAQ;AAER,QAAM,mBACJ,CAAC;AACH,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,SAAS,cAAc,CAAC,CAAC,GAAG;AACpE,UAAM,IAAI;AACV,qBAAiB,IAAI,IAAI;AAAA,MACvB,MAAM,EAAE;AAAA,MACR,MAAM,EAAE;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI,SAAS;AAAA,IACb,OAAO,SAAS,MAAM,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE;AAAA,IACtD,aAAa;AAAA,IACb,KAAK,SAAS;AAAA,IACd,aAAa,SAAS;AAAA,IACtB,gBAAgB,SAAS;AAAA,IACzB,UAAU,SAAS;AAAA,IACnB,YAAY;AAAA,EACd;AACF;AAKA,SAAS,oBACP,MACA,SACqB;AACrB,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,EAAE,OAAO,CAAC,EAAE;AAAA,IAErB,KAAK;AACH,aAAO,EAAE,WAAW,CAAC,EAAE;AAAA,IAEzB,KAAK;AACH,aAAO,EAAE,QAAQ,EAAE,QAAQ,SAAS,UAAU,SAAS,EAAE;AAAA,IAE3D,KAAK;AACH,aAAO;AAAA,QACL,QAAQ;AAAA,UACN,SAAS,SAAS,SAAS,IAAI,CAAC,SAAiB,EAAE,MAAM,IAAI,EAAE,KAAK,CAAC;AAAA,QACvE;AAAA,MACF;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,cAAc;AAAA,UACZ,SAAS,SAAS,SAAS,IAAI,CAAC,SAAiB,EAAE,MAAM,IAAI,EAAE,KAAK,CAAC;AAAA,QACvE;AAAA,MACF;AAAA,IAEF,KAAK;AACH,aAAO,EAAE,MAAM,CAAC,EAAE;AAAA,IAEpB,KAAK;AACH,aAAO,EAAE,UAAU,CAAC,EAAE;AAAA,IAExB,KAAK;AACH,aAAO,EAAE,KAAK,CAAC,EAAE;AAAA,IAEnB,KAAK;AACH,aAAO,EAAE,OAAO,CAAC,EAAE;AAAA,IAErB,KAAK;AACH,aAAO,EAAE,cAAc,CAAC,EAAE;AAAA,IAE5B,KAAK;AACH,aAAO;AAAA,QACL,QAAQ;AAAA,UACN,SACE,SAAS,SAAS,IAAI,CAAC,SAAiB,EAAE,MAAM,IAAI,EAAE,KAAK;AAAA,YACzD,EAAE,MAAM,cAAc;AAAA,YACtB,EAAE,MAAM,cAAc;AAAA,YACtB,EAAE,MAAM,OAAO;AAAA,UACjB;AAAA,QACJ;AAAA,MACF;AAAA,IAEF;AACE,aAAO,EAAE,WAAW,CAAC,EAAE;AAAA,EAC3B;AACF;AAKA,SAAS,wBACP,YACqB;AACrB,QAAM,SAA8B,CAAC;AAErC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,QAAI,UAAU,OAAW;AAGzB,QAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,OAAO;AAC9D,YAAM,EAAE,OAAO,GAAG,KAAK,IAAI;AAC3B,aAAO,GAAG,IAAI,mBAAmB,OAAO,IAAI;AAC5C;AAAA,IACF;AAGA,QAAI,OAAO,UAAU,UAAU;AAE7B,UAAI,IAAI,YAAY,MAAM,UAAU,IAAI,YAAY,MAAM,SAAS;AACjE,eAAO,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,EAAE;AAAA,MACxD,WAAW,MAAM,WAAW,SAAS,KAAK,MAAM,WAAW,UAAU,GAAG;AACtE,eAAO,GAAG,IAAI,EAAE,KAAK,MAAM;AAAA,MAC7B,WAAW,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,GAAG,GAAG;AACrD,eAAO,GAAG,IAAI,EAAE,OAAO,MAAM;AAAA,MAC/B,OAAO;AACL,eAAO,GAAG,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,EAAE;AAAA,MAC5D;AAAA,IACF,WAAW,OAAO,UAAU,UAAU;AACpC,aAAO,GAAG,IAAI,EAAE,QAAQ,MAAM;AAAA,IAChC,WAAW,OAAO,UAAU,WAAW;AACrC,aAAO,GAAG,IAAI,EAAE,UAAU,MAAM;AAAA,IAClC,WAAW,iBAAiB,MAAM;AAChC,aAAO,GAAG,IAAI,EAAE,MAAM,EAAE,OAAO,MAAM,YAAY,EAAE,EAAE;AAAA,IACvD,WAAW,MAAM,QAAQ,KAAK,GAAG;AAE/B,aAAO,GAAG,IAAI,EAAE,cAAc,MAAM,IAAI,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,EAAE,EAAE,EAAE;AAAA,IACxE;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,mBACP,MACA,OACqB;AACrB,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,MAAM,WAAW,MAAM,EAAE,CAAC,EAAE;AAAA,IAElE,KAAK;AACH,aAAO,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,MAAM,WAAW,MAAM,EAAE,CAAC,EAAE;AAAA,IAEtE,KAAK;AACH,aAAO,EAAE,QAAQ,MAAM,SAAS,MAAM;AAAA,IAExC,KAAK;AACH,aAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,QAAQ,MAAM,EAAE;AAAA,IAEjD,KAAK;AACH,YAAM,UAAU,MAAM,QAAQ,KAAK,IAAI,QAAQ,MAAM,WAAW,CAAC,KAAK;AACtE,aAAO,EAAE,cAAc,QAAQ,IAAI,CAAC,OAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE;AAAA,IAE1E,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,UACJ,OACE,MAAM,iBAAiB,OACnB,MAAM,MAAM,YAAY,IACxB,MAAM,SAAS;AAAA,UACrB,KAAK,MAAM,MACP,MAAM,eAAe,OACnB,MAAM,IAAI,YAAY,IACtB,MAAM,MACR;AAAA,QACN;AAAA,MACF;AAAA,IAEF,KAAK;AACH,aAAO,EAAE,UAAU,MAAM,WAAW,MAAM;AAAA,IAE5C,KAAK;AACH,aAAO,EAAE,KAAK,MAAM,OAAO,MAAM;AAAA,IAEnC,KAAK;AACH,aAAO,EAAE,OAAO,MAAM,SAAS,MAAM;AAAA,IAEvC,KAAK;AACH,aAAO,EAAE,cAAc,MAAM,SAAS,MAAM;AAAA,IAE9C,KAAK;AACH,aAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,QAAQ,MAAM,EAAE;AAAA,IAEjD;AACE,aAAO,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,OAAO,KAAK,EAAE,EAAE,CAAC,EAAE;AAAA,EAC/D;AACF;AAKA,SAAS,sBACP,YACqB;AACrB,QAAM,SAA8B,CAAC;AAErC,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK;AACH,eAAO,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,MAAW,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK;AACrE;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IACT,KAAK,WAAW,IAAI,CAAC,MAAW,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK;AAC5D;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK;AACpB;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK,QAAQ,QAAQ;AACpC;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK,cAAc,IAAI,CAAC,MAAW,EAAE,IAAI,KAAK,CAAC;AAC9D;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK,OAChB,EAAE,OAAO,KAAK,KAAK,OAAO,KAAK,KAAK,KAAK,IAAI,IAC7C;AACJ;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK;AACpB;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK;AACpB;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK;AACpB;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK;AACpB;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK,UAAU,KAAK,QAAQ,IAAI;AAC/C;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC,MAAW,EAAE,EAAE,KAAK,CAAC;AACxD;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK,SAAS,KAAK,OAAO,IAAI;AAC7C;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK;AACpB;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK,YAAY;AAChC;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK;AACpB;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK,gBAAgB;AACpC;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IACT,KAAK,OAAO,IAAI,CAAC,MAAW,EAAE,MAAM,OAAO,EAAE,UAAU,GAAG,KAAK,CAAC;AAClE;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,IAAI,KAAK,QAAQ,QAAQ;AACpC;AAAA,MAEF;AACE,eAAO,IAAI,IAAI;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/providers/anthropic-provider.ts","../src/core/providers/registry.ts","../src/core/providers/index.ts"],"sourcesContent":["/**\n * Anthropic Provider — Wraps the Anthropic SDK\n *\n * Converts between provider-agnostic LLM types and Anthropic's SDK types.\n * Handles extended thinking, vision, and tool use natively.\n */\n\nimport Anthropic from \"@anthropic-ai/sdk\";\nimport type { LLMProvider } from \"./provider\";\nimport type {\n LLMProviderCapabilities,\n LLMProviderConfig,\n LLMRequest,\n LLMResponse,\n LLMContentBlock,\n LLMStreamEvent,\n LLMStreamResult,\n LLMMessage,\n LLMTool,\n} from \"./types\";\n\nexport class AnthropicProvider implements LLMProvider {\n readonly id: string;\n readonly name: string;\n readonly type = \"anthropic\";\n private client: Anthropic;\n\n constructor(config: LLMProviderConfig) {\n this.id = config.id;\n this.name = config.name;\n this.client = new Anthropic({ apiKey: config.apiKey });\n }\n\n getCapabilities(): LLMProviderCapabilities {\n return {\n supportsVision: true,\n supportsToolUse: true,\n supportsStreaming: true,\n supportsExtendedThinking: true,\n supportsSystemPrompt: true,\n maxContextWindow: 200000,\n };\n }\n\n async createMessage(request: LLMRequest): Promise<LLMResponse> {\n const { system, messages } = this.extractSystem(request);\n\n const params: any = {\n model: request.model,\n max_tokens: request.max_tokens,\n system,\n messages,\n };\n\n if (request.tools?.length) {\n params.tools = request.tools.map(toLLMToolToAnthropicTool);\n }\n\n if (request.thinking) {\n params.thinking = request.thinking;\n }\n\n const response = await this.client.messages.create(params);\n\n return {\n content: response.content.map(anthropicBlockToLLM),\n stop_reason: mapStopReason(response.stop_reason),\n usage: {\n input_tokens: response.usage.input_tokens,\n output_tokens: response.usage.output_tokens,\n },\n model: response.model,\n };\n }\n\n streamMessage(request: LLMRequest): LLMStreamResult {\n const { system, messages } = this.extractSystem(request);\n\n const params: any = {\n model: request.model,\n max_tokens: request.max_tokens,\n system,\n messages,\n };\n\n if (request.tools?.length) {\n params.tools = request.tools.map(toLLMToolToAnthropicTool);\n }\n\n const stream = this.client.messages.stream(params);\n\n const events: AsyncIterable<LLMStreamEvent> = {\n async *[Symbol.asyncIterator]() {\n for await (const event of stream) {\n if (event.type === \"content_block_delta\" && (event.delta as any).type === \"text_delta\") {\n yield {\n type: \"content_block_delta\" as const,\n delta: { type: \"text_delta\" as const, text: (event.delta as any).text },\n };\n }\n }\n },\n };\n\n return {\n events,\n async finalMessage(): Promise<LLMResponse> {\n const msg = await stream.finalMessage();\n return {\n content: msg.content.map(anthropicBlockToLLM),\n stop_reason: mapStopReason(msg.stop_reason),\n usage: {\n input_tokens: msg.usage.input_tokens,\n output_tokens: msg.usage.output_tokens,\n },\n model: msg.model,\n };\n },\n };\n }\n\n async listModels(): Promise<string[]> {\n return [\n \"claude-haiku-4-5-20251001\",\n \"claude-sonnet-4-20250514\",\n \"claude-opus-4-20250514\",\n ];\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n // Minimal API call to check connectivity\n await this.client.messages.create({\n model: \"claude-haiku-4-5-20251001\",\n max_tokens: 1,\n messages: [{ role: \"user\", content: \"hi\" }],\n });\n return true;\n } catch {\n return false;\n }\n }\n\n /** Get the raw Anthropic client (for specialized use cases like vision) */\n getClient(): Anthropic {\n return this.client;\n }\n\n /**\n * Extract system messages and convert LLMMessages to Anthropic MessageParam format.\n * Anthropic uses a separate `system` parameter instead of a system role message.\n */\n private extractSystem(request: LLMRequest): {\n system: string;\n messages: any[];\n } {\n let system = request.system || \"\";\n\n const messages = request.messages\n .filter((m) => m.role !== \"system\")\n .map((m) => llmMessageToAnthropicMessage(m));\n\n return { system, messages };\n }\n}\n\n// ============================================\n// Conversion helpers\n// ============================================\n\nfunction toLLMToolToAnthropicTool(tool: LLMTool): any {\n // Anthropic uses the same format: { name, description, input_schema }\n return {\n name: tool.name,\n description: tool.description,\n input_schema: tool.input_schema,\n };\n}\n\nfunction llmMessageToAnthropicMessage(msg: LLMMessage): any {\n if (typeof msg.content === \"string\") {\n return { role: msg.role, content: msg.content };\n }\n\n // Convert content blocks\n const anthropicContent = msg.content.map((block) => {\n switch (block.type) {\n case \"text\":\n return { type: \"text\", text: block.text };\n case \"image\":\n return {\n type: \"image\",\n source: {\n type: block.source?.type || \"base64\",\n media_type: block.source?.mediaType || \"image/jpeg\",\n data: block.source?.data,\n ...(block.source?.url ? { url: block.source.url } : {}),\n },\n };\n case \"tool_use\":\n return {\n type: \"tool_use\",\n id: block.id,\n name: block.name,\n input: block.input,\n };\n case \"tool_result\":\n return {\n type: \"tool_result\",\n tool_use_id: block.tool_use_id,\n content: block.content,\n };\n default:\n return { type: \"text\", text: block.text || \"\" };\n }\n });\n\n return { role: msg.role, content: anthropicContent };\n}\n\nfunction anthropicBlockToLLM(block: any): LLMContentBlock {\n switch (block.type) {\n case \"text\":\n return { type: \"text\", text: block.text };\n case \"tool_use\":\n return {\n type: \"tool_use\",\n id: block.id,\n name: block.name,\n input: block.input,\n };\n default:\n return { type: \"text\", text: block.text || \"\" };\n }\n}\n\nfunction mapStopReason(reason: string | null): LLMResponse[\"stop_reason\"] {\n switch (reason) {\n case \"end_turn\":\n return \"end_turn\";\n case \"tool_use\":\n return \"tool_use\";\n case \"max_tokens\":\n return \"max_tokens\";\n default:\n return \"end_turn\";\n }\n}\n","/**\n * Provider Registry — Manages all configured LLM providers\n */\n\nimport type { LLMProvider } from \"./provider\";\n\nexport class ProviderRegistry {\n private providers: Map<string, LLMProvider> = new Map();\n private defaultProviderId: string | null = null;\n\n register(provider: LLMProvider): void {\n this.providers.set(provider.id, provider);\n // First registered provider becomes default\n if (!this.defaultProviderId) {\n this.defaultProviderId = provider.id;\n }\n }\n\n unregister(id: string): void {\n this.providers.delete(id);\n if (this.defaultProviderId === id) {\n this.defaultProviderId = this.providers.keys().next().value || null;\n }\n }\n\n get(id: string): LLMProvider | undefined {\n return this.providers.get(id);\n }\n\n getDefault(): LLMProvider {\n if (!this.defaultProviderId) {\n throw new Error(\n \"[ProviderRegistry] No LLM providers configured. Set CLAUDE_API_KEY, OPENROUTER_API_KEY, or OLLAMA_ENABLED.\"\n );\n }\n const provider = this.providers.get(this.defaultProviderId);\n if (!provider) {\n throw new Error(`[ProviderRegistry] Default provider '${this.defaultProviderId}' not found.`);\n }\n return provider;\n }\n\n setDefault(id: string): void {\n if (!this.providers.has(id)) {\n console.warn(`[ProviderRegistry] Provider '${id}' not registered, cannot set as default.`);\n return;\n }\n this.defaultProviderId = id;\n }\n\n getDefaultId(): string | null {\n return this.defaultProviderId;\n }\n\n has(id: string): boolean {\n return this.providers.has(id);\n }\n\n listProviders(): Array<{ id: string; name: string; type: string }> {\n return Array.from(this.providers.values()).map((p) => ({\n id: p.id,\n name: p.name,\n type: p.type,\n }));\n }\n\n getProviderCount(): number {\n return this.providers.size;\n }\n\n clear(): void {\n this.providers.clear();\n this.defaultProviderId = null;\n }\n}\n\nexport const providerRegistry = new ProviderRegistry();\n","/**\n * Provider initialization and re-exports\n */\n\nimport { env } from \"../../config/env\";\nimport { AnthropicProvider } from \"./anthropic-provider\";\nimport { OpenAICompatibleProvider } from \"./openai-compatible-provider\";\nimport { providerRegistry } from \"./registry\";\n\n/**\n * Initialize all configured LLM providers from environment variables.\n * Called once during application startup.\n */\nexport async function initializeProviders(): Promise<void> {\n // Always register Anthropic if CLAUDE_API_KEY is set\n if (env.CLAUDE_API_KEY) {\n providerRegistry.register(\n new AnthropicProvider({\n id: \"anthropic\",\n name: \"Anthropic\",\n type: \"anthropic\",\n apiKey: env.CLAUDE_API_KEY,\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: Anthropic\");\n }\n\n // Register OpenAI if key is set (for LLM use, separate from Whisper STT)\n if ((env as any).OPENAI_LLM_ENABLED && env.OPENAI_API_KEY) {\n providerRegistry.register(\n new OpenAICompatibleProvider({\n id: \"openai\",\n name: \"OpenAI\",\n type: \"openai\",\n apiKey: env.OPENAI_API_KEY,\n baseUrl: \"https://api.openai.com/v1\",\n defaultModel: \"gpt-4o\",\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: OpenAI\");\n }\n\n // Register OpenRouter if configured\n if ((env as any).OPENROUTER_API_KEY) {\n providerRegistry.register(\n new OpenAICompatibleProvider({\n id: \"openrouter\",\n name: \"OpenRouter\",\n type: \"openai-compatible\",\n apiKey: (env as any).OPENROUTER_API_KEY,\n baseUrl: (env as any).OPENROUTER_BASE_URL || \"https://openrouter.ai/api/v1\",\n defaultModel: \"anthropic/claude-sonnet-4-20250514\",\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: OpenRouter\");\n }\n\n // Register Groq if configured\n if ((env as any).GROQ_API_KEY) {\n providerRegistry.register(\n new OpenAICompatibleProvider({\n id: \"groq\",\n name: \"Groq\",\n type: \"openai-compatible\",\n apiKey: (env as any).GROQ_API_KEY,\n baseUrl: \"https://api.groq.com/openai/v1\",\n defaultModel: \"llama-3.1-70b-versatile\",\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: Groq\");\n }\n\n // Register Mistral if configured\n if ((env as any).MISTRAL_API_KEY) {\n providerRegistry.register(\n new OpenAICompatibleProvider({\n id: \"mistral\",\n name: \"Mistral\",\n type: \"openai-compatible\",\n apiKey: (env as any).MISTRAL_API_KEY,\n baseUrl: \"https://api.mistral.ai/v1\",\n defaultModel: \"mistral-large-latest\",\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: Mistral\");\n }\n\n // Register generic OpenAI-compatible endpoint if configured\n if ((env as any).OPENAI_COMPATIBLE_BASE_URL) {\n providerRegistry.register(\n new OpenAICompatibleProvider({\n id: \"custom\",\n name: \"Custom Provider\",\n type: \"openai-compatible\",\n apiKey: (env as any).OPENAI_COMPATIBLE_API_KEY || \"not-needed\",\n baseUrl: (env as any).OPENAI_COMPATIBLE_BASE_URL,\n defaultModel: (env as any).OPENAI_COMPATIBLE_MODEL || \"default\",\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: Custom (\" + (env as any).OPENAI_COMPATIBLE_BASE_URL + \")\");\n }\n\n // Register Ollama if enabled (requires async probe)\n if ((env as any).OLLAMA_ENABLED) {\n try {\n const { OllamaProvider } = await import(\"./ollama\");\n const ollamaBaseUrl = (env as any).OLLAMA_BASE_URL || \"http://localhost:11434\";\n const ollamaModel = (env as any).OLLAMA_DEFAULT_MODEL || \"llama3.1\";\n const ollama = new OllamaProvider(ollamaBaseUrl, ollamaModel);\n\n const available = await ollama.isAvailable();\n if (available) {\n providerRegistry.register(ollama);\n const models = await ollama.listModels();\n console.log(`[LLM] Registered provider: Ollama (${models.length} model(s): ${models.slice(0, 5).join(\", \")})`);\n } else {\n console.warn(`[LLM] Ollama enabled but not reachable at ${ollamaBaseUrl}`);\n }\n } catch (err: any) {\n console.warn(\"[LLM] Failed to initialize Ollama:\", err.message);\n }\n }\n\n // Set default provider\n const defaultId = (env as any).LLM_PROVIDER || \"anthropic\";\n if (providerRegistry.has(defaultId)) {\n providerRegistry.setDefault(defaultId);\n }\n\n const providers = providerRegistry.listProviders();\n if (providers.length === 0) {\n console.warn(\"[LLM] No LLM providers configured. Set CLAUDE_API_KEY or another provider key.\");\n } else {\n console.log(\n `[LLM] ${providers.length} provider(s) ready. Default: ${providerRegistry.getDefaultId()}`\n );\n }\n}\n\n// Re-exports\nexport { providerRegistry } from \"./registry\";\nexport { AnthropicProvider } from \"./anthropic-provider\";\nexport { OpenAICompatibleProvider } from \"./openai-compatible-provider\";\nexport { OllamaProvider } from \"./ollama\";\nexport type { LLMProvider } from \"./provider\";\nexport type {\n LLMMessage,\n LLMContentBlock,\n LLMTool,\n LLMRequest,\n LLMResponse,\n LLMStreamEvent,\n LLMStreamResult,\n LLMProviderCapabilities,\n LLMProviderConfig,\n} from \"./types\";\n"],"mappings":"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","names":["OllamaProvider"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/tools/image-analysis.ts","../src/tools/ocr.ts"],"sourcesContent":["import Anthropic from \"@anthropic-ai/sdk\";\nimport { env } from \"../config/env\";\nimport { readFile } from \"fs/promises\";\nimport { isPathAllowed } from \"../utils/paths\";\n\nconst anthropic = new Anthropic({\n apiKey: env.CLAUDE_API_KEY,\n});\n\nexport interface ImageAnalysisResult {\n success: boolean;\n analysis?: string;\n error?: string;\n}\n\n// Supported image MIME types\nconst SUPPORTED_TYPES: Record<string, string> = {\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n};\n\nfunction getMimeType(filename: string): string | null {\n const ext = filename.toLowerCase().slice(filename.lastIndexOf(\".\"));\n return SUPPORTED_TYPES[ext] || null;\n}\n\n// Analyze image from URL\nexport async function analyzeImageUrl(\n imageUrl: string,\n prompt: string\n): Promise<ImageAnalysisResult> {\n try {\n const response = await anthropic.messages.create({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 1024,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"url\",\n url: imageUrl,\n },\n },\n {\n type: \"text\",\n text: prompt || \"Describe this image in detail.\",\n },\n ],\n },\n ],\n });\n\n const textContent = response.content.find((c) => c.type === \"text\");\n return {\n success: true,\n analysis: textContent?.type === \"text\" ? textContent.text : undefined,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n// Analyze image from local file\nexport async function analyzeImageFile(\n filePath: string,\n prompt: string\n): Promise<ImageAnalysisResult> {\n try {\n // Security check\n if (!isPathAllowed(filePath)) {\n return {\n success: false,\n error: \"Access to this path is not allowed\",\n };\n }\n\n const mimeType = getMimeType(filePath);\n if (!mimeType) {\n return {\n success: false,\n error: \"Unsupported image format. Supported: jpg, png, gif, webp\",\n };\n }\n\n const imageData = await readFile(filePath);\n const base64 = imageData.toString(\"base64\");\n\n const response = await anthropic.messages.create({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 1024,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: mimeType as \"image/jpeg\" | \"image/png\" | \"image/gif\" | \"image/webp\",\n data: base64,\n },\n },\n {\n type: \"text\",\n text: prompt || \"Describe this image in detail.\",\n },\n ],\n },\n ],\n });\n\n const textContent = response.content.find((c) => c.type === \"text\");\n return {\n success: true,\n analysis: textContent?.type === \"text\" ? textContent.text : undefined,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n// Analyze image from buffer\nexport async function analyzeImageBuffer(\n imageBuffer: Buffer,\n mimeType: \"image/jpeg\" | \"image/png\" | \"image/gif\" | \"image/webp\",\n prompt: string\n): Promise<ImageAnalysisResult> {\n try {\n const base64 = imageBuffer.toString(\"base64\");\n\n const response = await anthropic.messages.create({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 1024,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"base64\",\n media_type: mimeType,\n data: base64,\n },\n },\n {\n type: \"text\",\n text: prompt || \"Describe this image in detail.\",\n },\n ],\n },\n ],\n });\n\n const textContent = response.content.find((c) => c.type === \"text\");\n return {\n success: true,\n analysis: textContent?.type === \"text\" ? textContent.text : undefined,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n// Combined function for tool use\nexport async function analyzeImage(\n options: {\n imageUrl?: string;\n imagePath?: string;\n prompt: string;\n }\n): Promise<ImageAnalysisResult> {\n if (options.imageUrl) {\n return analyzeImageUrl(options.imageUrl, options.prompt);\n }\n\n if (options.imagePath) {\n return analyzeImageFile(options.imagePath, options.prompt);\n }\n\n return {\n success: false,\n error: \"Either imageUrl or imagePath must be provided\",\n };\n}\n\nexport default {\n analyzeImage,\n analyzeImageUrl,\n analyzeImageFile,\n analyzeImageBuffer,\n};\n","import { readFile } from \"fs/promises\";\nimport { isPathAllowed } from \"../utils/paths\";\nimport { analyzeImageFile } from \"./image-analysis\";\n\nexport interface OCRResult {\n success: boolean;\n text?: string;\n confidence?: number;\n error?: string;\n}\n\n// OCR using Tesseract.js (local, no API key needed)\nexport async function ocrWithTesseract(\n filePath: string,\n language: string = \"eng\"\n): Promise<OCRResult> {\n try {\n const Tesseract = await import(\"tesseract.js\");\n const worker = await Tesseract.createWorker(language);\n const { data } = await worker.recognize(filePath);\n await worker.terminate();\n\n return {\n success: true,\n text: data.text,\n confidence: data.confidence / 100,\n };\n } catch (error) {\n return {\n success: false,\n error: `Tesseract OCR failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n\n// Use Claude Vision for OCR (most reliable for complex documents)\nexport async function ocrWithVision(\n filePath: string,\n language?: string\n): Promise<OCRResult> {\n const prompt = language\n ? `Extract all text from this image. The text is in ${language}. Return only the extracted text, preserving the original formatting and layout as much as possible.`\n : `Extract all text from this image. Return only the extracted text, preserving the original formatting and layout as much as possible.`;\n\n const result = await analyzeImageFile(filePath, prompt);\n\n if (result.success && result.analysis) {\n return {\n success: true,\n text: result.analysis,\n };\n }\n\n return {\n success: false,\n error: result.error || \"Failed to extract text\",\n };\n}\n\n// OCR using Tesseract.js as primary, falling back to Vision API\nexport async function ocrSimple(filePath: string): Promise<OCRResult> {\n const result = await ocrWithTesseract(filePath);\n if (result.success && result.confidence && result.confidence > 0.6) {\n return result;\n }\n // Fall back to Vision API on low confidence or failure\n return ocrWithVision(filePath);\n}\n\n// OCR for PDF files (extract text from each page)\nexport async function ocrPdf(\n filePath: string,\n pages?: string // e.g., \"1-5\" or \"1,3,5\"\n): Promise<OCRResult> {\n // For PDFs, we'll use Claude Vision on the file directly\n const prompt = `Extract all text from this PDF document. Return the text content, preserving the structure and formatting as much as possible. If there are multiple pages, separate them clearly.`;\n\n const result = await analyzeImageFile(filePath, prompt);\n\n if (result.success && result.analysis) {\n return {\n success: true,\n text: result.analysis,\n };\n }\n\n return {\n success: false,\n error: result.error || \"Failed to extract text from PDF\",\n };\n}\n\n// Main OCR function that determines the best approach\nexport async function performOCR(\n filePath: string,\n options?: {\n language?: string;\n useVision?: boolean;\n }\n): Promise<OCRResult> {\n // Security check\n if (!isPathAllowed(filePath)) {\n return {\n success: false,\n error: \"Access to this path is not allowed\",\n };\n }\n\n const ext = filePath.toLowerCase().slice(filePath.lastIndexOf(\".\"));\n\n // PDF handling\n if (ext === \".pdf\") {\n return ocrPdf(filePath);\n }\n\n // Image handling - use Vision API (most accurate)\n if ([\".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".bmp\", \".tiff\"].includes(ext)) {\n if (options?.useVision !== false) {\n return ocrWithVision(filePath, options?.language);\n }\n return ocrSimple(filePath);\n }\n\n return {\n success: false,\n error: `Unsupported file type: ${ext}`,\n };\n}\n\n// Extract structured data from document (tables, forms)\nexport async function extractStructuredData(\n filePath: string,\n dataType?: \"table\" | \"form\" | \"receipt\" | \"invoice\"\n): Promise<{\n success: boolean;\n data?: Record<string, unknown>;\n error?: string;\n}> {\n const prompts: Record<string, string> = {\n table: `Extract all tables from this image. Return the data as JSON arrays where each table is an array of rows, and each row is an array of cell values.`,\n form: `Extract all form fields from this image. Return as a JSON object where keys are field labels and values are the filled-in content.`,\n receipt: `Extract receipt information from this image. Return as JSON with: store_name, date, items (array with name, quantity, price), subtotal, tax, total.`,\n invoice: `Extract invoice information from this image. Return as JSON with: vendor, invoice_number, date, due_date, line_items (array), subtotal, tax, total, billing_address.`,\n };\n\n const prompt = dataType\n ? prompts[dataType]\n : `Extract any structured data from this image. Return as JSON.`;\n\n const result = await analyzeImageFile(filePath, prompt);\n\n if (result.success && result.analysis) {\n try {\n // Try to parse as JSON\n const jsonMatch = result.analysis.match(/```json\\n?([\\s\\S]*?)\\n?```/);\n if (jsonMatch) {\n return {\n success: true,\n data: JSON.parse(jsonMatch[1]),\n };\n }\n\n // Try direct parse\n const data = JSON.parse(result.analysis);\n return { success: true, data };\n } catch {\n // Return raw text if not JSON\n return {\n success: true,\n data: { rawText: result.analysis },\n };\n }\n }\n\n return {\n success: false,\n error: result.error || \"Failed to extract structured data\",\n };\n}\n\nexport default {\n performOCR,\n ocrWithVision,\n ocrWithTesseract,\n extractStructuredData,\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/integrations/notion/search.ts"],"sourcesContent":["import { getNotionClient } from \"./client\";\n\n/**\n * Search functionality for Notion workspace\n * Supports searching across pages and databases\n */\n\n// Type definitions for API responses\ninterface PageObjectResponse {\n object: \"page\";\n id: string;\n url: string;\n created_time: string;\n last_edited_time: string;\n archived: boolean;\n icon?: { type: string; emoji?: string; external?: { url: string } };\n cover?: { type: string; external?: { url: string }; file?: { url: string } };\n parent: { type: string; page_id?: string; database_id?: string };\n properties: Record<string, any>;\n}\n\ninterface DatabaseObjectResponse {\n object: \"database\";\n id: string;\n url: string;\n title: Array<{ plain_text: string }>;\n description: Array<{ plain_text: string }>;\n created_time: string;\n last_edited_time: string;\n is_inline: boolean;\n icon?: { type: string; emoji?: string; external?: { url: string } };\n cover?: { type: string; external?: { url: string }; file?: { url: string } };\n parent: { type: string; page_id?: string };\n}\n\ninterface SearchParams {\n query?: string;\n filter?: any;\n sort?: any;\n start_cursor?: string;\n page_size?: number;\n}\n\nexport type SearchObjectType = \"page\" | \"database\";\n\nexport interface SearchOptions {\n query?: string;\n filter?: {\n value: SearchObjectType;\n property: \"object\";\n };\n sort?: {\n direction: \"ascending\" | \"descending\";\n timestamp: \"last_edited_time\";\n };\n startCursor?: string;\n pageSize?: number;\n}\n\nexport interface SearchResultPage {\n type: \"page\";\n id: string;\n url: string;\n title: string;\n createdTime: string;\n lastEditedTime: string;\n archived: boolean;\n icon?: string;\n cover?: string;\n parent: {\n type: \"page\" | \"database\" | \"workspace\";\n id?: string;\n };\n}\n\nexport interface SearchResultDatabase {\n type: \"database\";\n id: string;\n url: string;\n title: string;\n description: string;\n createdTime: string;\n lastEditedTime: string;\n isInline: boolean;\n icon?: string;\n cover?: string;\n parent: {\n type: \"page\" | \"workspace\";\n id?: string;\n };\n}\n\nexport type SearchResult = SearchResultPage | SearchResultDatabase;\n\nexport interface SearchResponse {\n results: SearchResult[];\n hasMore: boolean;\n nextCursor: string | null;\n}\n\n/**\n * Extract title from page properties\n */\nfunction extractPageTitle(properties: Record<string, any>): string {\n for (const value of Object.values(properties)) {\n if (value?.type === \"title\" && Array.isArray(value.title)) {\n return value.title.map((t: any) => t.plain_text || \"\").join(\"\");\n }\n }\n return \"Untitled\";\n}\n\n/**\n * Convert page response to search result\n */\nfunction pageToSearchResult(page: PageObjectResponse): SearchResultPage {\n let parent: SearchResultPage[\"parent\"];\n\n if (page.parent.type === \"page_id\") {\n parent = { type: \"page\", id: page.parent.page_id };\n } else if (page.parent.type === \"database_id\") {\n parent = { type: \"database\", id: page.parent.database_id };\n } else {\n parent = { type: \"workspace\" };\n }\n\n return {\n type: \"page\",\n id: page.id,\n url: page.url,\n title: extractPageTitle(page.properties),\n createdTime: page.created_time,\n lastEditedTime: page.last_edited_time,\n archived: page.archived,\n icon:\n page.icon?.type === \"emoji\"\n ? page.icon.emoji\n : page.icon?.type === \"external\"\n ? page.icon.external.url\n : undefined,\n cover:\n page.cover?.type === \"external\"\n ? page.cover.external.url\n : page.cover?.type === \"file\"\n ? page.cover.file.url\n : undefined,\n parent,\n };\n}\n\n/**\n * Convert database response to search result\n */\nfunction databaseToSearchResult(\n database: DatabaseObjectResponse\n): SearchResultDatabase {\n let parent: SearchResultDatabase[\"parent\"];\n\n if (database.parent.type === \"page_id\") {\n parent = { type: \"page\", id: database.parent.page_id };\n } else {\n parent = { type: \"workspace\" };\n }\n\n return {\n type: \"database\",\n id: database.id,\n url: database.url,\n title: database.title.map((t) => t.plain_text).join(\"\"),\n description: database.description.map((t) => t.plain_text).join(\"\"),\n createdTime: database.created_time,\n lastEditedTime: database.last_edited_time,\n isInline: database.is_inline,\n icon:\n database.icon?.type === \"emoji\"\n ? database.icon.emoji\n : database.icon?.type === \"external\"\n ? database.icon.external.url\n : undefined,\n cover:\n database.cover?.type === \"external\"\n ? database.cover.external.url\n : database.cover?.type === \"file\"\n ? database.cover.file.url\n : undefined,\n parent,\n };\n}\n\n/**\n * Search across the entire Notion workspace\n */\nexport async function search(options: SearchOptions = {}): Promise<SearchResponse> {\n const notion = getNotionClient();\n\n const params: SearchParams = {};\n\n if (options.query) {\n params.query = options.query;\n }\n\n if (options.filter) {\n // Map 'database' to 'data_source' for newer SDK versions\n const filterValue = options.filter.value === \"database\" ? \"data_source\" : options.filter.value;\n params.filter = { value: filterValue, property: options.filter.property };\n }\n\n if (options.sort) {\n params.sort = options.sort;\n }\n\n if (options.startCursor) {\n params.start_cursor = options.startCursor;\n }\n\n if (options.pageSize) {\n params.page_size = options.pageSize;\n }\n\n const response = await notion.search(params as any);\n\n const results: SearchResult[] = response.results.map((item: any) => {\n if (item.object === \"page\") {\n return pageToSearchResult(item as PageObjectResponse);\n } else {\n return databaseToSearchResult(item as DatabaseObjectResponse);\n }\n });\n\n return {\n results,\n hasMore: response.has_more,\n nextCursor: response.next_cursor,\n };\n}\n\n/**\n * Search for pages only\n */\nexport async function searchPages(\n query?: string,\n options: Omit<SearchOptions, \"filter\"> = {}\n): Promise<SearchResultPage[]> {\n const response = await search({\n ...options,\n query,\n filter: { value: \"page\", property: \"object\" },\n });\n\n return response.results.filter(\n (r): r is SearchResultPage => r.type === \"page\"\n );\n}\n\n/**\n * Search for databases only\n */\nexport async function searchDatabases(\n query?: string,\n options: Omit<SearchOptions, \"filter\"> = {}\n): Promise<SearchResultDatabase[]> {\n const response = await search({\n ...options,\n query,\n filter: { value: \"database\", property: \"object\" },\n });\n\n return response.results.filter(\n (r): r is SearchResultDatabase => r.type === \"database\"\n );\n}\n\n/**\n * Search all results (handles pagination)\n */\nexport async function searchAll(\n query?: string,\n options: Omit<SearchOptions, \"startCursor\" | \"pageSize\"> = {}\n): Promise<SearchResult[]> {\n const allResults: SearchResult[] = [];\n let cursor: string | undefined;\n\n do {\n const response = await search({\n ...options,\n query,\n startCursor: cursor,\n pageSize: 100,\n });\n allResults.push(...response.results);\n cursor = response.nextCursor ?? undefined;\n } while (cursor);\n\n return allResults;\n}\n\n/**\n * Find a page by title\n */\nexport async function findPageByTitle(\n title: string,\n exactMatch: boolean = false\n): Promise<SearchResultPage | null> {\n const pages = await searchPages(title);\n\n if (exactMatch) {\n return pages.find((p) => p.title === title) || null;\n }\n\n return pages[0] || null;\n}\n\n/**\n * Find a database by title\n */\nexport async function findDatabaseByTitle(\n title: string,\n exactMatch: boolean = false\n): Promise<SearchResultDatabase | null> {\n const databases = await searchDatabases(title);\n\n if (exactMatch) {\n return databases.find((d) => d.title === title) || null;\n }\n\n return databases[0] || null;\n}\n\n/**\n * Get recently edited pages\n */\nexport async function getRecentlyEditedPages(\n limit: number = 10\n): Promise<SearchResultPage[]> {\n const response = await search({\n filter: { value: \"page\", property: \"object\" },\n sort: { direction: \"descending\", timestamp: \"last_edited_time\" },\n pageSize: limit,\n });\n\n return response.results.filter(\n (r): r is SearchResultPage => r.type === \"page\"\n );\n}\n\n/**\n * Get recently edited databases\n */\nexport async function getRecentlyEditedDatabases(\n limit: number = 10\n): Promise<SearchResultDatabase[]> {\n const response = await search({\n filter: { value: \"database\", property: \"object\" },\n sort: { direction: \"descending\", timestamp: \"last_edited_time\" },\n pageSize: limit,\n });\n\n return response.results.filter(\n (r): r is SearchResultDatabase => r.type === \"database\"\n );\n}\n\n/**\n * Full text search in workspace\n * Returns pages and databases matching the query\n */\nexport async function fullTextSearch(\n query: string,\n options: {\n objectType?: SearchObjectType;\n limit?: number;\n sortByRelevance?: boolean;\n } = {}\n): Promise<SearchResult[]> {\n const searchOptions: SearchOptions = {\n query,\n pageSize: options.limit ?? 20,\n };\n\n if (options.objectType) {\n searchOptions.filter = { value: options.objectType, property: \"object\" };\n }\n\n if (!options.sortByRelevance) {\n searchOptions.sort = {\n direction: \"descending\",\n timestamp: \"last_edited_time\",\n };\n }\n\n const response = await search(searchOptions);\n return response.results;\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/inputs/telegram/bot.ts","../src/inputs/telegram/handlers.ts"],"sourcesContent":["import { Bot, Context, session } from \"grammy\";\nimport { env } from \"../../config/env\";\nimport { handleMessage, handleVoice } from \"./handlers\";\nimport { scheduleReminder } from \"../../core/scheduler\";\n\nexport interface SessionData {\n messages: Array<{ role: \"user\" | \"assistant\"; content: string }>;\n}\n\nexport type OpenSentinelContext = Context & { session: SessionData };\n\nexport function createBot() {\n const bot = new Bot<OpenSentinelContext>(env.TELEGRAM_BOT_TOKEN);\n\n // Session middleware for conversation history\n bot.use(\n session({\n initial: (): SessionData => ({\n messages: [],\n }),\n })\n );\n\n // Only allow configured chat ID\n bot.use(async (ctx, next) => {\n const chatId = ctx.chat?.id?.toString();\n if (chatId !== env.TELEGRAM_CHAT_ID) {\n console.log(`Unauthorized access attempt from chat ID: ${chatId}`);\n return;\n }\n await next();\n });\n\n // Command handlers\n bot.command(\"start\", async (ctx) => {\n await ctx.reply(\n `Hello! I'm OpenSentinel, your personal AI assistant with JARVIS-like capabilities.\n\nI can:\n• Chat and answer questions using Claude AI\n• Execute shell commands on your system\n• Read and write files\n• Search the web\n• Remember important information\n• Set reminders\n\nSend me a message or voice note to get started!`\n );\n });\n\n bot.command(\"clear\", async (ctx) => {\n ctx.session.messages = [];\n await ctx.reply(\"✓ Conversation history cleared.\");\n });\n\n bot.command(\"remind\", async (ctx) => {\n const text = ctx.message?.text?.replace(\"/remind\", \"\").trim();\n\n if (!text) {\n await ctx.reply(\n \"Usage: /remind <time> <message>\\n\\nExamples:\\n• /remind 5m Check the oven\\n• /remind 1h Call mom\\n• /remind 30s Test reminder\"\n );\n return;\n }\n\n // Parse time and message\n const match = text.match(/^(\\d+)(s|m|h)\\s+(.+)$/i);\n if (!match) {\n await ctx.reply(\n \"Invalid format. Use: /remind <number><s/m/h> <message>\\n\\nExample: /remind 5m Check the oven\"\n );\n return;\n }\n\n const [, amount, unit, message] = match;\n const multipliers: Record<string, number> = {\n s: 1000,\n m: 60 * 1000,\n h: 60 * 60 * 1000,\n };\n const delayMs = parseInt(amount) * multipliers[unit.toLowerCase()];\n\n try {\n await scheduleReminder(message, delayMs, ctx.chat?.id?.toString());\n const timeStr = unit === \"s\" ? \"seconds\" : unit === \"m\" ? \"minutes\" : \"hours\";\n await ctx.reply(`✓ Reminder set for ${amount} ${timeStr}: \"${message}\"`);\n } catch (error) {\n await ctx.reply(\"Sorry, I couldn't set the reminder. Please try again.\");\n }\n });\n\n bot.command(\"help\", async (ctx) => {\n await ctx.reply(\n `*OpenSentinel Commands*\n\n/start - Welcome message\n/clear - Clear conversation history\n/remind <time> <message> - Set a reminder\n/help - Show this help\n\n*Features*\n• Send text messages for AI chat\n• Send voice messages for voice interaction\n• Ask me to run commands, search the web, or manage files\n\n*Examples*\n• \"What's the weather like?\"\n• \"List files in my Downloads folder\"\n• \"Search for the latest news about AI\"\n• /remind 5m Take a break`,\n { parse_mode: \"Markdown\" }\n );\n });\n\n // Message handlers\n bot.on(\"message:text\", handleMessage);\n bot.on(\"message:voice\", handleVoice);\n\n // Error handling\n bot.catch((err) => {\n console.error(\"Bot error:\", err);\n });\n\n return bot;\n}\n","import { InputFile } from \"grammy\";\nimport type { SentinelContext } from \"./bot\";\nimport { chatWithTools, type Message } from \"../../core/brain\";\nimport { transcribeAudio } from \"../../outputs/stt\";\nimport { textToSpeech } from \"../../outputs/tts\";\n\nconst MAX_HISTORY = 20; // Keep last 20 messages for context\n\nexport async function handleMessage(ctx: SentinelContext) {\n const text = ctx.message?.text;\n if (!text) return;\n\n // Add user message to history\n ctx.session.messages.push({ role: \"user\", content: text });\n\n // Trim history if too long\n if (ctx.session.messages.length > MAX_HISTORY) {\n ctx.session.messages = ctx.session.messages.slice(-MAX_HISTORY);\n }\n\n // Show typing indicator\n await ctx.replyWithChatAction(\"typing\");\n\n try {\n // Use chatWithTools for full capability\n const response = await chatWithTools(\n ctx.session.messages as Message[],\n ctx.chat?.id?.toString(),\n async () => {\n // Keep typing indicator alive during tool use\n await ctx.replyWithChatAction(\"typing\");\n }\n );\n\n // Add assistant response to history\n ctx.session.messages.push({ role: \"assistant\", content: response.content });\n\n // Build response with tool usage info\n let finalResponse = response.content;\n if (response.toolsUsed && response.toolsUsed.length > 0) {\n const toolList = [...new Set(response.toolsUsed)].join(\", \");\n finalResponse = `🔧 _Used: ${toolList}_\\n\\n${response.content}`;\n }\n\n // Send response (split if too long for Telegram)\n await sendResponse(ctx, finalResponse);\n\n console.log(\n `[Telegram] Processed message. Tokens: ${response.inputTokens}/${response.outputTokens}` +\n (response.toolsUsed ? ` Tools: ${response.toolsUsed.join(\", \")}` : \"\")\n );\n } catch (error) {\n console.error(\"Error processing message:\", error);\n const errMsg = error instanceof Error ? error.message : String(error);\n if (errMsg.includes(\"credit balance is too low\")) {\n await ctx.reply(\n \"⚠️ The AI service is temporarily unavailable due to API billing. The admin has been notified.\"\n );\n } else if (errMsg.includes(\"rate_limit\") || errMsg.includes(\"429\")) {\n await ctx.reply(\n \"⏳ Too many requests — please wait a moment and try again.\"\n );\n } else {\n await ctx.reply(\n \"Sorry, I encountered an error processing your message. Please try again.\"\n );\n }\n }\n}\n\nexport async function handleVoice(ctx: SentinelContext) {\n const voice = ctx.message?.voice;\n if (!voice) return;\n\n await ctx.replyWithChatAction(\"typing\");\n\n try {\n // Get voice file\n const file = await ctx.getFile();\n const fileUrl = `https://api.telegram.org/file/bot${process.env.TELEGRAM_BOT_TOKEN}/${file.file_path}`;\n\n // Download and transcribe\n const response = await fetch(fileUrl);\n const audioBuffer = await response.arrayBuffer();\n\n const transcription = await transcribeAudio(Buffer.from(audioBuffer));\n\n if (!transcription) {\n await ctx.reply(\"Sorry, I couldn't transcribe that voice message.\");\n return;\n }\n\n // Show what was transcribed\n await ctx.reply(`🎤 _\"${transcription}\"_`, { parse_mode: \"Markdown\" });\n\n // Process as text message\n ctx.session.messages.push({ role: \"user\", content: transcription });\n\n if (ctx.session.messages.length > MAX_HISTORY) {\n ctx.session.messages = ctx.session.messages.slice(-MAX_HISTORY);\n }\n\n await ctx.replyWithChatAction(\"typing\");\n\n const aiResponse = await chatWithTools(\n ctx.session.messages as Message[],\n ctx.chat?.id?.toString()\n );\n ctx.session.messages.push({\n role: \"assistant\",\n content: aiResponse.content,\n });\n\n // Send text response first\n await sendResponse(ctx, aiResponse.content);\n\n // Also send voice response if text is short enough\n if (aiResponse.content.length < 1000 && aiResponse.content.length > 10) {\n try {\n await ctx.replyWithChatAction(\"record_voice\");\n const audioBuffer = await textToSpeech(aiResponse.content);\n if (audioBuffer) {\n await ctx.replyWithVoice(new InputFile(audioBuffer, \"response.ogg\"));\n }\n } catch (ttsError) {\n console.error(\"TTS error:\", ttsError);\n // Don't fail if TTS fails, text was already sent\n }\n }\n\n console.log(\n `[Telegram] Processed voice message. Tokens: ${aiResponse.inputTokens}/${aiResponse.outputTokens}`\n );\n } catch (error) {\n console.error(\"Error processing voice message:\", error);\n await ctx.reply(\n \"Sorry, I encountered an error processing your voice message. Please try again.\"\n );\n }\n}\n\n// Helper to send response, handling Markdown errors\nasync function sendResponse(ctx: SentinelContext, text: string) {\n const maxLength = 4096;\n\n // Try with Markdown first\n try {\n if (text.length <= maxLength) {\n await ctx.reply(text, { parse_mode: \"Markdown\" });\n } else {\n const chunks = splitMessage(text, maxLength);\n for (const chunk of chunks) {\n await ctx.reply(chunk, { parse_mode: \"Markdown\" });\n }\n }\n } catch {\n // If Markdown fails, send as plain text\n if (text.length <= maxLength) {\n await ctx.reply(text);\n } else {\n const chunks = splitMessage(text, maxLength);\n for (const chunk of chunks) {\n await ctx.reply(chunk);\n }\n }\n }\n}\n\nfunction splitMessage(text: string, maxLength: number): string[] {\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= maxLength) {\n chunks.push(remaining);\n break;\n }\n\n // Find a good break point (newline or space)\n let breakPoint = remaining.lastIndexOf(\"\\n\", maxLength);\n if (breakPoint === -1 || breakPoint < maxLength / 2) {\n breakPoint = remaining.lastIndexOf(\" \", maxLength);\n }\n if (breakPoint === -1 || breakPoint < maxLength / 2) {\n breakPoint = maxLength;\n }\n\n chunks.push(remaining.slice(0, breakPoint));\n remaining = remaining.slice(breakPoint).trim();\n }\n\n return chunks;\n}\n"],"mappings":"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","names":["audioBuffer"]}