@hailer/mcp 1.1.15 → 1.1.16

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 (544) hide show
  1. package/dist/agents/bot-manager.d.ts +48 -0
  2. package/dist/agents/bot-manager.d.ts.map +1 -0
  3. package/dist/agents/bot-manager.js +254 -0
  4. package/dist/agents/bot-manager.js.map +1 -0
  5. package/dist/agents/bug-fixer/ai.d.ts +80 -0
  6. package/dist/agents/bug-fixer/ai.d.ts.map +1 -0
  7. package/dist/agents/bug-fixer/ai.js +466 -0
  8. package/dist/agents/bug-fixer/ai.js.map +1 -0
  9. package/dist/agents/bug-fixer/bot.d.ts +92 -0
  10. package/dist/agents/bug-fixer/bot.d.ts.map +1 -0
  11. package/dist/agents/bug-fixer/bot.js +687 -0
  12. package/dist/agents/bug-fixer/bot.js.map +1 -0
  13. package/dist/agents/bug-fixer/config.d.ts +21 -0
  14. package/dist/agents/bug-fixer/config.d.ts.map +1 -0
  15. package/dist/agents/bug-fixer/config.js +218 -0
  16. package/dist/agents/bug-fixer/config.js.map +1 -0
  17. package/dist/agents/bug-fixer/files.d.ts +67 -0
  18. package/dist/agents/bug-fixer/files.d.ts.map +1 -0
  19. package/dist/agents/bug-fixer/files.js +386 -0
  20. package/dist/agents/bug-fixer/files.js.map +1 -0
  21. package/dist/agents/bug-fixer/git.d.ts +48 -0
  22. package/dist/agents/bug-fixer/git.d.ts.map +1 -0
  23. package/dist/agents/bug-fixer/git.js +298 -0
  24. package/dist/agents/bug-fixer/git.js.map +1 -0
  25. package/dist/agents/bug-fixer/index.d.ts +103 -0
  26. package/dist/agents/bug-fixer/index.d.ts.map +1 -0
  27. package/dist/agents/bug-fixer/index.js +262 -0
  28. package/dist/agents/bug-fixer/index.js.map +1 -0
  29. package/dist/agents/bug-fixer/lsp.d.ts +113 -0
  30. package/dist/agents/bug-fixer/lsp.d.ts.map +1 -0
  31. package/dist/agents/bug-fixer/lsp.js +485 -0
  32. package/dist/agents/bug-fixer/lsp.js.map +1 -0
  33. package/dist/agents/bug-fixer/monitor.d.ts +123 -0
  34. package/dist/agents/bug-fixer/monitor.d.ts.map +1 -0
  35. package/dist/agents/bug-fixer/monitor.js +629 -0
  36. package/dist/agents/bug-fixer/monitor.js.map +1 -0
  37. package/dist/agents/bug-fixer/prompt.d.ts +5 -0
  38. package/dist/agents/bug-fixer/prompt.d.ts.map +1 -0
  39. package/dist/agents/bug-fixer/prompt.js +94 -0
  40. package/dist/agents/bug-fixer/prompt.js.map +1 -0
  41. package/dist/agents/bug-fixer/registries/pending-classification.d.ts +28 -0
  42. package/dist/agents/bug-fixer/registries/pending-classification.d.ts.map +1 -0
  43. package/dist/agents/bug-fixer/registries/pending-classification.js +50 -0
  44. package/dist/agents/bug-fixer/registries/pending-classification.js.map +1 -0
  45. package/dist/agents/bug-fixer/registries/pending-fix.d.ts +33 -0
  46. package/dist/agents/bug-fixer/registries/pending-fix.d.ts.map +1 -0
  47. package/dist/agents/bug-fixer/registries/pending-fix.js +64 -0
  48. package/dist/agents/bug-fixer/registries/pending-fix.js.map +1 -0
  49. package/dist/agents/bug-fixer/registries/pending.d.ts +27 -0
  50. package/dist/agents/bug-fixer/registries/pending.d.ts.map +1 -0
  51. package/dist/agents/bug-fixer/registries/pending.js +49 -0
  52. package/dist/agents/bug-fixer/registries/pending.js.map +1 -0
  53. package/dist/agents/bug-fixer/specialist-daemon.d.ts +88 -0
  54. package/dist/agents/bug-fixer/specialist-daemon.d.ts.map +1 -0
  55. package/dist/agents/bug-fixer/specialist-daemon.js +431 -0
  56. package/dist/agents/bug-fixer/specialist-daemon.js.map +1 -0
  57. package/dist/agents/bug-fixer/specialist.d.ts +47 -0
  58. package/dist/agents/bug-fixer/specialist.d.ts.map +1 -0
  59. package/dist/agents/bug-fixer/specialist.js +327 -0
  60. package/dist/agents/bug-fixer/specialist.js.map +1 -0
  61. package/dist/agents/bug-fixer/types.d.ts +123 -0
  62. package/dist/agents/bug-fixer/types.d.ts.map +1 -0
  63. package/dist/agents/bug-fixer/types.js +9 -0
  64. package/dist/agents/bug-fixer/types.js.map +1 -0
  65. package/dist/agents/factory.d.ts +172 -0
  66. package/dist/agents/factory.d.ts.map +1 -0
  67. package/dist/agents/factory.js +706 -0
  68. package/dist/agents/factory.js.map +1 -0
  69. package/dist/agents/hailer-expert/index.d.ts +8 -0
  70. package/dist/agents/hailer-expert/index.d.ts.map +1 -0
  71. package/dist/agents/hailer-expert/index.js +14 -0
  72. package/dist/agents/hailer-expert/index.js.map +1 -0
  73. package/dist/agents/hal/daemon.d.ts +174 -0
  74. package/dist/agents/hal/daemon.d.ts.map +1 -0
  75. package/dist/agents/hal/daemon.js +1385 -0
  76. package/dist/agents/hal/daemon.js.map +1 -0
  77. package/dist/agents/hal/definitions.d.ts +42 -0
  78. package/dist/agents/hal/definitions.d.ts.map +1 -0
  79. package/dist/agents/hal/definitions.js +300 -0
  80. package/dist/agents/hal/definitions.js.map +1 -0
  81. package/dist/agents/hal/index.d.ts +3 -0
  82. package/dist/agents/hal/index.d.ts.map +1 -0
  83. package/dist/agents/hal/index.js +8 -0
  84. package/dist/agents/hal/index.js.map +1 -0
  85. package/dist/agents/index.d.ts +18 -0
  86. package/dist/agents/index.d.ts.map +1 -0
  87. package/dist/agents/index.js +48 -0
  88. package/dist/agents/index.js.map +1 -0
  89. package/dist/agents/shared/base.d.ts +253 -0
  90. package/dist/agents/shared/base.d.ts.map +1 -0
  91. package/dist/agents/shared/base.js +1122 -0
  92. package/dist/agents/shared/base.js.map +1 -0
  93. package/dist/agents/shared/schemas/action-schema.d.ts +62 -0
  94. package/dist/agents/shared/schemas/action-schema.d.ts.map +1 -0
  95. package/dist/agents/shared/schemas/action-schema.js +483 -0
  96. package/dist/agents/shared/schemas/action-schema.js.map +1 -0
  97. package/dist/agents/shared/services/agent-registry.d.ts +108 -0
  98. package/dist/agents/shared/services/agent-registry.d.ts.map +1 -0
  99. package/dist/agents/shared/services/agent-registry.js +469 -0
  100. package/dist/agents/shared/services/agent-registry.js.map +1 -0
  101. package/dist/agents/shared/services/conversation-manager.d.ts +57 -0
  102. package/dist/agents/shared/services/conversation-manager.d.ts.map +1 -0
  103. package/dist/agents/shared/services/conversation-manager.js +168 -0
  104. package/dist/agents/shared/services/conversation-manager.js.map +1 -0
  105. package/dist/agents/shared/services/mcp-client.d.ts +56 -0
  106. package/dist/agents/shared/services/mcp-client.d.ts.map +1 -0
  107. package/dist/agents/shared/services/mcp-client.js +124 -0
  108. package/dist/agents/shared/services/mcp-client.js.map +1 -0
  109. package/dist/agents/shared/services/message-classifier.d.ts +37 -0
  110. package/dist/agents/shared/services/message-classifier.d.ts.map +1 -0
  111. package/dist/agents/shared/services/message-classifier.js +203 -0
  112. package/dist/agents/shared/services/message-classifier.js.map +1 -0
  113. package/dist/agents/shared/services/message-formatter.d.ts +89 -0
  114. package/dist/agents/shared/services/message-formatter.d.ts.map +1 -0
  115. package/dist/agents/shared/services/message-formatter.js +390 -0
  116. package/dist/agents/shared/services/message-formatter.js.map +1 -0
  117. package/dist/agents/shared/services/session-logger.d.ts +162 -0
  118. package/dist/agents/shared/services/session-logger.d.ts.map +1 -0
  119. package/dist/agents/shared/services/session-logger.js +724 -0
  120. package/dist/agents/shared/services/session-logger.js.map +1 -0
  121. package/dist/agents/shared/services/structured-output-executor.d.ts +88 -0
  122. package/dist/agents/shared/services/structured-output-executor.d.ts.map +1 -0
  123. package/dist/agents/shared/services/structured-output-executor.js +296 -0
  124. package/dist/agents/shared/services/structured-output-executor.js.map +1 -0
  125. package/dist/agents/shared/services/token-billing.d.ts +72 -0
  126. package/dist/agents/shared/services/token-billing.d.ts.map +1 -0
  127. package/dist/agents/shared/services/token-billing.js +198 -0
  128. package/dist/agents/shared/services/token-billing.js.map +1 -0
  129. package/dist/agents/shared/services/tool-executor.d.ts +43 -0
  130. package/dist/agents/shared/services/tool-executor.d.ts.map +1 -0
  131. package/dist/agents/shared/services/tool-executor.js +175 -0
  132. package/dist/agents/shared/services/tool-executor.js.map +1 -0
  133. package/dist/agents/shared/services/typing-indicator.d.ts +24 -0
  134. package/dist/agents/shared/services/typing-indicator.d.ts.map +1 -0
  135. package/dist/agents/shared/services/typing-indicator.js +54 -0
  136. package/dist/agents/shared/services/typing-indicator.js.map +1 -0
  137. package/dist/agents/shared/services/workspace-schema-cache.d.ts +122 -0
  138. package/dist/agents/shared/services/workspace-schema-cache.d.ts.map +1 -0
  139. package/dist/agents/shared/services/workspace-schema-cache.js +507 -0
  140. package/dist/agents/shared/services/workspace-schema-cache.js.map +1 -0
  141. package/dist/agents/shared/specialist.d.ts +91 -0
  142. package/dist/agents/shared/specialist.d.ts.map +1 -0
  143. package/dist/agents/shared/specialist.js +399 -0
  144. package/dist/agents/shared/specialist.js.map +1 -0
  145. package/dist/agents/shared/tool-schema-loader.d.ts +65 -0
  146. package/dist/agents/shared/tool-schema-loader.d.ts.map +1 -0
  147. package/dist/agents/shared/tool-schema-loader.js +238 -0
  148. package/dist/agents/shared/tool-schema-loader.js.map +1 -0
  149. package/dist/agents/shared/types.d.ts +190 -0
  150. package/dist/agents/shared/types.d.ts.map +1 -0
  151. package/dist/agents/shared/types.js +13 -0
  152. package/dist/agents/shared/types.js.map +1 -0
  153. package/dist/app.d.ts.map +1 -0
  154. package/dist/app.js.map +1 -0
  155. package/dist/bot/bot-config.d.ts.map +1 -0
  156. package/dist/bot/bot-config.js.map +1 -0
  157. package/dist/bot/bot-manager.d.ts.map +1 -0
  158. package/dist/bot/bot-manager.js.map +1 -0
  159. package/dist/bot/bot.d.ts.map +1 -0
  160. package/dist/bot/bot.js.map +1 -0
  161. package/dist/bot/operation-logger.d.ts.map +1 -0
  162. package/dist/bot/operation-logger.js.map +1 -0
  163. package/dist/bot/services/__tests__/permission-guard.test.d.ts +2 -0
  164. package/dist/bot/services/__tests__/permission-guard.test.d.ts.map +1 -0
  165. package/dist/bot/services/__tests__/permission-guard.test.js +357 -0
  166. package/dist/bot/services/__tests__/permission-guard.test.js.map +1 -0
  167. package/dist/bot/services/conversation-manager.d.ts.map +1 -0
  168. package/dist/bot/services/conversation-manager.js.map +1 -0
  169. package/dist/bot/services/index.d.ts.map +1 -0
  170. package/dist/bot/services/index.js.map +1 -0
  171. package/dist/bot/services/message-classifier.d.ts.map +1 -0
  172. package/dist/bot/services/message-classifier.js.map +1 -0
  173. package/dist/bot/services/message-formatter.d.ts.map +1 -0
  174. package/dist/bot/services/message-formatter.js.map +1 -0
  175. package/dist/bot/services/permission-guard.d.ts.map +1 -0
  176. package/dist/bot/services/permission-guard.js.map +1 -0
  177. package/dist/bot/services/session-logger.d.ts.map +1 -0
  178. package/dist/bot/services/session-logger.js.map +1 -0
  179. package/dist/bot/services/token-billing.d.ts.map +1 -0
  180. package/dist/bot/services/token-billing.js.map +1 -0
  181. package/dist/bot/services/types.d.ts.map +1 -0
  182. package/dist/bot/services/types.js.map +1 -0
  183. package/dist/bot/services/typing-indicator.d.ts.map +1 -0
  184. package/dist/bot/services/typing-indicator.js.map +1 -0
  185. package/dist/bot/services/workspace-schema-cache.d.ts.map +1 -0
  186. package/dist/bot/services/workspace-schema-cache.js.map +1 -0
  187. package/dist/bot/tool-executor.d.ts.map +1 -0
  188. package/dist/bot/tool-executor.js.map +1 -0
  189. package/dist/bot/workspace-overview.d.ts.map +1 -0
  190. package/dist/bot/workspace-overview.js.map +1 -0
  191. package/dist/bot-config/constants.d.ts +42 -0
  192. package/dist/bot-config/constants.d.ts.map +1 -0
  193. package/dist/bot-config/constants.js +118 -0
  194. package/dist/bot-config/constants.js.map +1 -0
  195. package/dist/bot-config/context.d.ts +157 -0
  196. package/dist/bot-config/context.d.ts.map +1 -0
  197. package/dist/bot-config/context.js +475 -0
  198. package/dist/bot-config/context.js.map +1 -0
  199. package/dist/bot-config/index.d.ts +21 -0
  200. package/dist/bot-config/index.d.ts.map +1 -0
  201. package/dist/bot-config/index.js +104 -0
  202. package/dist/bot-config/index.js.map +1 -0
  203. package/dist/bot-config/loader.d.ts +28 -0
  204. package/dist/bot-config/loader.d.ts.map +1 -0
  205. package/dist/bot-config/loader.js +194 -0
  206. package/dist/bot-config/loader.js.map +1 -0
  207. package/dist/bot-config/persistence.d.ts +68 -0
  208. package/dist/bot-config/persistence.d.ts.map +1 -0
  209. package/dist/bot-config/persistence.js +261 -0
  210. package/dist/bot-config/persistence.js.map +1 -0
  211. package/dist/bot-config/state.d.ts +56 -0
  212. package/dist/bot-config/state.d.ts.map +1 -0
  213. package/dist/bot-config/state.js +197 -0
  214. package/dist/bot-config/state.js.map +1 -0
  215. package/dist/bot-config/tools.d.ts +28 -0
  216. package/dist/bot-config/tools.d.ts.map +1 -0
  217. package/dist/bot-config/tools.js +279 -0
  218. package/dist/bot-config/tools.js.map +1 -0
  219. package/dist/bot-config/types.d.ts +45 -0
  220. package/dist/bot-config/types.d.ts.map +1 -0
  221. package/dist/bot-config/types.js +9 -0
  222. package/dist/bot-config/types.js.map +1 -0
  223. package/dist/bot-config/webhooks.d.ts +27 -0
  224. package/dist/bot-config/webhooks.d.ts.map +1 -0
  225. package/dist/bot-config/webhooks.js +212 -0
  226. package/dist/bot-config/webhooks.js.map +1 -0
  227. package/dist/cli.d.ts.map +1 -0
  228. package/dist/cli.js.map +1 -0
  229. package/dist/client/agents/base.d.ts +207 -0
  230. package/dist/client/agents/base.d.ts.map +1 -0
  231. package/dist/client/agents/base.js +744 -0
  232. package/dist/client/agents/base.js.map +1 -0
  233. package/dist/client/agents/definitions.d.ts +53 -0
  234. package/dist/client/agents/definitions.d.ts.map +1 -0
  235. package/dist/client/agents/definitions.js +263 -0
  236. package/dist/client/agents/definitions.js.map +1 -0
  237. package/dist/client/agents/orchestrator.d.ts +141 -0
  238. package/dist/client/agents/orchestrator.d.ts.map +1 -0
  239. package/dist/client/agents/orchestrator.js +1062 -0
  240. package/dist/client/agents/orchestrator.js.map +1 -0
  241. package/dist/client/agents/specialist.d.ts +86 -0
  242. package/dist/client/agents/specialist.d.ts.map +1 -0
  243. package/dist/client/agents/specialist.js +340 -0
  244. package/dist/client/agents/specialist.js.map +1 -0
  245. package/dist/client/bot-entrypoint.d.ts +7 -0
  246. package/dist/client/bot-entrypoint.d.ts.map +1 -0
  247. package/dist/client/bot-entrypoint.js +103 -0
  248. package/dist/client/bot-entrypoint.js.map +1 -0
  249. package/dist/client/bot-manager.d.ts +44 -0
  250. package/dist/client/bot-manager.d.ts.map +1 -0
  251. package/dist/client/bot-manager.js +173 -0
  252. package/dist/client/bot-manager.js.map +1 -0
  253. package/dist/client/bot-runner.d.ts +35 -0
  254. package/dist/client/bot-runner.d.ts.map +1 -0
  255. package/dist/client/bot-runner.js +188 -0
  256. package/dist/client/bot-runner.js.map +1 -0
  257. package/dist/client/chat-agent-daemon.d.ts +464 -0
  258. package/dist/client/chat-agent-daemon.d.ts.map +1 -0
  259. package/dist/client/chat-agent-daemon.js +1774 -0
  260. package/dist/client/chat-agent-daemon.js.map +1 -0
  261. package/dist/client/daemon-factory.d.ts +106 -0
  262. package/dist/client/daemon-factory.d.ts.map +1 -0
  263. package/dist/client/daemon-factory.js +301 -0
  264. package/dist/client/daemon-factory.js.map +1 -0
  265. package/dist/client/factory.d.ts +111 -0
  266. package/dist/client/factory.d.ts.map +1 -0
  267. package/dist/client/factory.js +314 -0
  268. package/dist/client/factory.js.map +1 -0
  269. package/dist/client/index.d.ts +17 -0
  270. package/dist/client/index.d.ts.map +1 -0
  271. package/dist/client/index.js +38 -0
  272. package/dist/client/index.js.map +1 -0
  273. package/dist/client/multi-bot-manager.d.ts +42 -0
  274. package/dist/client/multi-bot-manager.d.ts.map +1 -0
  275. package/dist/client/multi-bot-manager.js +161 -0
  276. package/dist/client/multi-bot-manager.js.map +1 -0
  277. package/dist/client/orchestrator-daemon.d.ts +87 -0
  278. package/dist/client/orchestrator-daemon.d.ts.map +1 -0
  279. package/dist/client/orchestrator-daemon.js +444 -0
  280. package/dist/client/orchestrator-daemon.js.map +1 -0
  281. package/dist/client/server.d.ts +8 -0
  282. package/dist/client/server.d.ts.map +1 -0
  283. package/dist/client/server.js +251 -0
  284. package/dist/client/server.js.map +1 -0
  285. package/dist/client/services/agent-registry.d.ts +108 -0
  286. package/dist/client/services/agent-registry.d.ts.map +1 -0
  287. package/dist/client/services/agent-registry.js +630 -0
  288. package/dist/client/services/agent-registry.js.map +1 -0
  289. package/dist/client/services/conversation-manager.d.ts +50 -0
  290. package/dist/client/services/conversation-manager.d.ts.map +1 -0
  291. package/dist/client/services/conversation-manager.js +136 -0
  292. package/dist/client/services/conversation-manager.js.map +1 -0
  293. package/dist/client/services/mcp-client.d.ts +48 -0
  294. package/dist/client/services/mcp-client.d.ts.map +1 -0
  295. package/dist/client/services/mcp-client.js +105 -0
  296. package/dist/client/services/mcp-client.js.map +1 -0
  297. package/dist/client/services/message-classifier.d.ts +37 -0
  298. package/dist/client/services/message-classifier.d.ts.map +1 -0
  299. package/dist/client/services/message-classifier.js +187 -0
  300. package/dist/client/services/message-classifier.js.map +1 -0
  301. package/dist/client/services/message-formatter.d.ts +84 -0
  302. package/dist/client/services/message-formatter.d.ts.map +1 -0
  303. package/dist/client/services/message-formatter.js +353 -0
  304. package/dist/client/services/message-formatter.js.map +1 -0
  305. package/dist/client/services/session-logger.d.ts +106 -0
  306. package/dist/client/services/session-logger.d.ts.map +1 -0
  307. package/dist/client/services/session-logger.js +446 -0
  308. package/dist/client/services/session-logger.js.map +1 -0
  309. package/dist/client/services/tool-executor.d.ts +41 -0
  310. package/dist/client/services/tool-executor.d.ts.map +1 -0
  311. package/dist/client/services/tool-executor.js +169 -0
  312. package/dist/client/services/tool-executor.js.map +1 -0
  313. package/dist/client/services/workspace-schema-cache.d.ts +149 -0
  314. package/dist/client/services/workspace-schema-cache.d.ts.map +1 -0
  315. package/dist/client/services/workspace-schema-cache.js +732 -0
  316. package/dist/client/services/workspace-schema-cache.js.map +1 -0
  317. package/dist/client/specialist-daemon.d.ts +77 -0
  318. package/dist/client/specialist-daemon.d.ts.map +1 -0
  319. package/dist/client/specialist-daemon.js +197 -0
  320. package/dist/client/specialist-daemon.js.map +1 -0
  321. package/dist/client/specialists.d.ts +53 -0
  322. package/dist/client/specialists.d.ts.map +1 -0
  323. package/dist/client/specialists.js +178 -0
  324. package/dist/client/specialists.js.map +1 -0
  325. package/dist/client/tool-schema-loader.d.ts +62 -0
  326. package/dist/client/tool-schema-loader.d.ts.map +1 -0
  327. package/dist/client/tool-schema-loader.js +232 -0
  328. package/dist/client/tool-schema-loader.js.map +1 -0
  329. package/dist/client/types.d.ts +327 -0
  330. package/dist/client/types.d.ts.map +1 -0
  331. package/dist/client/types.js +121 -0
  332. package/dist/client/types.js.map +1 -0
  333. package/dist/commands/seed-config.d.ts +9 -0
  334. package/dist/commands/seed-config.d.ts.map +1 -0
  335. package/dist/commands/seed-config.js +392 -0
  336. package/dist/commands/seed-config.js.map +1 -0
  337. package/dist/commands/setup.d.ts +11 -0
  338. package/dist/commands/setup.d.ts.map +1 -0
  339. package/dist/commands/setup.js +320 -0
  340. package/dist/commands/setup.js.map +1 -0
  341. package/dist/config.d.ts.map +1 -0
  342. package/dist/config.js.map +1 -0
  343. package/dist/core.d.ts.map +1 -0
  344. package/dist/core.js.map +1 -0
  345. package/dist/lib/discussion-lock.d.ts.map +1 -0
  346. package/dist/lib/discussion-lock.js.map +1 -0
  347. package/dist/lib/logger.d.ts.map +1 -0
  348. package/dist/lib/logger.js.map +1 -0
  349. package/dist/lib/request-logger.d.ts.map +1 -0
  350. package/dist/lib/request-logger.js.map +1 -0
  351. package/dist/mcp/UserContextCache.d.ts.map +1 -0
  352. package/dist/mcp/UserContextCache.js.map +1 -0
  353. package/dist/mcp/auth.d.ts.map +1 -0
  354. package/dist/mcp/auth.js.map +1 -0
  355. package/dist/mcp/hailer-clients.d.ts.map +1 -0
  356. package/dist/mcp/hailer-clients.js.map +1 -0
  357. package/dist/mcp/session-store.d.ts.map +1 -0
  358. package/dist/mcp/session-store.js.map +1 -0
  359. package/dist/mcp/signal-handler.d.ts.map +1 -0
  360. package/dist/mcp/signal-handler.js.map +1 -0
  361. package/dist/mcp/tool-registry.d.ts.map +1 -0
  362. package/dist/mcp/tool-registry.js.map +1 -0
  363. package/dist/mcp/tools/__tests__/discussion-forward.test.d.ts +2 -0
  364. package/dist/mcp/tools/__tests__/discussion-forward.test.d.ts.map +1 -0
  365. package/dist/mcp/tools/__tests__/discussion-forward.test.js +218 -0
  366. package/dist/mcp/tools/__tests__/discussion-forward.test.js.map +1 -0
  367. package/dist/mcp/tools/activity.d.ts.map +1 -0
  368. package/dist/mcp/tools/activity.js.map +1 -0
  369. package/dist/mcp/tools/app-core.d.ts.map +1 -0
  370. package/dist/mcp/tools/app-core.js.map +1 -0
  371. package/dist/mcp/tools/app-marketplace.d.ts.map +1 -0
  372. package/dist/mcp/tools/app-marketplace.js.map +1 -0
  373. package/dist/mcp/tools/app-member.d.ts.map +1 -0
  374. package/dist/mcp/tools/app-member.js.map +1 -0
  375. package/dist/mcp/tools/app-scaffold.d.ts.map +1 -0
  376. package/dist/mcp/tools/app-scaffold.js.map +1 -0
  377. package/dist/mcp/tools/app.d.ts.map +1 -0
  378. package/dist/mcp/tools/app.js.map +1 -0
  379. package/dist/mcp/tools/bot-config/constants.d.ts.map +1 -0
  380. package/dist/mcp/tools/bot-config/constants.js.map +1 -0
  381. package/dist/mcp/tools/bot-config/core.d.ts.map +1 -0
  382. package/dist/mcp/tools/bot-config/core.js.map +1 -0
  383. package/dist/mcp/tools/bot-config/index.d.ts.map +1 -0
  384. package/dist/mcp/tools/bot-config/index.js.map +1 -0
  385. package/dist/mcp/tools/bot-config/tools.d.ts.map +1 -0
  386. package/dist/mcp/tools/bot-config/tools.js.map +1 -0
  387. package/dist/mcp/tools/bot-config/types.d.ts.map +1 -0
  388. package/dist/mcp/tools/bot-config/types.js.map +1 -0
  389. package/dist/mcp/tools/bug-fixer-tools.d.ts.map +1 -0
  390. package/dist/mcp/tools/bug-fixer-tools.js.map +1 -0
  391. package/dist/mcp/tools/company.d.ts.map +1 -0
  392. package/dist/mcp/tools/company.js.map +1 -0
  393. package/dist/mcp/tools/discussion.d.ts.map +1 -0
  394. package/dist/mcp/tools/discussion.js.map +1 -0
  395. package/dist/mcp/tools/document.d.ts.map +1 -0
  396. package/dist/mcp/tools/document.js.map +1 -0
  397. package/dist/mcp/tools/file.d.ts.map +1 -0
  398. package/dist/mcp/tools/file.js.map +1 -0
  399. package/dist/mcp/tools/insight.d.ts.map +1 -0
  400. package/dist/mcp/tools/insight.js.map +1 -0
  401. package/dist/mcp/tools/investigate.d.ts.map +1 -0
  402. package/dist/mcp/tools/investigate.js.map +1 -0
  403. package/dist/mcp/tools/user.d.ts.map +1 -0
  404. package/dist/mcp/tools/user.js.map +1 -0
  405. package/dist/mcp/tools/workflow-permissions.d.ts.map +1 -0
  406. package/dist/mcp/tools/workflow-permissions.js.map +1 -0
  407. package/dist/mcp/tools/workflow.d.ts.map +1 -0
  408. package/dist/mcp/tools/workflow.js.map +1 -0
  409. package/dist/mcp/utils/api-errors.d.ts.map +1 -0
  410. package/dist/mcp/utils/api-errors.js.map +1 -0
  411. package/dist/mcp/utils/data-transformers.d.ts.map +1 -0
  412. package/dist/mcp/utils/data-transformers.js.map +1 -0
  413. package/dist/mcp/utils/file-upload.d.ts.map +1 -0
  414. package/dist/mcp/utils/file-upload.js.map +1 -0
  415. package/dist/mcp/utils/hailer-api-client.d.ts.map +1 -0
  416. package/dist/mcp/utils/hailer-api-client.js.map +1 -0
  417. package/dist/mcp/utils/index.d.ts.map +1 -0
  418. package/dist/mcp/utils/index.js.map +1 -0
  419. package/dist/mcp/utils/logger.d.ts.map +1 -0
  420. package/dist/mcp/utils/logger.js.map +1 -0
  421. package/dist/mcp/utils/pagination.d.ts.map +1 -0
  422. package/dist/mcp/utils/pagination.js.map +1 -0
  423. package/dist/mcp/utils/response-builder.d.ts.map +1 -0
  424. package/dist/mcp/utils/response-builder.js.map +1 -0
  425. package/dist/mcp/utils/role-utils.d.ts.map +1 -0
  426. package/dist/mcp/utils/role-utils.js.map +1 -0
  427. package/dist/mcp/utils/tool-helpers.d.ts.map +1 -0
  428. package/dist/mcp/utils/tool-helpers.js.map +1 -0
  429. package/dist/mcp/utils/types.d.ts.map +1 -0
  430. package/dist/mcp/utils/types.js.map +1 -0
  431. package/dist/mcp/webhook-handler.d.ts.map +1 -0
  432. package/dist/mcp/webhook-handler.js.map +1 -0
  433. package/dist/mcp/workspace-cache.d.ts.map +1 -0
  434. package/dist/mcp/workspace-cache.js.map +1 -0
  435. package/dist/mcp-server.d.ts.map +1 -0
  436. package/dist/mcp-server.js.map +1 -0
  437. package/dist/modules/bug-reports/bug-config.d.ts +25 -0
  438. package/dist/modules/bug-reports/bug-config.d.ts.map +1 -0
  439. package/dist/modules/bug-reports/bug-config.js +187 -0
  440. package/dist/modules/bug-reports/bug-config.js.map +1 -0
  441. package/dist/modules/bug-reports/bug-monitor.d.ts +108 -0
  442. package/dist/modules/bug-reports/bug-monitor.d.ts.map +1 -0
  443. package/dist/modules/bug-reports/bug-monitor.js +510 -0
  444. package/dist/modules/bug-reports/bug-monitor.js.map +1 -0
  445. package/dist/modules/bug-reports/giuseppe-agent.d.ts +58 -0
  446. package/dist/modules/bug-reports/giuseppe-agent.d.ts.map +1 -0
  447. package/dist/modules/bug-reports/giuseppe-agent.js +467 -0
  448. package/dist/modules/bug-reports/giuseppe-agent.js.map +1 -0
  449. package/dist/modules/bug-reports/giuseppe-ai.d.ts +83 -0
  450. package/dist/modules/bug-reports/giuseppe-ai.d.ts.map +1 -0
  451. package/dist/modules/bug-reports/giuseppe-ai.js +466 -0
  452. package/dist/modules/bug-reports/giuseppe-ai.js.map +1 -0
  453. package/dist/modules/bug-reports/giuseppe-bot.d.ts +110 -0
  454. package/dist/modules/bug-reports/giuseppe-bot.d.ts.map +1 -0
  455. package/dist/modules/bug-reports/giuseppe-bot.js +804 -0
  456. package/dist/modules/bug-reports/giuseppe-bot.js.map +1 -0
  457. package/dist/modules/bug-reports/giuseppe-daemon.d.ts +80 -0
  458. package/dist/modules/bug-reports/giuseppe-daemon.d.ts.map +1 -0
  459. package/dist/modules/bug-reports/giuseppe-daemon.js +617 -0
  460. package/dist/modules/bug-reports/giuseppe-daemon.js.map +1 -0
  461. package/dist/modules/bug-reports/giuseppe-files.d.ts +64 -0
  462. package/dist/modules/bug-reports/giuseppe-files.d.ts.map +1 -0
  463. package/dist/modules/bug-reports/giuseppe-files.js +375 -0
  464. package/dist/modules/bug-reports/giuseppe-files.js.map +1 -0
  465. package/dist/modules/bug-reports/giuseppe-git.d.ts +48 -0
  466. package/dist/modules/bug-reports/giuseppe-git.d.ts.map +1 -0
  467. package/dist/modules/bug-reports/giuseppe-git.js +298 -0
  468. package/dist/modules/bug-reports/giuseppe-git.js.map +1 -0
  469. package/dist/modules/bug-reports/giuseppe-lsp.d.ts +113 -0
  470. package/dist/modules/bug-reports/giuseppe-lsp.d.ts.map +1 -0
  471. package/dist/modules/bug-reports/giuseppe-lsp.js +485 -0
  472. package/dist/modules/bug-reports/giuseppe-lsp.js.map +1 -0
  473. package/dist/modules/bug-reports/giuseppe-prompt.d.ts +5 -0
  474. package/dist/modules/bug-reports/giuseppe-prompt.d.ts.map +1 -0
  475. package/dist/modules/bug-reports/giuseppe-prompt.js +94 -0
  476. package/dist/modules/bug-reports/giuseppe-prompt.js.map +1 -0
  477. package/dist/modules/bug-reports/index.d.ts +77 -0
  478. package/dist/modules/bug-reports/index.d.ts.map +1 -0
  479. package/dist/modules/bug-reports/index.js +215 -0
  480. package/dist/modules/bug-reports/index.js.map +1 -0
  481. package/dist/modules/bug-reports/pending-classification-registry.d.ts +28 -0
  482. package/dist/modules/bug-reports/pending-classification-registry.d.ts.map +1 -0
  483. package/dist/modules/bug-reports/pending-classification-registry.js +50 -0
  484. package/dist/modules/bug-reports/pending-classification-registry.js.map +1 -0
  485. package/dist/modules/bug-reports/pending-fix-registry.d.ts +30 -0
  486. package/dist/modules/bug-reports/pending-fix-registry.d.ts.map +1 -0
  487. package/dist/modules/bug-reports/pending-fix-registry.js +42 -0
  488. package/dist/modules/bug-reports/pending-fix-registry.js.map +1 -0
  489. package/dist/modules/bug-reports/pending-registry.d.ts +27 -0
  490. package/dist/modules/bug-reports/pending-registry.d.ts.map +1 -0
  491. package/dist/modules/bug-reports/pending-registry.js +49 -0
  492. package/dist/modules/bug-reports/pending-registry.js.map +1 -0
  493. package/dist/modules/bug-reports/types.d.ts +123 -0
  494. package/dist/modules/bug-reports/types.d.ts.map +1 -0
  495. package/dist/modules/bug-reports/types.js +9 -0
  496. package/dist/modules/bug-reports/types.js.map +1 -0
  497. package/dist/plugins/bug-fixer/index.d.ts.map +1 -0
  498. package/dist/plugins/bug-fixer/index.js.map +1 -0
  499. package/dist/plugins/bug-fixer/tools.d.ts.map +1 -0
  500. package/dist/plugins/bug-fixer/tools.js.map +1 -0
  501. package/dist/plugins/vipunen/__tests__/tools.test.d.ts +10 -0
  502. package/dist/plugins/vipunen/__tests__/tools.test.d.ts.map +1 -0
  503. package/dist/plugins/vipunen/__tests__/tools.test.js +646 -0
  504. package/dist/plugins/vipunen/__tests__/tools.test.js.map +1 -0
  505. package/dist/plugins/vipunen/client.d.ts.map +1 -0
  506. package/dist/plugins/vipunen/client.js.map +1 -0
  507. package/dist/plugins/vipunen/index.d.ts.map +1 -0
  508. package/dist/plugins/vipunen/index.js.map +1 -0
  509. package/dist/plugins/vipunen/tools.d.ts.map +1 -0
  510. package/dist/plugins/vipunen/tools.js.map +1 -0
  511. package/dist/routes/agents.d.ts +44 -0
  512. package/dist/routes/agents.d.ts.map +1 -0
  513. package/dist/routes/agents.js +311 -0
  514. package/dist/routes/agents.js.map +1 -0
  515. package/dist/services/agent-credential-store.d.ts +73 -0
  516. package/dist/services/agent-credential-store.d.ts.map +1 -0
  517. package/dist/services/agent-credential-store.js +212 -0
  518. package/dist/services/agent-credential-store.js.map +1 -0
  519. package/dist/stdio-server.d.ts.map +1 -0
  520. package/dist/stdio-server.js.map +1 -0
  521. package/dist/workspace/context.d.ts +148 -0
  522. package/dist/workspace/context.d.ts.map +1 -0
  523. package/dist/workspace/context.js +339 -0
  524. package/dist/workspace/context.js.map +1 -0
  525. package/dist/workspace/credentials.d.ts +55 -0
  526. package/dist/workspace/credentials.d.ts.map +1 -0
  527. package/dist/workspace/credentials.js +239 -0
  528. package/dist/workspace/credentials.js.map +1 -0
  529. package/dist/workspace/index.d.ts +21 -0
  530. package/dist/workspace/index.d.ts.map +1 -0
  531. package/dist/workspace/index.js +45 -0
  532. package/dist/workspace/index.js.map +1 -0
  533. package/dist/workspace/loader.d.ts +27 -0
  534. package/dist/workspace/loader.d.ts.map +1 -0
  535. package/dist/workspace/loader.js +222 -0
  536. package/dist/workspace/loader.js.map +1 -0
  537. package/dist/workspace/schema.d.ts +37 -0
  538. package/dist/workspace/schema.d.ts.map +1 -0
  539. package/dist/workspace/schema.js +192 -0
  540. package/dist/workspace/schema.js.map +1 -0
  541. package/package.json +13 -1
  542. package/.claude/.context-watchdog.json +0 -1
  543. package/.claude/.session-checked +0 -1
  544. package/test-billing-server.js +0 -136
@@ -0,0 +1,1122 @@
1
+ "use strict";
2
+ /**
3
+ * Chat Agent Daemon
4
+ *
5
+ * A persistent LLM conversation that monitors all workspace chats.
6
+ * The LLM maintains context across messages and decides what to respond to.
7
+ *
8
+ * Architecture:
9
+ * - One daemon per bot client
10
+ * - Subscribes to ALL messenger.new signals (not filtered)
11
+ * - LLM sees every message with priority markers
12
+ * - LLM decides: RESPOND / IGNORE / ACTION
13
+ */
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.ChatAgentDaemon = void 0;
19
+ const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
20
+ const hailer_clients_1 = require("../../mcp/hailer-clients");
21
+ const logger_1 = require("../../lib/logger");
22
+ const tool_schema_loader_1 = require("./tool-schema-loader");
23
+ const tool_registry_1 = require("../../mcp/tool-registry");
24
+ const agent_registry_1 = require("./services/agent-registry");
25
+ const conversation_manager_1 = require("./services/conversation-manager");
26
+ const mcp_client_1 = require("./services/mcp-client");
27
+ const message_formatter_1 = require("./services/message-formatter");
28
+ const message_classifier_1 = require("./services/message-classifier");
29
+ const session_logger_1 = require("./services/session-logger");
30
+ const tool_executor_1 = require("./services/tool-executor");
31
+ const workspace_schema_cache_1 = require("./services/workspace-schema-cache");
32
+ const typing_indicator_1 = require("./services/typing-indicator");
33
+ const token_billing_1 = require("./services/token-billing");
34
+ const structured_output_executor_1 = require("./services/structured-output-executor");
35
+ const action_schema_1 = require("./schemas/action-schema");
36
+ const hailer_api_client_1 = require("../../mcp/utils/hailer-api-client");
37
+ const config_1 = require("../../config");
38
+ const bot_config_1 = require("../../bot-config");
39
+ const config_2 = require("../../config");
40
+ class ChatAgentDaemon {
41
+ logger;
42
+ client;
43
+ botClient;
44
+ config;
45
+ toolSchemaLoader = new tool_schema_loader_1.ToolSchemaLoader();
46
+ // Processing state
47
+ isProcessing = false;
48
+ messageQueue = [];
49
+ processedMessageIds = new Set();
50
+ // Tool schemas (loaded once)
51
+ toolIndex = [];
52
+ minimalTools = [];
53
+ // ===== SERVICES =====
54
+ /** Message classifier - handles message extraction and priority classification */
55
+ messageClassifier = null;
56
+ /** Conversation manager - handles per-discussion context and LRU cache */
57
+ conversationManager = null;
58
+ /** MCP client service - handles tool schema loading and execution */
59
+ mcpClient = null;
60
+ /** Tool executor - handles tool execution and write tracking */
61
+ toolExecutor = null;
62
+ /** Agent registration service - handles Agent Directory, Position, Team, etc. */
63
+ registryService = null;
64
+ /** Message formatting service - handles tag resolution and formatting */
65
+ messageFormatter = null;
66
+ /** Session logging service - handles activity session tracking */
67
+ sessionLogger = null;
68
+ /** Workspace schema cache - dynamic workflow/field ID lookup */
69
+ schemaCache = null;
70
+ /** Typing indicator service - handles typing state with auto-refresh */
71
+ typingIndicator = null;
72
+ /** Token billing service - handles real-time token burning per workspace */
73
+ tokenBilling = null;
74
+ /** Structured output executor - handles action-based output instead of native tools */
75
+ structuredOutputExecutor = null;
76
+ /** Current discussion context for tracking */
77
+ currentDiscussionId = null;
78
+ currentLinkedActivityId = null;
79
+ /** Unsubscribe function for messenger.new signals */
80
+ messengerUnsubscribe = null;
81
+ /** Original API key for cleanup - stored at init because botClient.config may change */
82
+ originalApiKey = null;
83
+ constructor(config) {
84
+ this.config = config;
85
+ this.botClient = config.botClient;
86
+ this.logger = (0, logger_1.createLogger)({
87
+ component: "ChatAgentDaemon",
88
+ botId: config.botClient.userId
89
+ });
90
+ this.client = new sdk_1.default({
91
+ apiKey: config.anthropicApiKey,
92
+ });
93
+ }
94
+ /**
95
+ * Get the workspace schema cache for dynamic workflow/field ID lookup
96
+ * Exposed for modules that need to share schema discovery (e.g., Bug Fixer)
97
+ */
98
+ getSchemaCache() {
99
+ return this.schemaCache;
100
+ }
101
+ /**
102
+ * Initialize the daemon - load tools and subscribe to signals
103
+ */
104
+ async initialize() {
105
+ this.logger.info("Initializing Chat Agent Daemon", {
106
+ botId: this.botClient.userId,
107
+ email: (0, config_2.maskEmail)(this.botClient.config.email),
108
+ });
109
+ // Load tool index once
110
+ const allowedGroups = this.getToolGroups();
111
+ let tools = await this.toolSchemaLoader.loadToolIndex({
112
+ mcpServerUrl: this.config.mcpServerUrl,
113
+ mcpServerApiKey: this.botClient.config.mcpServerApiKey,
114
+ allowedGroups,
115
+ });
116
+ // Filter by whitelist if agent specifies one
117
+ const whitelist = this.getToolWhitelist();
118
+ if (whitelist) {
119
+ tools = tools.filter((t) => whitelist.includes(t.name));
120
+ this.logger.debug("Tools filtered by whitelist", {
121
+ total: tools.length,
122
+ whitelist: whitelist.length
123
+ });
124
+ }
125
+ this.toolIndex = tools;
126
+ this.minimalTools = this.toolSchemaLoader.toFullToolDefinitions(this.toolIndex);
127
+ this.logger.debug("Tools loaded", { toolCount: this.toolIndex.length });
128
+ // Initialize MCP client service (must be first - other services depend on it)
129
+ this.mcpClient = new mcp_client_1.McpClientService(this.config.mcpServerUrl, this.botClient.config.mcpServerApiKey, this.logger);
130
+ // Get workspace ID early - needed for schema cache and registration
131
+ const workspaceId = this.botClient.workspaceCache?.currentWorkspace?._id || "";
132
+ // Initialize workspace schema cache FIRST (discovers workflows dynamically)
133
+ // This MUST happen before agent registration so we have dynamic workflow IDs
134
+ this.schemaCache = new workspace_schema_cache_1.WorkspaceSchemaCacheService(this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient));
135
+ // Initialize schema for current workspace (may install template if missing)
136
+ if (workspaceId) {
137
+ await this.schemaCache.initializeForWorkspace(workspaceId);
138
+ }
139
+ // Initialize conversation manager
140
+ this.conversationManager = new conversation_manager_1.ConversationManager(100, // maxConversations
141
+ this.config.maxContextMessages || 50, this.client, this.logger);
142
+ // Initialize tool executor (with token billing for cache invalidation)
143
+ this.toolExecutor = new tool_executor_1.ToolExecutor(this.mcpClient, this.logger, this.tokenBilling || undefined);
144
+ // Initialize structured output executor (if enabled)
145
+ if (this.config.useStructuredOutputs) {
146
+ this.structuredOutputExecutor = new structured_output_executor_1.StructuredOutputExecutor(this.mcpClient, this.toolExecutor, this.logger);
147
+ this.logger.info("Structured outputs enabled - saving ~100K tokens per request");
148
+ }
149
+ // Initialize message classifier
150
+ this.messageClassifier = new message_classifier_1.MessageClassifier(this.botClient.userId, this.botClient, this.logger);
151
+ // Initialize typing indicator service
152
+ this.typingIndicator = new typing_indicator_1.TypingIndicatorService(this.botClient, this.logger);
153
+ // Initialize token billing service (if enabled)
154
+ const appConfig = (0, config_1.createApplicationConfig)();
155
+ if (appConfig.tokenBilling.enabled) {
156
+ // Create HailerApiClient from botClient
157
+ const hailerApiClient = this.botClient?.client
158
+ ? new hailer_api_client_1.HailerApiClient(this.botClient.client)
159
+ : null;
160
+ this.tokenBilling = new token_billing_1.TokenBillingService(this.logger, hailerApiClient || undefined);
161
+ this.logger.info("Token billing service initialized", {
162
+ hasHailerClient: !!hailerApiClient,
163
+ });
164
+ }
165
+ // Create agent registry service WITH schema cache for dynamic ID lookup
166
+ this.registryService = new agent_registry_1.AgentRegistryService(this.schemaCache, this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient), this.getDefaultTeamId.bind(this));
167
+ // Initialize message formatter service
168
+ this.messageFormatter = new message_formatter_1.MessageFormatterService(this.botClient, this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient));
169
+ // Build agent info from config and abstract methods
170
+ const { firstName, lastName } = this.getAgentName();
171
+ const agentInfo = {
172
+ firstName,
173
+ lastName,
174
+ description: this.getAgentDescription(),
175
+ email: this.botClient.config.email,
176
+ userId: this.botClient.userId,
177
+ };
178
+ // Register agent in workspace (handles deduplication internally)
179
+ this.logger.info("Starting agent registration", { workspaceId });
180
+ await this.registryService.registerAllAgentData(agentInfo, this.getPositionDetails(), this.config.mcpServerUrl, this.toolIndex, workspaceId);
181
+ // Store the API key at initialization for cleanup
182
+ // This is critical because botClient.config.mcpServerApiKey may change during daemon restart
183
+ this.originalApiKey = this.botClient.config.mcpServerApiKey;
184
+ // Subscribe to messenger.new signals using the working signal system (same as BugMonitor)
185
+ this.messengerUnsubscribe = (0, hailer_clients_1.subscribeToSignal)(this.botClient.config.mcpServerApiKey, 'messenger.new', (eventData) => {
186
+ // Convert raw event data to HailerSignal format expected by handleSignal
187
+ const signal = {
188
+ type: 'messenger.new',
189
+ data: eventData,
190
+ timestamp: Date.now(),
191
+ workspaceId: eventData.sid,
192
+ };
193
+ this.handleSignal(signal);
194
+ });
195
+ if (this.messengerUnsubscribe) {
196
+ this.logger.info("Subscribed to messenger.new signals via HailerClientManager");
197
+ }
198
+ else {
199
+ this.logger.warn("Failed to subscribe to messenger.new signals - no client manager found");
200
+ }
201
+ // Initialize session logger service (after registration so we have agentDirectoryId)
202
+ this.sessionLogger = new session_logger_1.SessionLoggerService(this.registryService?.getAgentDirectoryId() ?? null, this.logger, this.mcpClient.callMcpTool.bind(this.mcpClient), this.getDefaultTeamId.bind(this));
203
+ // Pass Anthropic client for conversation summary generation
204
+ this.sessionLogger.setAnthropicClient(this.client);
205
+ // Pass schema cache for dynamic workflow ID lookup
206
+ if (workspaceId && this.schemaCache) {
207
+ this.sessionLogger.setSchemaCache(this.schemaCache, workspaceId);
208
+ }
209
+ // Start idle session check timer (every 30 seconds)
210
+ this.sessionLogger.startIdleCheckTimer(30_000);
211
+ this.logger.info("Chat Agent Daemon initialized and listening", {
212
+ workspaceId,
213
+ agentDirectoryId: this.registryService.getAgentDirectoryId(),
214
+ positionId: this.registryService.getPositionId(),
215
+ teamId: this.registryService.getTeamId(),
216
+ });
217
+ }
218
+ /**
219
+ * Extract and classify incoming message from signal
220
+ * Can be overridden in subclasses to customize filtering
221
+ */
222
+ async extractIncomingMessage(signal) {
223
+ return this.messageClassifier.extractIncomingMessage(signal);
224
+ }
225
+ /**
226
+ * Handle incoming signal from Hailer
227
+ */
228
+ async handleSignal(signal) {
229
+ try {
230
+ // EARLY dedup check using raw signal data (before async operation)
231
+ // This prevents race condition where two signals arrive simultaneously
232
+ const signalData = signal.data;
233
+ const rawMsgId = signalData.msg_id;
234
+ if (rawMsgId) {
235
+ if (this.processedMessageIds.has(rawMsgId)) {
236
+ this.logger.debug("Early dedup: skipping duplicate signal", { rawMsgId });
237
+ return;
238
+ }
239
+ // Add immediately to prevent race condition
240
+ this.processedMessageIds.add(rawMsgId);
241
+ }
242
+ const message = await this.extractIncomingMessage(signal);
243
+ if (!message) {
244
+ // Remove from set if extraction failed (message was invalid)
245
+ if (rawMsgId)
246
+ this.processedMessageIds.delete(rawMsgId);
247
+ return;
248
+ }
249
+ // Clean up old IDs (keep last 500)
250
+ if (this.processedMessageIds.size > 500) {
251
+ const ids = Array.from(this.processedMessageIds);
252
+ this.processedMessageIds = new Set(ids.slice(-250));
253
+ }
254
+ this.logger.info("Incoming message", {
255
+ from: message.senderName,
256
+ discussion: message.discussionId,
257
+ priority: message.priority,
258
+ reason: message.priorityReason,
259
+ preview: message.content.substring(0, 50),
260
+ });
261
+ // Queue the message
262
+ this.messageQueue.push(message);
263
+ // Process if not already processing
264
+ if (!this.isProcessing) {
265
+ await this.processQueue();
266
+ }
267
+ }
268
+ catch (error) {
269
+ this.logger.error("Failed to handle signal", error);
270
+ }
271
+ }
272
+ /**
273
+ * Process queued messages through the LLM
274
+ * Note: Uses flag-first pattern to prevent race conditions
275
+ */
276
+ async processQueue() {
277
+ // Set flag FIRST to prevent race condition (multiple async calls)
278
+ if (this.isProcessing)
279
+ return;
280
+ this.isProcessing = true;
281
+ // Now check queue (after claiming the lock)
282
+ if (this.messageQueue.length === 0) {
283
+ this.isProcessing = false;
284
+ return;
285
+ }
286
+ try {
287
+ // Sort by priority (high first) then by timestamp
288
+ this.messageQueue.sort((a, b) => {
289
+ const priorityOrder = { high: 0, normal: 1, low: 2 };
290
+ if (priorityOrder[a.priority] !== priorityOrder[b.priority]) {
291
+ return priorityOrder[a.priority] - priorityOrder[b.priority];
292
+ }
293
+ return a.timestamp - b.timestamp;
294
+ });
295
+ // Process one message at a time for now
296
+ while (this.messageQueue.length > 0) {
297
+ const message = this.messageQueue.shift();
298
+ await this.processMessage(message);
299
+ }
300
+ }
301
+ finally {
302
+ this.isProcessing = false;
303
+ }
304
+ }
305
+ /**
306
+ * Process a single message through the persistent LLM conversation
307
+ */
308
+ async processMessage(message) {
309
+ // Check if bot is still enabled (may have been disabled via AI Hub)
310
+ const botState = (0, bot_config_1.getBotState)();
311
+ if (!botState[this.config.botClient.userId]) {
312
+ this.logger.info("Bot disabled, skipping message", {
313
+ discussion: message.discussionId,
314
+ from: message.senderName,
315
+ });
316
+ return;
317
+ }
318
+ const startTime = Date.now();
319
+ // Update current context for session tracking
320
+ this.currentDiscussionId = message.discussionId;
321
+ this.currentLinkedActivityId = message.linkedActivityId || null;
322
+ // Multi-tenant: Initialize schema cache for this workspace on-demand
323
+ // Each workspace has its own workflow IDs - must be cached before processing
324
+ if (this.schemaCache && message.workspaceId) {
325
+ const schemas = this.schemaCache.getSchemas(message.workspaceId);
326
+ if (!schemas?.initialized) {
327
+ this.logger.info("Initializing schema cache for workspace", { workspaceId: message.workspaceId });
328
+ await this.schemaCache.initializeForWorkspace(message.workspaceId);
329
+ // Update session logger with workspace-specific schema
330
+ if (this.sessionLogger) {
331
+ this.sessionLogger.setSchemaCache(this.schemaCache, message.workspaceId);
332
+ }
333
+ }
334
+ }
335
+ // Start typing indicator with auto-refresh
336
+ this.typingIndicator?.start(message.discussionId);
337
+ // Get or create activity session
338
+ const session = this.sessionLogger.getOrCreateActivitySession(message);
339
+ session.lastActivityTime = Date.now();
340
+ session.metrics.messagesProcessed++;
341
+ // Check balance before every message (caching prevents API spam)
342
+ if (this.tokenBilling && message.workspaceId) {
343
+ const balance = await this.tokenBilling.checkBalance(message.workspaceId);
344
+ if (!balance.hasBalance) {
345
+ this.logger.info("Session rejected - no token balance", {
346
+ workspaceId: message.workspaceId,
347
+ balance: balance.balance,
348
+ discussion: message.discussionId,
349
+ });
350
+ this.typingIndicator?.stop();
351
+ await this.sendInsufficientBalanceMessage(message.discussionId);
352
+ return;
353
+ }
354
+ }
355
+ // Add user message to conversation log (compact version)
356
+ const userSnippet = message.content.length > 100
357
+ ? message.content.substring(0, 100) + "..."
358
+ : message.content;
359
+ session.conversation.push(`${message.senderName}: ${userSnippet}`);
360
+ // Format incoming message for LLM
361
+ let incomingContent = this.formatIncomingMessage(message);
362
+ // Get conversation for THIS discussion (isolated context)
363
+ const conversation = this.conversationManager.getConversation(message.discussionId);
364
+ // Track conversation length BEFORE this message for proper cleanup on IGNORE
365
+ const conversationLengthBeforeMessage = conversation.length;
366
+ // COLD START: If conversation is empty, try to load memory context from Hailer
367
+ if (conversation.length === 0) {
368
+ const memoryContext = await this.loadMemoryContext(message.discussionId, message.workspaceId);
369
+ if (memoryContext) {
370
+ // Prepend memory context to the user message
371
+ incomingContent = `${memoryContext}\n\n[Current message]\n${incomingContent}`;
372
+ this.logger.debug("Injected memory context on cold start", {
373
+ discussion: message.discussionId.substring(0, 8),
374
+ });
375
+ }
376
+ }
377
+ // Append to conversation
378
+ conversation.push({
379
+ role: "user",
380
+ content: incomingContent,
381
+ });
382
+ // Check context size and summarize if needed
383
+ await this.conversationManager.manageContextSize(message.discussionId);
384
+ try {
385
+ // Call LLM with this discussion's conversation (with caching enabled)
386
+ const cachedConversation = this.conversationManager.prepareForCaching(conversation);
387
+ // Use structured outputs if enabled (saves ~100K tokens per request)
388
+ let response;
389
+ if (this.config.useStructuredOutputs) {
390
+ response = await this.callLlmWithStructuredOutputs(cachedConversation);
391
+ }
392
+ else {
393
+ // Log sizing for comparison with structured outputs
394
+ const systemPrompt = this.getCachedSystemPrompt();
395
+ const tools = this.getTools();
396
+ const systemCharCount = systemPrompt.reduce((acc, block) => acc + (block.text?.length || 0), 0);
397
+ const toolsCharCount = JSON.stringify(tools).length;
398
+ const messagesCharCount = JSON.stringify(cachedConversation).length;
399
+ this.logger.info("Native tools request sizing", {
400
+ systemCharCount,
401
+ toolsCharCount,
402
+ messagesCharCount,
403
+ estimatedTokens: Math.round((systemCharCount + toolsCharCount + messagesCharCount) / 4),
404
+ toolCount: tools.length,
405
+ });
406
+ response = await this.client.messages.create({
407
+ model: this.config.model || "claude-haiku-4-5-20251001",
408
+ max_tokens: 2000,
409
+ system: systemPrompt,
410
+ messages: cachedConversation,
411
+ tools,
412
+ });
413
+ // Log actual usage
414
+ if (response.usage) {
415
+ const usage = response.usage;
416
+ this.logger.info("Native tools response usage", {
417
+ inputTokens: usage.input_tokens,
418
+ outputTokens: usage.output_tokens,
419
+ cacheCreationTokens: usage.cache_creation_input_tokens || 0,
420
+ cacheReadTokens: usage.cache_read_input_tokens || 0,
421
+ });
422
+ }
423
+ }
424
+ // Track token usage in the activity session (including cache stats for billing)
425
+ if (response.usage) {
426
+ const inputTokens = response.usage.input_tokens;
427
+ const outputTokens = response.usage.output_tokens;
428
+ const cacheCreationTokens = response.usage.cache_creation_input_tokens || 0;
429
+ const cacheReadTokens = response.usage.cache_read_input_tokens || 0;
430
+ session.metrics.inputTokens += inputTokens;
431
+ session.metrics.outputTokens += outputTokens;
432
+ session.metrics.cacheCreationTokens += cacheCreationTokens;
433
+ session.metrics.cacheReadTokens += cacheReadTokens;
434
+ session.metrics.apiCalls += 1;
435
+ // Burn tokens real-time (fire-and-forget)
436
+ if (this.tokenBilling && session.workspaceId) {
437
+ const cost = this.tokenBilling.calculateCost(inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens);
438
+ this.tokenBilling.burnTokens({
439
+ workspaceId: session.workspaceId,
440
+ inputTokens,
441
+ outputTokens,
442
+ cacheCreationTokens,
443
+ cacheReadTokens,
444
+ costUsd: cost,
445
+ sessionId: session.discussionId,
446
+ activityId: session.activityId,
447
+ });
448
+ }
449
+ }
450
+ // Handle response (pass original length for proper cleanup on IGNORE)
451
+ if (this.config.useStructuredOutputs) {
452
+ await this.handleStructuredResponse(response, message, conversationLengthBeforeMessage);
453
+ }
454
+ else {
455
+ await this.handleLlmResponse(response, message, conversationLengthBeforeMessage);
456
+ }
457
+ const duration = Date.now() - startTime;
458
+ this.logger.info("Message processed", {
459
+ discussion: message.discussionId,
460
+ duration,
461
+ stopReason: response.stop_reason,
462
+ sessionActivity: session.activityName,
463
+ });
464
+ // Update last activity time (idle checker will flush when needed)
465
+ session.lastActivityTime = Date.now();
466
+ }
467
+ catch (error) {
468
+ this.logger.error("LLM processing failed", error);
469
+ // Stop typing indicator on error
470
+ this.typingIndicator?.stop();
471
+ // On error, remove the message from conversation to avoid poisoning context
472
+ if (conversation.length > 0) {
473
+ conversation.pop();
474
+ }
475
+ }
476
+ }
477
+ /**
478
+ * Format incoming message for LLM consumption
479
+ */
480
+ formatIncomingMessage(message) {
481
+ const priorityTag = message.priority === "high" ? " priority=\"high\"" : "";
482
+ const reasonAttr = message.priority === "high" ? ` reason="${message.priorityReason}"` : "";
483
+ const activityAttr = message.linkedActivityId ? ` activity_id="${message.linkedActivityId}"` : "";
484
+ // Build file attachment info if present
485
+ let fileInfo = "";
486
+ if (message.fileAttachments && message.fileAttachments.length > 0) {
487
+ const fileList = message.fileAttachments.map(f => ` - ${f.filename} (ID: ${f.fileId}${f.size ? `, ${Math.round(f.size / 1024)}KB` : ""}${f.mime ? `, ${f.mime}` : ""})`).join("\n");
488
+ fileInfo = `\n[File attached: ${message.fileAttachments.length} file(s) - IDs: ${message.fileAttachments.map(f => f.fileId).join(", ")}]\n${fileList}\n\nUse download_file tool with fileId to read file contents.`;
489
+ }
490
+ return `<incoming discussion="${message.discussionId}"${activityAttr} from="${message.senderName}" user_id="${message.senderId}" timestamp="${new Date(message.timestamp).toISOString()}"${priorityTag}${reasonAttr}>
491
+ ${message.content}${fileInfo}
492
+ </incoming>`;
493
+ }
494
+ /**
495
+ * Load memory context on cold start
496
+ * Uses discussion message history (FREE) instead of SESSION_LOG (costs tokens)
497
+ */
498
+ async loadMemoryContext(discussionId, _workspaceId) {
499
+ if (!this.mcpClient) {
500
+ return null;
501
+ }
502
+ try {
503
+ // Fetch last 15 messages from discussion (FREE - read operation)
504
+ const result = await this.mcpClient.callMcpTool("fetch_discussion_messages", {
505
+ discussionId,
506
+ limit: 15,
507
+ });
508
+ const text = result?.content?.[0]?.text;
509
+ if (!text || text.includes("No messages found")) {
510
+ return null;
511
+ }
512
+ // Extract just the message content, skip the header/metadata
513
+ const messagesMatch = text.match(/📨 \*\*MESSAGES\*\*[\s\S]*/);
514
+ if (!messagesMatch) {
515
+ return null;
516
+ }
517
+ return `[Previous conversation in this discussion]\n${messagesMatch[0]}`;
518
+ }
519
+ catch (error) {
520
+ this.logger.debug("Failed to load memory context from discussion", {
521
+ discussion: discussionId.substring(0, 8),
522
+ error: error instanceof Error ? error.message : String(error),
523
+ });
524
+ return null;
525
+ }
526
+ }
527
+ /**
528
+ * Execute tool calls and continue the conversation
529
+ * Simple passthrough - just execute tools and return results to LLM
530
+ * @param conversationLengthBeforeMessage - passed through for proper IGNORE cleanup
531
+ */
532
+ async executeToolsAndContinue(toolUseBlocks, originalMessage, conversationLengthBeforeMessage) {
533
+ // Get current activity session
534
+ const sessionKey = this.currentLinkedActivityId || this.currentDiscussionId || "default";
535
+ const session = this.sessionLogger.getSession(sessionKey);
536
+ // Store the user's request that triggered these tool calls (for context)
537
+ if (session && !session.triggerRequest) {
538
+ session.triggerRequest = originalMessage.content.substring(0, 500);
539
+ session.requestedBy = originalMessage.senderName;
540
+ session.requestedById = originalMessage.senderId;
541
+ }
542
+ // Execute tools using the tool executor service
543
+ const toolResults = await this.toolExecutor.executeTools(toolUseBlocks, {
544
+ session,
545
+ preprocessToolInput: this.preprocessToolInput.bind(this),
546
+ });
547
+ // Get conversation for this discussion
548
+ const conversation = this.conversationManager.getConversation(originalMessage.discussionId);
549
+ // Add tool results to conversation
550
+ conversation.push({
551
+ role: "user",
552
+ content: toolResults,
553
+ });
554
+ // Continue with LLM (with caching enabled)
555
+ const cachedConversation = this.conversationManager.prepareForCaching(conversation);
556
+ const response = await this.client.messages.create({
557
+ model: this.config.model || "claude-haiku-4-5-20251001",
558
+ max_tokens: 2000,
559
+ system: this.getCachedSystemPrompt(),
560
+ messages: cachedConversation,
561
+ tools: this.getTools(),
562
+ });
563
+ // Track token usage in session (including cache stats for billing)
564
+ if (session && response.usage) {
565
+ const inputTokens = response.usage.input_tokens;
566
+ const outputTokens = response.usage.output_tokens;
567
+ const cacheCreationTokens = response.usage.cache_creation_input_tokens || 0;
568
+ const cacheReadTokens = response.usage.cache_read_input_tokens || 0;
569
+ session.metrics.inputTokens += inputTokens;
570
+ session.metrics.outputTokens += outputTokens;
571
+ session.metrics.cacheCreationTokens += cacheCreationTokens;
572
+ session.metrics.cacheReadTokens += cacheReadTokens;
573
+ session.metrics.apiCalls += 1;
574
+ session.lastActivityTime = Date.now();
575
+ // Burn tokens real-time (fire-and-forget)
576
+ if (this.tokenBilling && session.workspaceId) {
577
+ const cost = this.tokenBilling.calculateCost(inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens);
578
+ this.tokenBilling.burnTokens({
579
+ workspaceId: session.workspaceId,
580
+ inputTokens,
581
+ outputTokens,
582
+ cacheCreationTokens,
583
+ cacheReadTokens,
584
+ costUsd: cost,
585
+ sessionId: session.discussionId,
586
+ activityId: session.activityId,
587
+ });
588
+ }
589
+ }
590
+ // Recursively handle (might need more tools or finally respond)
591
+ await this.handleLlmResponse(response, originalMessage, conversationLengthBeforeMessage);
592
+ }
593
+ /**
594
+ * Handle LLM response
595
+ * Override in subclasses to customize response handling
596
+ * @param conversationLengthBeforeMessage - length to truncate to on IGNORE (cleans up entire tool loop)
597
+ */
598
+ async handleLlmResponse(response, originalMessage, conversationLengthBeforeMessage) {
599
+ const conversation = this.conversationManager.getConversation(originalMessage.discussionId);
600
+ // Add assistant response to conversation
601
+ conversation.push({
602
+ role: "assistant",
603
+ content: response.content,
604
+ });
605
+ // Check for tool calls - execute and continue
606
+ const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
607
+ if (toolUseBlocks.length > 0) {
608
+ await this.executeToolsAndContinue(toolUseBlocks, originalMessage, conversationLengthBeforeMessage);
609
+ return;
610
+ }
611
+ // Extract text response
612
+ const textBlocks = response.content.filter((block) => block.type === "text");
613
+ if (textBlocks.length === 0)
614
+ return;
615
+ const responseText = textBlocks.map(b => b.text).join("\n").trim();
616
+ this.logger.info("LLM response received", {
617
+ discussion: originalMessage.discussionId,
618
+ responseLength: responseText.length,
619
+ });
620
+ // IGNORE/COMPLETE decision - clean up context (entire tool loop if any)
621
+ // LLM may use IGNORE (don't respond) or COMPLETE (already posted via tool)
622
+ if (responseText.includes("<decision>IGNORE</decision>") ||
623
+ responseText.includes("<decision>COMPLETE</decision>") ||
624
+ responseText.includes("<ignore")) {
625
+ this.logger.debug("LLM decided to ignore", { discussion: originalMessage.discussionId });
626
+ this.typingIndicator?.stop();
627
+ // If we have the original conversation length, truncate to it (cleans up entire tool loop)
628
+ if (conversationLengthBeforeMessage !== undefined) {
629
+ conversation.length = Math.min(conversationLengthBeforeMessage, conversation.length);
630
+ this.logger.debug("Truncated conversation to pre-message state", {
631
+ discussion: originalMessage.discussionId,
632
+ newLength: conversation.length
633
+ });
634
+ }
635
+ else {
636
+ // Fallback: just remove assistant response and user message
637
+ conversation.pop(); // Remove assistant response
638
+ conversation.pop(); // Remove incoming message
639
+ }
640
+ return;
641
+ }
642
+ // Explicit <respond> tag
643
+ const responseMatch = responseText.match(/<respond discussion="([^"]+)">([\s\S]*?)<\/respond>/);
644
+ if (responseMatch) {
645
+ await this.postResponse(responseMatch[1], responseMatch[2].trim());
646
+ return;
647
+ }
648
+ // High priority: always respond if substantive
649
+ if (originalMessage.priority === "high" && responseText.length > 10 &&
650
+ !responseText.includes("<thinking>") && !responseText.startsWith("I'll")) {
651
+ await this.postResponse(originalMessage.discussionId, responseText);
652
+ return;
653
+ }
654
+ // Normal priority without <respond> tag - clean up context
655
+ if (originalMessage.priority === "normal") {
656
+ this.logger.debug("Normal priority without <respond> - removing from context");
657
+ this.typingIndicator?.stop();
658
+ if (conversationLengthBeforeMessage !== undefined) {
659
+ conversation.length = Math.min(conversationLengthBeforeMessage, conversation.length);
660
+ }
661
+ else {
662
+ conversation.pop();
663
+ conversation.pop();
664
+ }
665
+ }
666
+ }
667
+ // ===== STRUCTURED OUTPUTS SUPPORT =====
668
+ /**
669
+ * Call LLM with structured outputs instead of native tools
670
+ * Saves ~100K tokens per request by not sending tool schemas
671
+ */
672
+ async callLlmWithStructuredOutputs(messages) {
673
+ // Build system prompt with action reference
674
+ const systemPrompt = this.getCachedSystemPrompt();
675
+ const actionPrompt = this.structuredOutputExecutor.generateActionPrompt(this.getAllowedActions());
676
+ // Combine system prompt with action reference
677
+ // ARCHITECTURE for caching:
678
+ // 1. Static blocks (all except last) - stripped of cache_control
679
+ // 2. Action prompt - WITH cache_control (this is the cache breakpoint)
680
+ // 3. Dynamic block (last) - NO cache_control, comes AFTER breakpoint
681
+ // This way only static + action are cached, dynamic content is fresh each call
682
+ const systemBlocks = Array.isArray(systemPrompt) ? systemPrompt : [{ type: "text", text: systemPrompt }];
683
+ // Separate static (all but last) from dynamic (last)
684
+ const staticBlocks = systemBlocks.slice(0, -1);
685
+ const dynamicBlock = systemBlocks.length > 1 ? systemBlocks[systemBlocks.length - 1] : null;
686
+ const combinedSystem = [
687
+ // Static blocks (stripped of cache_control)
688
+ ...staticBlocks.map(block => ({
689
+ type: "text",
690
+ text: block.text || "",
691
+ })),
692
+ // Action prompt WITH cache_control (cache breakpoint)
693
+ {
694
+ type: "text",
695
+ text: actionPrompt,
696
+ cache_control: { type: "ephemeral" },
697
+ },
698
+ // Dynamic block AFTER breakpoint (not cached)
699
+ ...(dynamicBlock ? [{
700
+ type: "text",
701
+ text: dynamicBlock.text || "",
702
+ }] : []),
703
+ ];
704
+ // DEBUG: Log what we're sending to API
705
+ const systemCharCount = combinedSystem.reduce((acc, block) => acc + (block.text?.length || 0), 0);
706
+ const messagesCharCount = JSON.stringify(messages).length;
707
+ const outputFormat = this.structuredOutputExecutor.getOutputFormat();
708
+ const schemaCharCount = JSON.stringify(outputFormat).length;
709
+ this.logger.info("Structured outputs request sizing", {
710
+ systemCharCount,
711
+ messagesCharCount,
712
+ schemaCharCount,
713
+ estimatedTokens: Math.round((systemCharCount + messagesCharCount) / 4),
714
+ messagesCount: messages.length,
715
+ });
716
+ // Call with structured outputs beta
717
+ // Note: Prompt caching is now GA (no beta header needed)
718
+ // Note: output_format is a beta feature not yet in SDK types
719
+ const params = {
720
+ model: this.config.model || "claude-haiku-4-5-20251001",
721
+ max_tokens: 2000,
722
+ betas: [structured_output_executor_1.STRUCTURED_OUTPUTS_BETA],
723
+ system: combinedSystem,
724
+ messages,
725
+ output_format: outputFormat,
726
+ };
727
+ const response = await this.client.beta.messages.create(params);
728
+ // DEBUG: Log actual usage from API
729
+ if (response.usage) {
730
+ const usage = response.usage;
731
+ this.logger.info("Structured outputs response usage", {
732
+ inputTokens: usage.input_tokens,
733
+ outputTokens: usage.output_tokens,
734
+ cacheCreationTokens: usage.cache_creation_input_tokens || 0,
735
+ cacheReadTokens: usage.cache_read_input_tokens || 0,
736
+ estimatedVsActual: `${Math.round((systemCharCount + messagesCharCount) / 4)} vs ${usage.input_tokens + (usage.cache_creation_input_tokens || 0)}`,
737
+ });
738
+ }
739
+ return response;
740
+ }
741
+ /**
742
+ * Handle structured output response
743
+ * Parses JSON action and executes it
744
+ */
745
+ async handleStructuredResponse(response, originalMessage, conversationLengthBeforeMessage) {
746
+ const conversation = this.conversationManager.getConversation(originalMessage.discussionId);
747
+ // Add assistant response to conversation
748
+ conversation.push({
749
+ role: "assistant",
750
+ content: response.content,
751
+ });
752
+ // Parse the action from response
753
+ const action = this.structuredOutputExecutor.parseResponse(response);
754
+ if (!action) {
755
+ this.logger.warn("Failed to parse action from response");
756
+ this.typingIndicator?.stop();
757
+ // Remove failed response from context
758
+ conversation.pop();
759
+ return;
760
+ }
761
+ this.logger.debug("Parsed action", {
762
+ action: action.action,
763
+ thinking: action.thinking?.substring(0, 50),
764
+ });
765
+ // Get session for tracking
766
+ const sessionKey = this.currentLinkedActivityId || this.currentDiscussionId || "default";
767
+ const session = this.sessionLogger.getSession(sessionKey);
768
+ // Execute the action
769
+ const result = await this.structuredOutputExecutor.executeAction(action, {
770
+ session,
771
+ preprocessToolInput: this.preprocessToolInput.bind(this),
772
+ });
773
+ // Handle terminal actions
774
+ if (result.isTerminal) {
775
+ if (result.action === "respond" && result.responseText) {
776
+ await this.postResponse(originalMessage.discussionId, result.responseText);
777
+ }
778
+ else if (result.action === "ignore") {
779
+ this.logger.debug("Action: ignore", { discussion: originalMessage.discussionId });
780
+ this.typingIndicator?.stop();
781
+ // Clean up context on ignore
782
+ if (conversationLengthBeforeMessage !== undefined) {
783
+ conversation.length = Math.min(conversationLengthBeforeMessage, conversation.length);
784
+ }
785
+ else {
786
+ conversation.pop();
787
+ conversation.pop();
788
+ }
789
+ }
790
+ else if (result.action === "invite_specialist" && result.specialist) {
791
+ // Handle specialist invitation (override in subclass)
792
+ await this.handleSpecialistInvite(result.specialist.key, result.specialist.context, originalMessage);
793
+ }
794
+ return;
795
+ }
796
+ // Non-terminal action: add result and continue
797
+ if (result.error || result.toolResult) {
798
+ const resultMessage = this.structuredOutputExecutor.formatResultForConversation(result);
799
+ conversation.push(resultMessage);
800
+ // Continue the loop with another LLM call
801
+ await this.executeStructuredActionLoop(originalMessage, conversationLengthBeforeMessage);
802
+ }
803
+ }
804
+ /**
805
+ * Continue executing actions until a terminal action
806
+ */
807
+ async executeStructuredActionLoop(originalMessage, conversationLengthBeforeMessage) {
808
+ const conversation = this.conversationManager.getConversation(originalMessage.discussionId);
809
+ const sessionKey = this.currentLinkedActivityId || this.currentDiscussionId || "default";
810
+ const session = this.sessionLogger.getSession(sessionKey);
811
+ // Call LLM again with structured outputs
812
+ const cachedConversation = this.conversationManager.prepareForCaching(conversation);
813
+ const response = await this.callLlmWithStructuredOutputs(cachedConversation);
814
+ // Track token usage
815
+ if (session && response.usage) {
816
+ const inputTokens = response.usage.input_tokens;
817
+ const outputTokens = response.usage.output_tokens;
818
+ const cacheCreationTokens = response.usage.cache_creation_input_tokens || 0;
819
+ const cacheReadTokens = response.usage.cache_read_input_tokens || 0;
820
+ session.metrics.inputTokens += inputTokens;
821
+ session.metrics.outputTokens += outputTokens;
822
+ session.metrics.cacheCreationTokens += cacheCreationTokens;
823
+ session.metrics.cacheReadTokens += cacheReadTokens;
824
+ session.metrics.apiCalls += 1;
825
+ session.lastActivityTime = Date.now();
826
+ // Burn tokens real-time
827
+ if (this.tokenBilling && session.workspaceId) {
828
+ const cost = this.tokenBilling.calculateCost(inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens);
829
+ this.tokenBilling.burnTokens({
830
+ workspaceId: session.workspaceId,
831
+ inputTokens,
832
+ outputTokens,
833
+ cacheCreationTokens,
834
+ cacheReadTokens,
835
+ costUsd: cost,
836
+ sessionId: session.discussionId,
837
+ activityId: session.activityId,
838
+ });
839
+ }
840
+ }
841
+ // Handle the response (recursive)
842
+ await this.handleStructuredResponse(response, originalMessage, conversationLengthBeforeMessage);
843
+ }
844
+ /**
845
+ * Get allowed actions for this agent
846
+ * Override in subclass to customize available actions
847
+ */
848
+ getAllowedActions() {
849
+ // Default: all actions except meta actions (handled separately)
850
+ return action_schema_1.BOT_ACTIONS.filter((a) => a !== "respond" && a !== "ignore" && a !== "invite_specialist");
851
+ }
852
+ /**
853
+ * Handle specialist invitation
854
+ * Override in subclass (e.g., HAL daemon) to implement specialist logic
855
+ */
856
+ async handleSpecialistInvite(specialistKey, context, originalMessage) {
857
+ this.logger.warn("Specialist invite not implemented in base class", {
858
+ specialist: specialistKey,
859
+ });
860
+ }
861
+ /**
862
+ * Post a response to a discussion
863
+ * Automatically converts @mentions and #activity tags to Hailer tags
864
+ * Includes links metadata required for tags to work
865
+ */
866
+ async postResponse(discussionId, content) {
867
+ // Stop typing indicator before posting
868
+ this.typingIndicator?.stop();
869
+ try {
870
+ // Resolve tags that need API lookup
871
+ let formattedContent = await this.messageFormatter.resolveUserTags(content); // @userId → [hailerTag|Name](id)
872
+ formattedContent = await this.messageFormatter.resolveActivityTags(formattedContent); // #activityId → [hailerTag|Name](id)
873
+ formattedContent = await this.messageFormatter.resolveHailerUrls(formattedContent); // URLs → [hailerTag|Name](id)
874
+ // Then convert any remaining @mentions from cache (fallback)
875
+ formattedContent = this.messageFormatter.convertMentionsToTags(formattedContent);
876
+ // Remove redundant "(Name)" after tags - LLM sometimes adds these
877
+ formattedContent = formattedContent.replace(/(\[hailerTag\|[^\]]+\]\([a-f0-9]{24}\)\uFEFF?)\s*\([^)]+\)/gi, '$1');
878
+ // Extract link metadata for any tags in the content
879
+ const links = this.messageFormatter.extractTagLinks(formattedContent);
880
+ // Build message object with links if we have any
881
+ const messageData = {
882
+ msg: formattedContent
883
+ };
884
+ if (links.length > 0) {
885
+ messageData.links = links;
886
+ }
887
+ await this.botClient.client.socket.request("messenger.send", [
888
+ messageData,
889
+ discussionId,
890
+ ]);
891
+ // Track response in activity session
892
+ const sessionKey = this.currentLinkedActivityId || this.currentDiscussionId || "default";
893
+ const session = this.sessionLogger.getSession(sessionKey);
894
+ if (session) {
895
+ session.metrics.responsesPosted++;
896
+ session.actions.push(`Responded in discussion`);
897
+ session.lastActivityTime = Date.now();
898
+ // Add bot response to conversation log (compact version)
899
+ const botSnippet = content.length > 100 ? content.substring(0, 100) + "..." : content;
900
+ session.conversation.push(`Bot: ${botSnippet}`);
901
+ }
902
+ this.logger.info("Response posted", {
903
+ discussion: discussionId,
904
+ length: formattedContent.length,
905
+ hadTags: formattedContent !== content,
906
+ linkCount: links.length,
907
+ });
908
+ }
909
+ catch (error) {
910
+ this.logger.error("Failed to post response", error);
911
+ }
912
+ }
913
+ /**
914
+ * Send insufficient balance message to user
915
+ * Can be overridden in subclasses to customize the message
916
+ */
917
+ async sendInsufficientBalanceMessage(discussionId) {
918
+ try {
919
+ await this.botClient.client.socket.request("messenger.send", [
920
+ { msg: "Insufficient balance. Please top up your workspace AI credits to continue." },
921
+ discussionId,
922
+ ]);
923
+ }
924
+ catch (error) {
925
+ this.logger.error("Failed to send insufficient balance message", error);
926
+ }
927
+ }
928
+ /**
929
+ * Get the system prompt for the daemon
930
+ * MUST be overridden in subclasses
931
+ */
932
+ getSystemPrompt() {
933
+ throw new Error("getSystemPrompt() must be implemented by subclass");
934
+ }
935
+ /**
936
+ * Get the system prompt wrapped with Anthropic prompt caching
937
+ * This enables 50% cost reduction on cached tokens after first use
938
+ */
939
+ getCachedSystemPrompt() {
940
+ return [
941
+ {
942
+ type: "text",
943
+ text: this.getSystemPrompt(),
944
+ cache_control: { type: "ephemeral" },
945
+ },
946
+ ];
947
+ }
948
+ /**
949
+ * Get tools for LLM calls
950
+ * Override in subclass to add custom tools (like trigger_giuseppe_retry)
951
+ */
952
+ getTools() {
953
+ return this.minimalTools;
954
+ }
955
+ /**
956
+ * Get tool groups to load for this agent
957
+ * Override in subclass to include additional groups (e.g., BOT_INTERNAL)
958
+ */
959
+ getToolGroups() {
960
+ return [tool_registry_1.ToolGroup.READ, tool_registry_1.ToolGroup.WRITE];
961
+ }
962
+ /**
963
+ * Get tool whitelist for this agent
964
+ * Override in subclass to limit which tools are available
965
+ * Return null for all tools, or array of tool names
966
+ */
967
+ getToolWhitelist() {
968
+ return null; // Default: all tools
969
+ }
970
+ /**
971
+ * Preprocess tool input before execution
972
+ * Override in subclass to inject context (e.g., sourceActivityId)
973
+ * @param toolName - Name of the tool being called
974
+ * @param input - Original tool input from LLM
975
+ * @returns Processed input (may be modified)
976
+ */
977
+ preprocessToolInput(toolName, input) {
978
+ // Auto-inject discussionId for leave_discussion if not provided
979
+ if (toolName === "leave_discussion" && !input.discussionId && !input.activityId) {
980
+ if (this.currentDiscussionId) {
981
+ this.logger.debug("Auto-injected discussionId for leave_discussion", {
982
+ discussionId: this.currentDiscussionId,
983
+ });
984
+ return { ...input, discussionId: this.currentDiscussionId };
985
+ }
986
+ }
987
+ return input; // Default: no preprocessing
988
+ }
989
+ /**
990
+ * Call MCP tool (delegates to McpClientService)
991
+ * Protected for subclass access
992
+ */
993
+ async callMcpTool(name, args) {
994
+ return this.mcpClient.callMcpTool(name, args);
995
+ }
996
+ /**
997
+ * Stop the daemon
998
+ * Flushes all pending activity sessions before stopping
999
+ */
1000
+ async stop() {
1001
+ // Stop idle check timer and flush all pending sessions
1002
+ this.sessionLogger?.stopIdleCheckTimer();
1003
+ await this.sessionLogger?.flushAllSessions();
1004
+ // Unsubscribe from messenger.new signals
1005
+ if (this.messengerUnsubscribe) {
1006
+ this.messengerUnsubscribe();
1007
+ this.messengerUnsubscribe = null;
1008
+ }
1009
+ // Disconnect the Hailer client connection using the ORIGINAL API key
1010
+ // This is critical: botClient.config.mcpServerApiKey may have been updated to a new value
1011
+ // before stop() is called during restart, so we must use the stored originalApiKey
1012
+ if (this.originalApiKey) {
1013
+ (0, hailer_clients_1.disconnectHailerClientByApiKey)(this.originalApiKey);
1014
+ this.originalApiKey = null;
1015
+ }
1016
+ this.botClient.signalHandler.unsubscribe(`daemon-${this.botClient.userId}`);
1017
+ this.logger.info("Chat Agent Daemon stopped", {
1018
+ agentDirectoryId: this.registryService?.getAgentDirectoryId(),
1019
+ activeSessions: this.sessionLogger?.getActiveSessions().size ?? 0,
1020
+ });
1021
+ }
1022
+ /**
1023
+ * Get current conversation state (for debugging)
1024
+ */
1025
+ getConversationState() {
1026
+ // Get current discussion's conversation
1027
+ const currentConversation = this.currentDiscussionId
1028
+ ? this.conversationManager.getConversation(this.currentDiscussionId)
1029
+ : [];
1030
+ // Get last 5 messages with preview
1031
+ const lastMessages = currentConversation.slice(-5).map(msg => {
1032
+ let preview = "";
1033
+ if (typeof msg.content === "string") {
1034
+ preview = msg.content.substring(0, 100);
1035
+ }
1036
+ else if (Array.isArray(msg.content)) {
1037
+ const textBlock = msg.content.find((b) => b.type === "text");
1038
+ preview = textBlock?.text?.substring(0, 100) || "[tool call/result]";
1039
+ }
1040
+ return {
1041
+ role: msg.role,
1042
+ preview: preview + (preview.length >= 100 ? "..." : ""),
1043
+ };
1044
+ });
1045
+ const state = this.conversationManager.getState(this.currentDiscussionId ?? undefined);
1046
+ return {
1047
+ discussionCount: state.discussionCount,
1048
+ currentDiscussion: this.currentDiscussionId,
1049
+ currentMessageCount: currentConversation.length,
1050
+ queueLength: this.messageQueue.length,
1051
+ lastMessages,
1052
+ isProcessing: this.isProcessing,
1053
+ };
1054
+ }
1055
+ // ===== AGENT REGISTRY & SESSION LOGGING METHODS =====
1056
+ /**
1057
+ * Get agent's display name (override in subclass for custom names)
1058
+ * Default implementation uses the actual Hailer user name from BotClient
1059
+ */
1060
+ getAgentName() {
1061
+ // Use actual Hailer user name from BotClient (populated from workspace cache)
1062
+ return {
1063
+ firstName: this.botClient.firstName,
1064
+ lastName: this.botClient.lastName,
1065
+ };
1066
+ }
1067
+ /**
1068
+ * Get agent's description/system prompt (override in subclass)
1069
+ */
1070
+ getAgentDescription() {
1071
+ return "Chat Agent Daemon - handles general workspace conversations";
1072
+ }
1073
+ /**
1074
+ * Get default team ID from workspace cache
1075
+ * Returns the first available team, or undefined if no teams exist
1076
+ *
1077
+ * Teams structure in init is: { teams: { workspaceId: { teamId: teamData, ... } } }
1078
+ */
1079
+ getDefaultTeamId() {
1080
+ const rawInit = this.botClient.workspaceCache?.rawInit;
1081
+ if (!rawInit?.teams) {
1082
+ this.logger.debug("No teams in workspace cache");
1083
+ return undefined;
1084
+ }
1085
+ // Teams are nested under workspace ID
1086
+ // Structure: { workspaceId: { teamId1: {...}, teamId2: {...} } }
1087
+ const workspaceTeams = Object.values(rawInit.teams)[0];
1088
+ if (!workspaceTeams || typeof workspaceTeams !== 'object') {
1089
+ this.logger.debug("No workspace teams found");
1090
+ return undefined;
1091
+ }
1092
+ const teamIds = Object.keys(workspaceTeams);
1093
+ if (teamIds.length === 0) {
1094
+ this.logger.debug("No teams available in workspace");
1095
+ return undefined;
1096
+ }
1097
+ const defaultTeamId = teamIds[0];
1098
+ const teamName = workspaceTeams[defaultTeamId]?.name || 'unknown';
1099
+ this.logger.debug("Using default team", { teamId: defaultTeamId, teamName, teamCount: teamIds.length });
1100
+ return defaultTeamId;
1101
+ }
1102
+ /**
1103
+ * Get agent's Position details (override in subclass for custom positions)
1104
+ */
1105
+ getPositionDetails() {
1106
+ return {
1107
+ name: "Chat Agent",
1108
+ purpose: "General workspace assistant that monitors discussions and responds to user queries.",
1109
+ personaTone: "Professional, helpful, and concise. Responds directly without unnecessary filler.",
1110
+ coreCapabilities: "- Monitor workspace discussions\n- Answer questions about workflows and activities\n- Execute MCP tools to read/write data\n- Tag users and link activities",
1111
+ boundaries: "- Never fabricate data - always use tools\n- Don't respond to off-topic messages\n- Don't share sensitive credentials",
1112
+ };
1113
+ }
1114
+ /**
1115
+ * Get agent directory ID
1116
+ */
1117
+ getAgentDirectoryId() {
1118
+ return this.registryService?.getAgentDirectoryId() || null;
1119
+ }
1120
+ }
1121
+ exports.ChatAgentDaemon = ChatAgentDaemon;
1122
+ //# sourceMappingURL=base.js.map