@johpaz/hive-agents 0.0.39 → 0.0.40

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 (202) hide show
  1. package/README.md +29 -69
  2. package/dist/hive.js +2522 -1927
  3. package/dist/tool-worker.js +1791 -1334
  4. package/dist/ui/assets/AgentCreateForm-b7xHyfNc.js +1 -0
  5. package/dist/ui/assets/AgentDetailPage-VHy3M7mI.js +1 -0
  6. package/dist/ui/assets/AgentNewPage-BnWImQMx.js +1 -0
  7. package/dist/ui/{dist/assets/AgentsPage-C-GSRk-N.js → assets/AgentsPage-WFy5abqx.js} +1 -1
  8. package/dist/ui/assets/ApiClientPage-BV7zLIL7.js +3 -0
  9. package/dist/ui/assets/{CanvasPage-Cvs5ctza.js → CanvasPage-B9zuIrTm.js} +1 -1
  10. package/dist/ui/assets/{ChannelsPage-C5m_L7P9.js → ChannelsPage-DiN3NvIM.js} +1 -1
  11. package/dist/ui/assets/{DashboardPage-CztbRQdm.js → DashboardPage-CHjARjVK.js} +1 -1
  12. package/dist/ui/assets/{LoginPage-OMsrx5oj.js → LoginPage-Dwd_XxoU.js} +1 -1
  13. package/dist/ui/{dist/assets/LogsPage-CcYYwjgF.js → assets/LogsPage-DW8Nnqe6.js} +1 -1
  14. package/dist/ui/assets/MeetingPage-D3bkiKYt.js +1 -0
  15. package/dist/ui/assets/{NotFound-GbAJDgoD.js → NotFound-BIUDlIXU.js} +1 -1
  16. package/dist/ui/assets/ProvidersPage-UqsDAxPQ.js +1 -0
  17. package/dist/ui/{dist/assets/RecoverPage-CwB2ByCU.js → assets/RecoverPage-8hTjr_JU.js} +1 -1
  18. package/dist/ui/assets/SettingsPage-DNa0jOkA.js +9 -0
  19. package/dist/ui/assets/{SetupPage-DOVh1ldK.js → SetupPage-Bdm2irQG.js} +1 -1
  20. package/dist/ui/assets/WebChatPage-DElJg6P2.js +16 -0
  21. package/dist/ui/assets/accordion-CnLzKNHK.js +1 -0
  22. package/dist/ui/{dist/assets/alert-D_2Y3qjL.js → assets/alert-DylmSCDJ.js} +1 -1
  23. package/dist/ui/{dist/assets/alert-dialog-CpMxaNcu.js → assets/alert-dialog-DNNWN_SI.js} +1 -1
  24. package/dist/ui/assets/{badge-CxTPR6_t.js → badge-ChENFgkC.js} +1 -1
  25. package/dist/ui/assets/chevron-down-DIosfU_U.js +1 -0
  26. package/dist/ui/assets/chevron-up-CI-W21Fy.js +1 -0
  27. package/dist/ui/{dist/assets/dialog-DfS3idb3.js → assets/dialog-BJ-npIv8.js} +1 -1
  28. package/dist/ui/assets/{dropdown-menu-BdCbAW1z.js → dropdown-menu-DDiaHg5y.js} +1 -1
  29. package/dist/ui/assets/{es-Cz5h9_84.js → es-ecSKCyB6.js} +1 -1
  30. package/dist/ui/assets/index-CawKP29y.js +116 -0
  31. package/dist/ui/assets/index-DIcsEkyd.css +2 -0
  32. package/dist/ui/{dist/assets/label-byJkqOYq.js → assets/label-Bi6udtSd.js} +1 -1
  33. package/dist/ui/assets/select-BQCOjM2j.js +1 -0
  34. package/dist/ui/assets/useProviders-Dlizq_8q.js +1 -0
  35. package/dist/ui/dist/assets/AgentCreateForm-b7xHyfNc.js +1 -0
  36. package/dist/ui/dist/assets/AgentDetailPage-VHy3M7mI.js +1 -0
  37. package/dist/ui/dist/assets/AgentNewPage-BnWImQMx.js +1 -0
  38. package/dist/ui/{assets/AgentsPage-C-GSRk-N.js → dist/assets/AgentsPage-WFy5abqx.js} +1 -1
  39. package/dist/ui/dist/assets/ApiClientPage-BV7zLIL7.js +3 -0
  40. package/dist/ui/dist/assets/{CanvasPage-Cvs5ctza.js → CanvasPage-B9zuIrTm.js} +1 -1
  41. package/dist/ui/dist/assets/{ChannelsPage-C5m_L7P9.js → ChannelsPage-DiN3NvIM.js} +1 -1
  42. package/dist/ui/dist/assets/{DashboardPage-CztbRQdm.js → DashboardPage-CHjARjVK.js} +1 -1
  43. package/dist/ui/dist/assets/{LoginPage-OMsrx5oj.js → LoginPage-Dwd_XxoU.js} +1 -1
  44. package/dist/ui/{assets/LogsPage-CcYYwjgF.js → dist/assets/LogsPage-DW8Nnqe6.js} +1 -1
  45. package/dist/ui/dist/assets/MeetingPage-D3bkiKYt.js +1 -0
  46. package/dist/ui/dist/assets/{NotFound-GbAJDgoD.js → NotFound-BIUDlIXU.js} +1 -1
  47. package/dist/ui/dist/assets/ProvidersPage-UqsDAxPQ.js +1 -0
  48. package/dist/ui/{assets/RecoverPage-CwB2ByCU.js → dist/assets/RecoverPage-8hTjr_JU.js} +1 -1
  49. package/dist/ui/dist/assets/SettingsPage-DNa0jOkA.js +9 -0
  50. package/dist/ui/dist/assets/{SetupPage-DOVh1ldK.js → SetupPage-Bdm2irQG.js} +1 -1
  51. package/dist/ui/dist/assets/WebChatPage-DElJg6P2.js +16 -0
  52. package/dist/ui/dist/assets/accordion-CnLzKNHK.js +1 -0
  53. package/dist/ui/{assets/alert-D_2Y3qjL.js → dist/assets/alert-DylmSCDJ.js} +1 -1
  54. package/dist/ui/{assets/alert-dialog-CpMxaNcu.js → dist/assets/alert-dialog-DNNWN_SI.js} +1 -1
  55. package/dist/ui/dist/assets/{badge-CxTPR6_t.js → badge-ChENFgkC.js} +1 -1
  56. package/dist/ui/dist/assets/chevron-down-DIosfU_U.js +1 -0
  57. package/dist/ui/dist/assets/chevron-up-CI-W21Fy.js +1 -0
  58. package/dist/ui/{assets/dialog-DfS3idb3.js → dist/assets/dialog-BJ-npIv8.js} +1 -1
  59. package/dist/ui/dist/assets/{dropdown-menu-BdCbAW1z.js → dropdown-menu-DDiaHg5y.js} +1 -1
  60. package/dist/ui/dist/assets/{es-Cz5h9_84.js → es-ecSKCyB6.js} +1 -1
  61. package/dist/ui/dist/assets/index-CawKP29y.js +116 -0
  62. package/dist/ui/dist/assets/index-DIcsEkyd.css +2 -0
  63. package/dist/ui/{assets/label-byJkqOYq.js → dist/assets/label-Bi6udtSd.js} +1 -1
  64. package/dist/ui/dist/assets/select-BQCOjM2j.js +1 -0
  65. package/dist/ui/dist/assets/useProviders-Dlizq_8q.js +1 -0
  66. package/dist/ui/dist/index.html +4 -4
  67. package/dist/ui/index.html +4 -4
  68. package/package.json +1 -1
  69. package/packages/cli/src/commands/gateway.ts +1 -1
  70. package/packages/cli/src/commands/onboard.ts +27 -1
  71. package/packages/core/src/agent/agent-loop.ts +104 -2
  72. package/packages/core/src/agent/context-compiler.ts +6 -0
  73. package/packages/core/src/agent/llm-client.ts +2 -0
  74. package/packages/core/src/agent/llm-providers/hiveagents.ts +248 -0
  75. package/packages/core/src/agent/llm-providers/interface.ts +2 -0
  76. package/packages/core/src/agent/llm-providers/openai-compat-base.ts +49 -25
  77. package/packages/core/src/agent/providers/index.ts +3 -2
  78. package/packages/core/src/agent/stuck-loop.ts +90 -14
  79. package/packages/core/src/channels/base.ts +7 -1
  80. package/packages/core/src/config/loader.ts +1 -1
  81. package/packages/core/src/gateway/routes/providers.ts +56 -0
  82. package/packages/core/src/gateway/server.ts +120 -55
  83. package/packages/core/src/gateway/slash-commands.ts +7 -1
  84. package/packages/core/src/storage/onboarding.ts +28 -0
  85. package/packages/core/src/storage/seed.ts +14 -0
  86. package/packages/skills/src/bundled-data.generated.ts +1357 -1357
  87. package/dist/ui/assets/AgentCreateForm-BTCzFbca.js +0 -1
  88. package/dist/ui/assets/AgentDetailPage-o27TRSVw.js +0 -1
  89. package/dist/ui/assets/AgentNewPage-400cCpYt.js +0 -1
  90. package/dist/ui/assets/ApiClientPage-BOTpz6oP.js +0 -3
  91. package/dist/ui/assets/MeetingPage-CrKVAfe6.js +0 -1
  92. package/dist/ui/assets/ProvidersPage-uqPcZUSV.js +0 -1
  93. package/dist/ui/assets/SettingsPage-DKLlye0z.js +0 -9
  94. package/dist/ui/assets/WebChatPage-c-7S9jnT.js +0 -16
  95. package/dist/ui/assets/accordion-DAbcVQCn.js +0 -1
  96. package/dist/ui/assets/chevron-up-BYhk0K2J.js +0 -1
  97. package/dist/ui/assets/index-CmGm_r89.js +0 -116
  98. package/dist/ui/assets/index-T7HgphSn.css +0 -2
  99. package/dist/ui/assets/select-Cl16QYa_.js +0 -1
  100. package/dist/ui/assets/useProviders-eEri6BAc.js +0 -1
  101. package/dist/ui/dist/assets/AgentCreateForm-BTCzFbca.js +0 -1
  102. package/dist/ui/dist/assets/AgentDetailPage-o27TRSVw.js +0 -1
  103. package/dist/ui/dist/assets/AgentNewPage-400cCpYt.js +0 -1
  104. package/dist/ui/dist/assets/ApiClientPage-BOTpz6oP.js +0 -3
  105. package/dist/ui/dist/assets/MeetingPage-CrKVAfe6.js +0 -1
  106. package/dist/ui/dist/assets/ProvidersPage-uqPcZUSV.js +0 -1
  107. package/dist/ui/dist/assets/SettingsPage-DKLlye0z.js +0 -9
  108. package/dist/ui/dist/assets/WebChatPage-c-7S9jnT.js +0 -16
  109. package/dist/ui/dist/assets/accordion-DAbcVQCn.js +0 -1
  110. package/dist/ui/dist/assets/chevron-up-BYhk0K2J.js +0 -1
  111. package/dist/ui/dist/assets/index-CmGm_r89.js +0 -116
  112. package/dist/ui/dist/assets/index-T7HgphSn.css +0 -2
  113. package/dist/ui/dist/assets/select-Cl16QYa_.js +0 -1
  114. package/dist/ui/dist/assets/useProviders-eEri6BAc.js +0 -1
  115. /package/dist/ui/assets/{card-CXAm46at.js → card-DFKnZ6ky.js} +0 -0
  116. /package/dist/ui/assets/{circle-alert-CyHDwUj8.js → circle-alert-KuAm2FWh.js} +0 -0
  117. /package/dist/ui/assets/{circle-check-Bb54Ebmu.js → circle-check-6Ard1-2z.js} +0 -0
  118. /package/dist/ui/assets/{circle-x-Bv6WrUJo.js → circle-x-DjLkFDO8.js} +0 -0
  119. /package/dist/ui/assets/{copy-dU94ZGsi.js → copy-Bu5d7C-0.js} +0 -0
  120. /package/dist/ui/assets/{cpu-DSpPVLAz.js → cpu-KDy6-FAI.js} +0 -0
  121. /package/dist/ui/assets/{download-D9ZyUZZR.js → download-Cjbk4Rek.js} +0 -0
  122. /package/dist/ui/assets/{external-link-CHPbUorN.js → external-link-6sTlRDUR.js} +0 -0
  123. /package/dist/ui/assets/{eye-epHJZ_nQ.js → eye-Df8o0tkC.js} +0 -0
  124. /package/dist/ui/assets/{file-text-BEjEmgby.js → file-text-lnxnjBp0.js} +0 -0
  125. /package/dist/ui/assets/{folder-open-iQMHVEqS.js → folder-open-DJBLDFjv.js} +0 -0
  126. /package/dist/ui/assets/{format-oFACFaca.js → format-BwdV8bB5.js} +0 -0
  127. /package/dist/ui/assets/{gateway-url-iG-C6Agn.js → gateway-url-DwzPmoc8.js} +0 -0
  128. /package/dist/ui/assets/{gauge-D0_GMEcq.js → gauge-B8Tj43rC.js} +0 -0
  129. /package/dist/ui/assets/{hexagon-DsGOUl-H.js → hexagon-6L79pgVK.js} +0 -0
  130. /package/dist/ui/assets/{history-BSG-Ypqf.js → history-CAF_R34_.js} +0 -0
  131. /package/dist/ui/assets/{info-NwLoa2Mj.js → info-WjromB4Y.js} +0 -0
  132. /package/dist/ui/assets/{key-3EP0dhkT.js → key-DyKOoQh5.js} +0 -0
  133. /package/dist/ui/assets/{loader-circle-CZNax6kS.js → loader-circle-BmBOgYze.js} +0 -0
  134. /package/dist/ui/assets/{lock-Ei1_J-Nq.js → lock-BS6OLXPv.js} +0 -0
  135. /package/dist/ui/assets/{pause-BUqah9Bi.js → pause-VqeUmp2Z.js} +0 -0
  136. /package/dist/ui/assets/{play-NcZ4swwL.js → play-zJpWuhrr.js} +0 -0
  137. /package/dist/ui/assets/{plus-CX1xyhp5.js → plus-BZQX26Dr.js} +0 -0
  138. /package/dist/ui/assets/{progress-Dtz-Mzys.js → progress-D5c-Eilm.js} +0 -0
  139. /package/dist/ui/assets/{refresh-cw-DaYdjQFk.js → refresh-cw-CCzDCAuz.js} +0 -0
  140. /package/dist/ui/assets/{save-CUdYyHNy.js → save-hUmZhceG.js} +0 -0
  141. /package/dist/ui/assets/{scroll-area-BXtLsE9E.js → scroll-area-CihOx0cb.js} +0 -0
  142. /package/dist/ui/assets/{search-BGmPJ-6L.js → search-DzDptO9s.js} +0 -0
  143. /package/dist/ui/assets/{send-BuQcUO-R.js → send-BPk9XbIq.js} +0 -0
  144. /package/dist/ui/assets/{settings-CcMGI1iU.js → settings-BGfrZ_zM.js} +0 -0
  145. /package/dist/ui/assets/{shield-C-05qB-2.js → shield-CxhcUT39.js} +0 -0
  146. /package/dist/ui/assets/{slider-D2I0qven.js → slider-bcUiUfx0.js} +0 -0
  147. /package/dist/ui/assets/{sparkles-D6fx8JC5.js → sparkles-BhwlS1pc.js} +0 -0
  148. /package/dist/ui/assets/{square-BD81nFtN.js → square-DMNWw4Hi.js} +0 -0
  149. /package/dist/ui/assets/{switch-h2SfQX4B.js → switch-BR30E4ej.js} +0 -0
  150. /package/dist/ui/assets/{table-CVkIRJKK.js → table-B3aGEaVp.js} +0 -0
  151. /package/dist/ui/assets/{tabs-C619jxbO.js → tabs-LQidMKRS.js} +0 -0
  152. /package/dist/ui/assets/{terminal-DN38Q456.js → terminal--7G943As.js} +0 -0
  153. /package/dist/ui/assets/{textarea-wvA-FDjO.js → textarea-B6Z1Zc6W.js} +0 -0
  154. /package/dist/ui/assets/{trash-2-BHRa5ft9.js → trash-2-xD2o4SgX.js} +0 -0
  155. /package/dist/ui/assets/{triangle-alert-D4nwAVbc.js → triangle-alert-pVIJGjga.js} +0 -0
  156. /package/dist/ui/assets/{vendor-router-pCP7sjma.js → vendor-router-gqiZ7xhx.js} +0 -0
  157. /package/dist/ui/assets/{volume-2-B6tkRy2u.js → volume-2-BekVQl6P.js} +0 -0
  158. /package/dist/ui/assets/{zap-QO7iWMRg.js → zap-B4RaNNO5.js} +0 -0
  159. /package/dist/ui/dist/assets/{card-CXAm46at.js → card-DFKnZ6ky.js} +0 -0
  160. /package/dist/ui/dist/assets/{circle-alert-CyHDwUj8.js → circle-alert-KuAm2FWh.js} +0 -0
  161. /package/dist/ui/dist/assets/{circle-check-Bb54Ebmu.js → circle-check-6Ard1-2z.js} +0 -0
  162. /package/dist/ui/dist/assets/{circle-x-Bv6WrUJo.js → circle-x-DjLkFDO8.js} +0 -0
  163. /package/dist/ui/dist/assets/{copy-dU94ZGsi.js → copy-Bu5d7C-0.js} +0 -0
  164. /package/dist/ui/dist/assets/{cpu-DSpPVLAz.js → cpu-KDy6-FAI.js} +0 -0
  165. /package/dist/ui/dist/assets/{download-D9ZyUZZR.js → download-Cjbk4Rek.js} +0 -0
  166. /package/dist/ui/dist/assets/{external-link-CHPbUorN.js → external-link-6sTlRDUR.js} +0 -0
  167. /package/dist/ui/dist/assets/{eye-epHJZ_nQ.js → eye-Df8o0tkC.js} +0 -0
  168. /package/dist/ui/dist/assets/{file-text-BEjEmgby.js → file-text-lnxnjBp0.js} +0 -0
  169. /package/dist/ui/dist/assets/{folder-open-iQMHVEqS.js → folder-open-DJBLDFjv.js} +0 -0
  170. /package/dist/ui/dist/assets/{format-oFACFaca.js → format-BwdV8bB5.js} +0 -0
  171. /package/dist/ui/dist/assets/{gateway-url-iG-C6Agn.js → gateway-url-DwzPmoc8.js} +0 -0
  172. /package/dist/ui/dist/assets/{gauge-D0_GMEcq.js → gauge-B8Tj43rC.js} +0 -0
  173. /package/dist/ui/dist/assets/{hexagon-DsGOUl-H.js → hexagon-6L79pgVK.js} +0 -0
  174. /package/dist/ui/dist/assets/{history-BSG-Ypqf.js → history-CAF_R34_.js} +0 -0
  175. /package/dist/ui/dist/assets/{info-NwLoa2Mj.js → info-WjromB4Y.js} +0 -0
  176. /package/dist/ui/dist/assets/{key-3EP0dhkT.js → key-DyKOoQh5.js} +0 -0
  177. /package/dist/ui/dist/assets/{loader-circle-CZNax6kS.js → loader-circle-BmBOgYze.js} +0 -0
  178. /package/dist/ui/dist/assets/{lock-Ei1_J-Nq.js → lock-BS6OLXPv.js} +0 -0
  179. /package/dist/ui/dist/assets/{pause-BUqah9Bi.js → pause-VqeUmp2Z.js} +0 -0
  180. /package/dist/ui/dist/assets/{play-NcZ4swwL.js → play-zJpWuhrr.js} +0 -0
  181. /package/dist/ui/dist/assets/{plus-CX1xyhp5.js → plus-BZQX26Dr.js} +0 -0
  182. /package/dist/ui/dist/assets/{progress-Dtz-Mzys.js → progress-D5c-Eilm.js} +0 -0
  183. /package/dist/ui/dist/assets/{refresh-cw-DaYdjQFk.js → refresh-cw-CCzDCAuz.js} +0 -0
  184. /package/dist/ui/dist/assets/{save-CUdYyHNy.js → save-hUmZhceG.js} +0 -0
  185. /package/dist/ui/dist/assets/{scroll-area-BXtLsE9E.js → scroll-area-CihOx0cb.js} +0 -0
  186. /package/dist/ui/dist/assets/{search-BGmPJ-6L.js → search-DzDptO9s.js} +0 -0
  187. /package/dist/ui/dist/assets/{send-BuQcUO-R.js → send-BPk9XbIq.js} +0 -0
  188. /package/dist/ui/dist/assets/{settings-CcMGI1iU.js → settings-BGfrZ_zM.js} +0 -0
  189. /package/dist/ui/dist/assets/{shield-C-05qB-2.js → shield-CxhcUT39.js} +0 -0
  190. /package/dist/ui/dist/assets/{slider-D2I0qven.js → slider-bcUiUfx0.js} +0 -0
  191. /package/dist/ui/dist/assets/{sparkles-D6fx8JC5.js → sparkles-BhwlS1pc.js} +0 -0
  192. /package/dist/ui/dist/assets/{square-BD81nFtN.js → square-DMNWw4Hi.js} +0 -0
  193. /package/dist/ui/dist/assets/{switch-h2SfQX4B.js → switch-BR30E4ej.js} +0 -0
  194. /package/dist/ui/dist/assets/{table-CVkIRJKK.js → table-B3aGEaVp.js} +0 -0
  195. /package/dist/ui/dist/assets/{tabs-C619jxbO.js → tabs-LQidMKRS.js} +0 -0
  196. /package/dist/ui/dist/assets/{terminal-DN38Q456.js → terminal--7G943As.js} +0 -0
  197. /package/dist/ui/dist/assets/{textarea-wvA-FDjO.js → textarea-B6Z1Zc6W.js} +0 -0
  198. /package/dist/ui/dist/assets/{trash-2-BHRa5ft9.js → trash-2-xD2o4SgX.js} +0 -0
  199. /package/dist/ui/dist/assets/{triangle-alert-D4nwAVbc.js → triangle-alert-pVIJGjga.js} +0 -0
  200. /package/dist/ui/dist/assets/{vendor-router-pCP7sjma.js → vendor-router-gqiZ7xhx.js} +0 -0
  201. /package/dist/ui/dist/assets/{volume-2-B6tkRy2u.js → volume-2-BekVQl6P.js} +0 -0
  202. /package/dist/ui/dist/assets/{zap-QO7iWMRg.js → zap-B4RaNNO5.js} +0 -0
@@ -5416,7 +5416,7 @@ var init_loader = __esm(() => {
5416
5416
  tools: ToolRestrictionsSchema.optional()
5417
5417
  });
5418
5418
  ModelsConfigSchema = object({
5419
- defaultProvider: _enum(["openai", "anthropic", "gemini", "mistral", "kimi", "ollama", "openrouter", "deepseek"]).optional(),
5419
+ defaultProvider: _enum(["openai", "anthropic", "gemini", "mistral", "kimi", "ollama", "openrouter", "deepseek", "hiveagents"]).optional(),
5420
5420
  defaults: record(string2(), string2()).optional(),
5421
5421
  providers: record(string2(), ProviderConfigSchema).optional()
5422
5422
  });
@@ -10044,7 +10044,8 @@ var init_interface = __esm(() => {
10044
10044
  nvidia: "https://integrate.api.nvidia.com/v1",
10045
10045
  qwen: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
10046
10046
  minimax: "https://api.minimaxi.com/v1",
10047
- "opencode-go": "https://opencode.ai/zen/go/v1"
10047
+ "opencode-go": "https://opencode.ai/zen/go/v1",
10048
+ hiveagents: "https://llm.hiveagents.io/v1"
10048
10049
  };
10049
10050
  DEFAULT_PROFILE = {
10050
10051
  normalizeToolNames: false,
@@ -10065,7 +10066,8 @@ var init_interface = __esm(() => {
10065
10066
  qwen: { ...DEFAULT_PROFILE, normalizeToolNames: true, retryWithoutToolsOnCodes: [400, 422] },
10066
10067
  "local-llama": { ...DEFAULT_PROFILE },
10067
10068
  minimax: { ...DEFAULT_PROFILE, normalizeToolNames: true, retryWithoutToolsOnCodes: [400, 422] },
10068
- "opencode-go": { ...DEFAULT_PROFILE, normalizeToolNames: true, retryWithoutToolsOnCodes: [400, 422] }
10069
+ "opencode-go": { ...DEFAULT_PROFILE, normalizeToolNames: true, retryWithoutToolsOnCodes: [400, 422] },
10070
+ hiveagents: { ...DEFAULT_PROFILE, retryWithoutToolsOnCodes: [400, 422] }
10069
10071
  };
10070
10072
  NO_TOOL_MODELS = new Set([
10071
10073
  "deepseek-reasoner",
@@ -50997,8 +50999,15 @@ class OpenAICompatBase {
50997
50999
  isLocalProvider() {
50998
51000
  return false;
50999
51001
  }
51002
+ async resolveOpenAIClient(apiKey, baseURL) {
51003
+ const { default: OpenAI2 } = await Promise.resolve().then(() => (init_openai(), exports_openai));
51004
+ return new OpenAI2({ apiKey, baseURL });
51005
+ }
51000
51006
  async beforeCall(_options) {}
51001
51007
  injectToolsIntoPrompt(_body, _preparedTools) {}
51008
+ modifyRequestBody(body, _options) {
51009
+ return body;
51010
+ }
51002
51011
  _convertContentPart(part) {
51003
51012
  switch (part.type) {
51004
51013
  case "text":
@@ -51021,7 +51030,6 @@ class OpenAICompatBase {
51021
51030
  return msg;
51022
51031
  }
51023
51032
  async call(options) {
51024
- const { default: OpenAI2 } = await Promise.resolve().then(() => (init_openai(), exports_openai));
51025
51033
  const baseURL = options.baseUrl?.trim() || OPENAI_COMPAT_BASE_URLS[this.providerName] || undefined;
51026
51034
  const isLocal = this.isLocalProvider();
51027
51035
  await this.beforeCall(options);
@@ -51029,7 +51037,7 @@ class OpenAICompatBase {
51029
51037
  if (!apiKey) {
51030
51038
  throw new Error(`API key missing for provider: ${this.providerName}. Configure it in Settings \u2192 Providers.`);
51031
51039
  }
51032
- const client = new OpenAI2({ apiKey, baseURL });
51040
+ const client = await this.resolveOpenAIClient(apiKey, baseURL);
51033
51041
  const sanitized = sanitizeMessages(options.messages);
51034
51042
  const rawMessages = this.needsReasoningRoundtrip() ? sanitized : sanitized.map(({ reasoning_content: _rc, ...rest }) => rest);
51035
51043
  const messagesForProvider = rawMessages.map((m2) => this._convertMessage(m2));
@@ -51076,7 +51084,7 @@ class OpenAICompatBase {
51076
51084
  }
51077
51085
  let response;
51078
51086
  try {
51079
- response = await client.chat.completions.create(body);
51087
+ response = await client.chat.completions.create(this.modifyRequestBody(body, options));
51080
51088
  } catch (err) {
51081
51089
  const status = err?.status ?? err?.response?.status;
51082
51090
  const errMsg = (err?.error?.message ?? err?.message ?? "").toLowerCase();
@@ -51086,7 +51094,7 @@ class OpenAICompatBase {
51086
51094
  delete bodyNoTools.tools;
51087
51095
  delete bodyNoTools.tool_choice;
51088
51096
  delete bodyNoTools.parallel_tool_calls;
51089
- response = await client.chat.completions.create(bodyNoTools);
51097
+ response = await client.chat.completions.create(this.modifyRequestBody(bodyNoTools, options));
51090
51098
  } else if (status === 400 && (errMsg.includes("context length") || errMsg.includes("input_tokens") || errMsg.includes("maximum input length"))) {
51091
51099
  log26.warn(`[llm-client] ${this.providerName}: context overflow \u2014 compacting messages and retrying`);
51092
51100
  const compacted = [...body.messages];
@@ -51105,7 +51113,7 @@ class OpenAICompatBase {
51105
51113
  if (body.max_tokens)
51106
51114
  body.max_tokens = Math.min(body.max_tokens, 4096);
51107
51115
  log26.info(`[llm-client] ${this.providerName}: compacted ${compacted.length} msgs \u2192 ${body.messages.length} msgs, max_tokens=${body.max_tokens}`);
51108
- response = await client.chat.completions.create(body);
51116
+ response = await client.chat.completions.create(this.modifyRequestBody(body, options));
51109
51117
  } else {
51110
51118
  throw err;
51111
51119
  }
@@ -51142,7 +51150,7 @@ class OpenAICompatBase {
51142
51150
  async _streamCall(client, body, options, toolNameMap, sendTools, profile) {
51143
51151
  let stream;
51144
51152
  try {
51145
- stream = await client.chat.completions.create({ ...body, stream: true });
51153
+ stream = await client.chat.completions.create({ ...this.modifyRequestBody(body, options), stream: true });
51146
51154
  } catch (err) {
51147
51155
  const status = err?.status ?? err?.response?.status;
51148
51156
  const errMsg = (err?.error?.message ?? err?.message ?? "").toLowerCase();
@@ -51152,7 +51160,7 @@ class OpenAICompatBase {
51152
51160
  delete bodyNoTools.tools;
51153
51161
  delete bodyNoTools.tool_choice;
51154
51162
  delete bodyNoTools.parallel_tool_calls;
51155
- stream = await client.chat.completions.create({ ...bodyNoTools, stream: true });
51163
+ stream = await client.chat.completions.create({ ...this.modifyRequestBody(bodyNoTools, options), stream: true });
51156
51164
  } else if (status === 400 && (errMsg.includes("context length") || errMsg.includes("input_tokens") || errMsg.includes("maximum input length"))) {
51157
51165
  log26.warn(`[llm-client] ${this.providerName}: context overflow \u2014 compacting messages and retrying stream`);
51158
51166
  const compacted = [...body.messages];
@@ -51171,7 +51179,7 @@ class OpenAICompatBase {
51171
51179
  if (body.max_tokens)
51172
51180
  body.max_tokens = Math.min(body.max_tokens, 4096);
51173
51181
  log26.info(`[llm-client] ${this.providerName}: compacted ${compacted.length} msgs \u2192 ${body.messages.length} msgs, max_tokens=${body.max_tokens}`);
51174
- stream = await client.chat.completions.create({ ...body, stream: true });
51182
+ stream = await client.chat.completions.create({ ...this.modifyRequestBody(body, options), stream: true });
51175
51183
  } else {
51176
51184
  throw err;
51177
51185
  }
@@ -51255,13 +51263,21 @@ function extractToolCallsFromText(content, toolNameMap, knownToolNames) {
51255
51263
  while ((match = regex.exec(content)) !== null) {
51256
51264
  try {
51257
51265
  const json = JSON.parse(match[1]);
51258
- if (json.name) {
51266
+ const calls = Array.isArray(json) ? json : [json];
51267
+ for (const call of calls) {
51268
+ if (!call)
51269
+ continue;
51270
+ const fn = call.function || call;
51271
+ const name = fn.name ?? call.name;
51272
+ let args = fn.arguments ?? call.arguments ?? call.parameters;
51273
+ if (!name)
51274
+ continue;
51259
51275
  tool_calls.push({
51260
51276
  id: crypto.randomUUID(),
51261
51277
  type: "function",
51262
51278
  function: {
51263
- name: toolNameMap.get(json.name) ?? json.name,
51264
- arguments: typeof json.arguments === "object" ? JSON.stringify(json.arguments) : json.arguments || "{}"
51279
+ name: toolNameMap.get(name) ?? name,
51280
+ arguments: typeof args === "object" ? JSON.stringify(args) : args || "{}"
51265
51281
  }
51266
51282
  });
51267
51283
  extractedContent = extractedContent.replace(match[0], "").trim();
@@ -51271,19 +51287,28 @@ function extractToolCallsFromText(content, toolNameMap, knownToolNames) {
51271
51287
  }
51272
51288
  if (tool_calls.length === 0 && knownToolNames && knownToolNames.size > 0) {
51273
51289
  try {
51274
- const json = JSON.parse(content.trim());
51275
- const resolvedName = toolNameMap.get(json.name) ?? json.name;
51276
- if (json.name && knownToolNames.has(resolvedName) && (json.arguments || json.parameters)) {
51277
- const args = json.arguments || json.parameters;
51278
- tool_calls.push({
51279
- id: crypto.randomUUID(),
51280
- type: "function",
51281
- function: {
51282
- name: resolvedName,
51283
- arguments: typeof args === "object" ? JSON.stringify(args) : args || "{}"
51284
- }
51285
- });
51286
- extractedContent = "";
51290
+ const trimmed = content.trim();
51291
+ const jsonText = trimmed.replace(/^```(?:json|tool_call)?\s*|\s*```$/g, "").trim();
51292
+ const json = JSON.parse(jsonText);
51293
+ const calls = Array.isArray(json) ? json : [json];
51294
+ for (const call of calls) {
51295
+ if (!call)
51296
+ continue;
51297
+ const fn = call.function || call;
51298
+ const name = fn.name ?? call.name;
51299
+ let args = fn.arguments ?? call.arguments ?? call.parameters;
51300
+ const resolvedName = toolNameMap.get(name) ?? name;
51301
+ if (name && knownToolNames.has(resolvedName) && (args !== undefined || calls.length === 1)) {
51302
+ tool_calls.push({
51303
+ id: crypto.randomUUID(),
51304
+ type: "function",
51305
+ function: {
51306
+ name: resolvedName,
51307
+ arguments: typeof args === "object" ? JSON.stringify(args) : args || "{}"
51308
+ }
51309
+ });
51310
+ extractedContent = "";
51311
+ }
51287
51312
  }
51288
51313
  } catch {}
51289
51314
  }
@@ -51753,6 +51778,197 @@ var init_opencode_go = __esm(() => {
51753
51778
  };
51754
51779
  });
51755
51780
 
51781
+ // packages/core/src/agent/llm-providers/hiveagents.ts
51782
+ function getApiBase(baseUrl) {
51783
+ return baseUrl?.replace(/\/v1\/?$/, "") || DEFAULT_BASE;
51784
+ }
51785
+ function getAuthHeaders(apiKey) {
51786
+ return {
51787
+ "Content-Type": "application/json",
51788
+ Authorization: `Bearer ${apiKey}`
51789
+ };
51790
+ }
51791
+ async function loadHiveAgentsModel(modelId, apiKey, baseUrl, ctx = HIVEAGENTS_DEFAULT_LOAD_CTX) {
51792
+ const apiBase = getApiBase(baseUrl);
51793
+ const headers = getAuthHeaders(apiKey);
51794
+ const loadBody = {
51795
+ model: modelId,
51796
+ config: { ctx }
51797
+ };
51798
+ try {
51799
+ log29.info(`[hiveagents] \u2192 POST ${apiBase}/api/load`);
51800
+ log29.info(`[hiveagents] \u2192 Body: ${JSON.stringify(loadBody)}`);
51801
+ const res = await fetch(`${apiBase}/api/load`, {
51802
+ method: "POST",
51803
+ headers,
51804
+ body: JSON.stringify(loadBody),
51805
+ signal: AbortSignal.timeout(HIVEAGENTS_LOAD_FETCH_TIMEOUT_MS)
51806
+ });
51807
+ const responseText = await res.text().catch(() => "");
51808
+ if (!res.ok) {
51809
+ const isTransientCloudflareError = [502, 503, 504, 524, 530].includes(res.status);
51810
+ if (isTransientCloudflareError) {
51811
+ log29.warn(`[hiveagents] \u2190 Load request hit transient error (HTTP ${res.status}); backend may still be loading`);
51812
+ return { success: true, loading: true };
51813
+ }
51814
+ log29.error(`[hiveagents] \u2190 Load failed: HTTP ${res.status} ${res.statusText} \u2014 ${responseText}`);
51815
+ return { success: false, error: `Load failed: HTTP ${res.status} \u2014 ${responseText || res.statusText}` };
51816
+ }
51817
+ log29.info(`[hiveagents] \u2190 Load accepted: ${responseText}`);
51818
+ return { success: true };
51819
+ } catch (err) {
51820
+ const msg = err.message || "";
51821
+ if (msg.includes("timed out") || msg.includes("abort") || msg.includes("AbortError")) {
51822
+ log29.warn(`[hiveagents] \u2190 Load request timed out after ${HIVEAGENTS_LOAD_FETCH_TIMEOUT_MS}ms; backend may still be loading`);
51823
+ return { success: true, loading: true };
51824
+ }
51825
+ return { success: false, error: msg };
51826
+ }
51827
+ }
51828
+ async function getHiveAgentsModelStatus(apiKey, baseUrl) {
51829
+ const apiBase = getApiBase(baseUrl);
51830
+ const headers = getAuthHeaders(apiKey);
51831
+ try {
51832
+ const res = await fetch(`${apiBase}/api/status`, { headers });
51833
+ if (!res.ok)
51834
+ return { loaded: false };
51835
+ const data = await res.json();
51836
+ return {
51837
+ loaded: !!data.loaded,
51838
+ model: data.model
51839
+ };
51840
+ } catch {
51841
+ return { loaded: false };
51842
+ }
51843
+ }
51844
+ var log29, DEFAULT_BASE = "https://llm.hiveagents.io", HIVEAGENTS_DEFAULT_LOAD_CTX = 50000, BLOCKED_HEADERS, HIVEAGENTS_LOAD_FETCH_TIMEOUT_MS = 90000, HiveAgentsProvider;
51845
+ var init_hiveagents = __esm(() => {
51846
+ init_logger();
51847
+ init_openai_compat_base();
51848
+ log29 = logger.child("llm-client");
51849
+ BLOCKED_HEADERS = [
51850
+ "user-agent",
51851
+ "x-stainless-lang",
51852
+ "x-stainless-package-version",
51853
+ "x-stainless-runtime",
51854
+ "x-stainless-runtime-version",
51855
+ "x-stainless-arch",
51856
+ "x-stainless-os"
51857
+ ];
51858
+ HiveAgentsProvider = class HiveAgentsProvider extends OpenAICompatBase {
51859
+ _currentModelId = "";
51860
+ constructor() {
51861
+ super("hiveagents");
51862
+ }
51863
+ _isGemma4(modelId) {
51864
+ return /^gemma-?4/i.test(modelId);
51865
+ }
51866
+ _isQwen3(modelId) {
51867
+ return /^qwen3?/i.test(modelId);
51868
+ }
51869
+ async resolveOpenAIClient(apiKey, baseURL) {
51870
+ const { default: OpenAI2 } = await Promise.resolve().then(() => (init_openai(), exports_openai));
51871
+ return new OpenAI2({
51872
+ apiKey,
51873
+ baseURL,
51874
+ fetch: async (url, init) => {
51875
+ const headers = new Headers(init?.headers);
51876
+ for (const h of BLOCKED_HEADERS)
51877
+ headers.delete(h);
51878
+ const headersObj = {};
51879
+ headers.forEach((v2, k2) => {
51880
+ headersObj[k2] = k2.toLowerCase() === "authorization" ? `Bearer \u2022\u2022\u2022\u2022${v2.slice(-6)}` : v2;
51881
+ });
51882
+ log29.info(`[hiveagents] \u2192 POST ${url}`);
51883
+ log29.info(`[hiveagents] \u2192 Headers: ${JSON.stringify(headersObj)}`);
51884
+ if (init?.body) {
51885
+ try {
51886
+ const parsed = JSON.parse(init.body);
51887
+ const summary = { model: parsed.model, messages: parsed.messages?.length, tools: parsed.tools?.length, max_tokens: parsed.max_tokens, temperature: parsed.temperature, tool_choice: parsed.tool_choice, extra_body: parsed.extra_body };
51888
+ log29.info(`[hiveagents] \u2192 Body summary: ${JSON.stringify(summary)}`);
51889
+ } catch {}
51890
+ }
51891
+ const res = await fetch(url, { ...init, headers });
51892
+ log29.info(`[hiveagents] \u2190 Response: ${res.status} ${res.statusText}`);
51893
+ return res;
51894
+ }
51895
+ });
51896
+ }
51897
+ async call(options) {
51898
+ const realModelId = options.model.replace(/^hiveagents\//i, "");
51899
+ if (realModelId && realModelId !== "local") {
51900
+ await this._ensureModelLoaded(realModelId, options);
51901
+ }
51902
+ this._currentModelId = realModelId;
51903
+ let callOptions = { ...options, model: "hiveagents/local" };
51904
+ if (this._isQwen3(realModelId) && options.thinking?.enabled === false) {
51905
+ const msgs = callOptions.messages.map((m2) => ({ ...m2 }));
51906
+ const sysMsg = msgs.find((m2) => m2.role === "system");
51907
+ if (sysMsg && typeof sysMsg.content === "string") {
51908
+ if (!sysMsg.content.startsWith("/no_think"))
51909
+ sysMsg.content = `/no_think
51910
+ ` + sysMsg.content;
51911
+ } else {
51912
+ msgs.unshift({ role: "system", content: "/no_think" });
51913
+ }
51914
+ callOptions = { ...callOptions, messages: msgs };
51915
+ }
51916
+ return super.call(callOptions);
51917
+ }
51918
+ modifyRequestBody(body, options) {
51919
+ if (this._isGemma4(this._currentModelId)) {
51920
+ const enableThinking = options.thinking?.enabled !== false;
51921
+ body.extra_body = {
51922
+ ...body.extra_body ?? {},
51923
+ chat_template_kwargs: { enable_thinking: enableThinking }
51924
+ };
51925
+ }
51926
+ return body;
51927
+ }
51928
+ async _ensureModelLoaded(modelId, options) {
51929
+ const status = await getHiveAgentsModelStatus(options.apiKey, options.baseUrl);
51930
+ if (status.loaded && status.model?.name === modelId) {
51931
+ log29.info(`[hiveagents] Model ${modelId} already loaded`);
51932
+ return;
51933
+ }
51934
+ log29.warn(`[hiveagents] Model ${modelId} not loaded. Triggering load with ctx=${HIVEAGENTS_DEFAULT_LOAD_CTX}`);
51935
+ const result = await loadHiveAgentsModel(modelId, options.apiKey, options.baseUrl);
51936
+ if (!result.success) {
51937
+ log29.warn(`[hiveagents] Auto-load failed for ${modelId}: ${result.error}`);
51938
+ }
51939
+ }
51940
+ injectToolsIntoPrompt(body, preparedTools) {
51941
+ if (body.tools && body.tools.length > 0) {
51942
+ return;
51943
+ }
51944
+ const toolDescriptions = preparedTools.map((t) => JSON.stringify(t.function)).join(`
51945
+ `);
51946
+ const instruction = [
51947
+ "You have access to the following tools.",
51948
+ "When you need to use a tool, output EXACTLY one JSON block wrapped in <tool_call> tags and NOTHING ELSE in that turn:",
51949
+ "",
51950
+ "<tool_call>",
51951
+ '{"name": "browser_navigate", "arguments": {"url": "https://example.com"}}',
51952
+ "</tool_call>",
51953
+ "",
51954
+ "Use the exact tool name and argument names from the list below. Do not add extra text, markdown, or explanations inside the tool_call block.",
51955
+ "",
51956
+ "Tools:",
51957
+ toolDescriptions
51958
+ ].join(`
51959
+ `);
51960
+ const sysMsg = body.messages.find((m2) => m2.role === "system");
51961
+ if (sysMsg) {
51962
+ sysMsg.content += `
51963
+
51964
+ ` + instruction;
51965
+ } else {
51966
+ body.messages.unshift({ role: "system", content: instruction });
51967
+ }
51968
+ }
51969
+ };
51970
+ });
51971
+
51756
51972
  // packages/core/src/storage/crypto.ts
51757
51973
  var exports_crypto = {};
51758
51974
  __export(exports_crypto, {
@@ -52045,7 +52261,7 @@ function persistSecretToDb(name, value) {
52045
52261
  }
52046
52262
  const key = getMasterKey();
52047
52263
  if (!key) {
52048
- log29.warn(`[secrets] No master key in ${process.env.HIVE_HOME || "~/.hive"}/.master.key \u2014 cannot persist ${name} to DB fallback`);
52264
+ log30.warn(`[secrets] No master key in ${process.env.HIVE_HOME || "~/.hive"}/.master.key \u2014 cannot persist ${name} to DB fallback`);
52049
52265
  return false;
52050
52266
  }
52051
52267
  const iv = nodeCrypto.randomBytes(12).toString("hex");
@@ -52057,15 +52273,15 @@ function persistSecretToDb(name, value) {
52057
52273
  db.query(`UPDATE ${table} SET ${column}_encrypted = ?, ${column}_iv = ? WHERE id = ?`).run(enc, iv, id);
52058
52274
  return true;
52059
52275
  } catch (err) {
52060
- log29.warn(`[secrets] DB fallback failed for ${name}: ${err.message}`);
52276
+ log30.warn(`[secrets] DB fallback failed for ${name}: ${err.message}`);
52061
52277
  return false;
52062
52278
  }
52063
52279
  }
52064
- var log29, SERVICE = "hive", _mem, _keychainOk = null;
52280
+ var log30, SERVICE = "hive", _mem, _keychainOk = null;
52065
52281
  var init_crypto = __esm(() => {
52066
52282
  init_logger();
52067
52283
  init_sqlite();
52068
- log29 = logger.child("crypto");
52284
+ log30 = logger.child("crypto");
52069
52285
  _mem = new Map;
52070
52286
  });
52071
52287
 
@@ -52101,8 +52317,10 @@ function getProvider(provider) {
52101
52317
  return new MiniMaxProvider;
52102
52318
  case "opencode-go":
52103
52319
  return new OpenCodeGoProvider;
52320
+ case "hiveagents":
52321
+ return new HiveAgentsProvider;
52104
52322
  default:
52105
- log30.warn(`[llm-client] Unknown provider "${provider}" \u2014 falling back to OpenAI-compatible endpoint`);
52323
+ log31.warn(`[llm-client] Unknown provider "${provider}" \u2014 falling back to OpenAI-compatible endpoint`);
52106
52324
  return new OpenAIProvider;
52107
52325
  }
52108
52326
  }
@@ -52112,7 +52330,7 @@ async function callLLM(options) {
52112
52330
  } catch (err) {
52113
52331
  const msg = err.message;
52114
52332
  const cleanModel = options.model.replace(new RegExp(`^${options.provider}\\/`), "");
52115
- log30.error(`[llm-client] Error calling ${options.provider}/${cleanModel}: ${msg}`, err);
52333
+ log31.error(`[llm-client] Error calling ${options.provider}/${cleanModel}: ${msg}`, err);
52116
52334
  return { content: `[LLM Error] ${msg}`, stop_reason: "error" };
52117
52335
  }
52118
52336
  }
@@ -52136,7 +52354,7 @@ async function resolveProviderConfig(providerId, modelId) {
52136
52354
  contextWindow: modelRow?.context_window ?? undefined
52137
52355
  };
52138
52356
  }
52139
- var log30;
52357
+ var log31;
52140
52358
  var init_llm_client = __esm(() => {
52141
52359
  init_logger();
52142
52360
  init_gemini();
@@ -52153,7 +52371,8 @@ var init_llm_client = __esm(() => {
52153
52371
  init_qwen();
52154
52372
  init_minimax();
52155
52373
  init_opencode_go();
52156
- log30 = logger.child("llm-client");
52374
+ init_hiveagents();
52375
+ log31 = logger.child("llm-client");
52157
52376
  });
52158
52377
 
52159
52378
  // node_modules/.bun/toon-format-parser@1.1.4/node_modules/toon-format-parser/dist/index.mjs
@@ -52616,13 +52835,13 @@ function recordUsage(options) {
52616
52835
  INSERT INTO usage_records (id, provider, model, input_tokens, output_tokens, cost_usd, latency_ms, created_at)
52617
52836
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
52618
52837
  `).run(randomUUID(), options.provider, options.model, options.inputTokens, options.outputTokens, costUsd, options.latencyMs || null, Math.floor(Date.now() / 1000));
52619
- log31.info(`[USAGE RECORDED] provider=${options.provider} model=${options.model} input=${options.inputTokens} output=${options.outputTokens} cost=$${costUsd.toFixed(4)}`);
52838
+ log32.info(`[USAGE RECORDED] provider=${options.provider} model=${options.model} input=${options.inputTokens} output=${options.outputTokens} cost=$${costUsd.toFixed(4)}`);
52620
52839
  } catch (error4) {
52621
52840
  console.error("Failed to record usage:", error4);
52622
52841
  }
52623
52842
  }
52624
52843
  function getUsageStats(hours = 24) {
52625
- log31.info(`[USAGE STATS] Fetching stats for last ${hours} hours`);
52844
+ log32.info(`[USAGE STATS] Fetching stats for last ${hours} hours`);
52626
52845
  const db = getDb();
52627
52846
  const since = Math.floor(Date.now() / 1000) - hours * 3600;
52628
52847
  const totals = db.prepare(`
@@ -52748,17 +52967,17 @@ function recordToonSavings(analysis, costSaved, category) {
52748
52967
  )
52749
52968
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
52750
52969
  `).run(`toon_${category}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`, "toon", category, 0, 0, 0, Math.max(0, analysis.savedTokens), costSaved, analysis.jsonBytes, analysis.toonBytes, analysis.savedBytes, Math.max(0, analysis.savedPercent), analysis.jsonTokens, analysis.toonTokens, Math.max(0, analysis.savedTokensPercent), Math.floor(Date.now() / 1000));
52751
- log31.debug(`[TOON] Recorded ${analysis.savedTokens} tokens ($${costSaved.toFixed(6)}) saved for ${category}`);
52970
+ log32.debug(`[TOON] Recorded ${analysis.savedTokens} tokens ($${costSaved.toFixed(6)}) saved for ${category}`);
52752
52971
  } catch (error4) {
52753
- log31.warn(`[TOON] Failed to record savings:`, error4);
52972
+ log32.warn(`[TOON] Failed to record savings:`, error4);
52754
52973
  }
52755
52974
  });
52756
52975
  }
52757
- var log31, MODEL_PRICING;
52976
+ var log32, MODEL_PRICING;
52758
52977
  var init_usage2 = __esm(() => {
52759
52978
  init_sqlite();
52760
52979
  init_logger();
52761
- log31 = logger.child("usage");
52980
+ log32 = logger.child("usage");
52762
52981
  MODEL_PRICING = {
52763
52982
  "claude-opus-4-6": { inputPer1M: 5, outputPer1M: 25 },
52764
52983
  "claude-sonnet-4-6": { inputPer1M: 3, outputPer1M: 15 },
@@ -52840,7 +53059,7 @@ function stringify2(data, model) {
52840
53059
  const tokensSaved = Math.max(0, analysis.savedTokens);
52841
53060
  const savingsPercent = Math.max(0, analysis.savedTokensPercent);
52842
53061
  const costSaved = tokensSaved * TOON_AVERAGE_COST_PER_TOKEN;
52843
- log32.debug(`[TOON] Converted - saved ${tokensSaved} tokens ($${costSaved.toFixed(6)}) (${savingsPercent.toFixed(1)}%)`);
53062
+ log33.debug(`[TOON] Converted - saved ${tokensSaved} tokens ($${costSaved.toFixed(6)}) (${savingsPercent.toFixed(1)}%)`);
52844
53063
  return {
52845
53064
  content: toonContent,
52846
53065
  format: "toon",
@@ -52858,7 +53077,7 @@ function stringify2(data, model) {
52858
53077
  savedTokensPercent: analysis.savedTokensPercent
52859
53078
  };
52860
53079
  } catch (error4) {
52861
- log32.warn(`[TOON] Failed, falling back to JSON:`, error4);
53080
+ log33.warn(`[TOON] Failed, falling back to JSON:`, error4);
52862
53081
  return {
52863
53082
  content: jsonContent,
52864
53083
  format: "toon",
@@ -52909,12 +53128,12 @@ function formatContext(data, model) {
52909
53128
  }
52910
53129
  return result.content;
52911
53130
  }
52912
- var log32, TOON_AVERAGE_COST_PER_TOKEN = 0.000000375;
53131
+ var log33, TOON_AVERAGE_COST_PER_TOKEN = 0.000000375;
52913
53132
  var init_toon = __esm(() => {
52914
53133
  init_dist2();
52915
53134
  init_logger();
52916
53135
  init_usage2();
52917
- log32 = logger.child("toon");
53136
+ log33 = logger.child("toon");
52918
53137
  });
52919
53138
 
52920
53139
  // packages/core/src/agent/conversation-store.ts
@@ -52966,7 +53185,7 @@ function stripLeadingOrphanedTools(rows) {
52966
53185
  start++;
52967
53186
  }
52968
53187
  if (start > 0) {
52969
- log33.warn(`[conv-store] Stripped ${start} leading orphaned tool message(s) from window (tool_call_ids outside window)`);
53188
+ log34.warn(`[conv-store] Stripped ${start} leading orphaned tool message(s) from window (tool_call_ids outside window)`);
52970
53189
  }
52971
53190
  return start > 0 ? rows.slice(start) : rows;
52972
53191
  }
@@ -53014,12 +53233,12 @@ function getScratchpad(threadId) {
53014
53233
  const db = getDb();
53015
53234
  return db.query("SELECT key, value FROM scratchpad WHERE thread_id = ? ORDER BY updated_at DESC").all(threadId);
53016
53235
  }
53017
- var log33;
53236
+ var log34;
53018
53237
  var init_conversation_store = __esm(() => {
53019
53238
  init_sqlite();
53020
53239
  init_logger();
53021
53240
  init_toon();
53022
- log33 = logger.child("conv-store");
53241
+ log34 = logger.child("conv-store");
53023
53242
  });
53024
53243
 
53025
53244
  // packages/core/src/agent/curator.ts
@@ -53034,9 +53253,9 @@ async function runCurator() {
53034
53253
  const lastProcessed = db.query("SELECT COALESCE(MAX(source_reflection_id), 0) as mid FROM playbook").get()?.mid ?? 0;
53035
53254
  const reflections = db.query("SELECT * FROM reflections WHERE id > ? ORDER BY id ASC").all(lastProcessed);
53036
53255
  if (reflections.length === 0) {
53037
- log34.debug("[curator] No new reflections to process");
53256
+ log35.debug("[curator] No new reflections to process");
53038
53257
  } else {
53039
- log34.info(`[curator] Processing ${reflections.length} new reflections`);
53258
+ log35.info(`[curator] Processing ${reflections.length} new reflections`);
53040
53259
  for (const reflection of reflections) {
53041
53260
  processReflection(db, reflection);
53042
53261
  }
@@ -53067,11 +53286,11 @@ async function runCurator() {
53067
53286
  applicable_to: null,
53068
53287
  sourceReflectionId: null
53069
53288
  });
53070
- log34.info(`[curator] Archived inactive worker: ${worker.name} (${worker.id})`);
53289
+ log35.info(`[curator] Archived inactive worker: ${worker.name} (${worker.id})`);
53071
53290
  }
53072
- log34.info("[curator] Playbook updated");
53291
+ log35.info("[curator] Playbook updated");
53073
53292
  } catch (err) {
53074
- log34.warn("[curator] Error:", err);
53293
+ log35.warn("[curator] Error:", err);
53075
53294
  }
53076
53295
  }
53077
53296
  function processReflection(db, reflection) {
@@ -53108,10 +53327,10 @@ function addOrUpdateRule(db, opts) {
53108
53327
  `).run(opts.rule, opts.category, opts.applicable_to, opts.sourceReflectionId);
53109
53328
  }
53110
53329
  }
53111
- var log34, DAYS_BEFORE_ARCHIVE = 14, MAX_HARMFUL_BEFORE_PRUNE = 3;
53330
+ var log35, DAYS_BEFORE_ARCHIVE = 14, MAX_HARMFUL_BEFORE_PRUNE = 3;
53112
53331
  var init_curator = __esm(() => {
53113
53332
  init_logger();
53114
- log34 = logger.child("curator");
53333
+ log35 = logger.child("curator");
53115
53334
  });
53116
53335
 
53117
53336
  // packages/core/src/agent/reflector.ts
@@ -53123,21 +53342,21 @@ async function runReflector() {
53123
53342
  try {
53124
53343
  const { getDb: getDb2 } = await Promise.resolve().then(() => (init_sqlite(), exports_sqlite));
53125
53344
  const db = getDb2();
53126
- log35.info(`[reflector] Starting reflection cycle...`);
53127
- log35.debug(`[reflector] Querying last reflection ID...`);
53345
+ log36.info(`[reflector] Starting reflection cycle...`);
53346
+ log36.debug(`[reflector] Querying last reflection ID...`);
53128
53347
  const lastReflectionId = db.query("SELECT MAX(id) as mid FROM reflections").get()?.mid ?? 0;
53129
- log35.debug(`[reflector] Last reflection ID: ${lastReflectionId}`);
53130
- log35.debug(`[reflector] Querying last processed trace ID with json_each...`);
53348
+ log36.debug(`[reflector] Last reflection ID: ${lastReflectionId}`);
53349
+ log36.debug(`[reflector] Querying last processed trace ID with json_each...`);
53131
53350
  let lastProcessedTrace = 0;
53132
53351
  try {
53133
53352
  const result = db.query(`SELECT MAX(CAST(json_each.value AS INTEGER)) as max_id
53134
53353
  FROM reflections, json_each(reflections.trace_ids)
53135
53354
  WHERE reflections.id = (SELECT MAX(id) FROM reflections)`).get()?.max_id ?? 0;
53136
53355
  lastProcessedTrace = result;
53137
- log35.debug(`[reflector] Last processed trace ID: ${lastProcessedTrace}`);
53356
+ log36.debug(`[reflector] Last processed trace ID: ${lastProcessedTrace}`);
53138
53357
  } catch (jsonErr) {
53139
- log35.error(`[reflector] json_each query failed:`, jsonErr);
53140
- log35.error(`[reflector] Full error details:`, {
53358
+ log36.error(`[reflector] json_each query failed:`, jsonErr);
53359
+ log36.error(`[reflector] Full error details:`, {
53141
53360
  message: jsonErr.message,
53142
53361
  stack: jsonErr.stack,
53143
53362
  errno: jsonErr.errno,
@@ -53145,7 +53364,7 @@ async function runReflector() {
53145
53364
  });
53146
53365
  throw jsonErr;
53147
53366
  }
53148
- log35.debug(`[reflector] Fetching traces from DB, lastProcessedTrace=${lastProcessedTrace}, limit=${MAX_TRACES_TO_ANALYZE}`);
53367
+ log36.debug(`[reflector] Fetching traces from DB, lastProcessedTrace=${lastProcessedTrace}, limit=${MAX_TRACES_TO_ANALYZE}`);
53149
53368
  const traces = db.query(`
53150
53369
  SELECT id, agent_id, agent_name, tool_used, input_summary,
53151
53370
  output_summary, success, error_message, duration_ms, tokens_used, created_at
@@ -53154,15 +53373,15 @@ async function runReflector() {
53154
53373
  ORDER BY id ASC
53155
53374
  LIMIT ?
53156
53375
  `).all(lastProcessedTrace, MAX_TRACES_TO_ANALYZE);
53157
- log35.debug(`[reflector] Fetched ${traces.length} traces from DB`);
53376
+ log36.debug(`[reflector] Fetched ${traces.length} traces from DB`);
53158
53377
  if (traces.length < MIN_TRACES_TO_RUN) {
53159
- log35.debug(`[reflector] Not enough traces (${traces.length}/${MIN_TRACES_TO_RUN}), skipping`);
53378
+ log36.debug(`[reflector] Not enough traces (${traces.length}/${MIN_TRACES_TO_RUN}), skipping`);
53160
53379
  return;
53161
53380
  }
53162
- log35.info(`[reflector] Analyzing ${traces.length} traces...`);
53381
+ log36.info(`[reflector] Analyzing ${traces.length} traces...`);
53163
53382
  const insights = analyzeTracesLocally(traces);
53164
53383
  if (insights.length === 0) {
53165
- log35.debug("[reflector] No insights generated");
53384
+ log36.debug("[reflector] No insights generated");
53166
53385
  return;
53167
53386
  }
53168
53387
  const traceIds = JSON.stringify(traces.map((t) => t.id));
@@ -53172,12 +53391,12 @@ async function runReflector() {
53172
53391
  VALUES (?, ?, ?, ?, ?, ?)
53173
53392
  `).run(traceIds, insight.type, insight.description, insight.affectedTools ? JSON.stringify(insight.affectedTools) : null, insight.affectedAgents ? JSON.stringify(insight.affectedAgents) : null, insight.confidence);
53174
53393
  }
53175
- log35.info(`[reflector] Generated ${insights.length} insights`);
53394
+ log36.info(`[reflector] Generated ${insights.length} insights`);
53176
53395
  const { runCurator: runCurator2 } = await Promise.resolve().then(() => (init_curator(), exports_curator));
53177
53396
  await runCurator2();
53178
- log35.info(`[reflector] Reflection cycle completed successfully`);
53397
+ log36.info(`[reflector] Reflection cycle completed successfully`);
53179
53398
  } catch (err) {
53180
- log35.error(`[reflector] Error during reflection:`, {
53399
+ log36.error(`[reflector] Error during reflection:`, {
53181
53400
  message: err.message,
53182
53401
  stack: err.stack,
53183
53402
  errno: err.errno,
@@ -53257,10 +53476,10 @@ function analyzeTracesLocally(traces) {
53257
53476
  }
53258
53477
  return insights;
53259
53478
  }
53260
- var log35, MAX_TRACES_TO_ANALYZE = 30, MIN_TRACES_TO_RUN = 10;
53479
+ var log36, MAX_TRACES_TO_ANALYZE = 30, MIN_TRACES_TO_RUN = 10;
53261
53480
  var init_reflector = __esm(() => {
53262
53481
  init_logger();
53263
- log35 = logger.child("reflector");
53482
+ log36 = logger.child("reflector");
53264
53483
  });
53265
53484
 
53266
53485
  // packages/core/src/agent/tracer.ts
@@ -53277,7 +53496,7 @@ function saveTrace(trace) {
53277
53496
  `).run(trace.threadId, trace.agentId, trace.agentName, trace.toolUsed ?? null, trace.inputSummary.substring(0, 500), trace.outputSummary.substring(0, 500), trace.success ? 1 : 0, trace.errorMessage ?? null, trace.durationMs ?? null, trace.tokensUsed ?? null);
53278
53497
  checkReflectorTrigger().catch(() => {});
53279
53498
  } catch (err) {
53280
- log36.warn("[tracer] Failed to save trace:", err);
53499
+ log37.warn("[tracer] Failed to save trace:", err);
53281
53500
  }
53282
53501
  });
53283
53502
  }
@@ -53288,7 +53507,7 @@ async function checkReflectorTrigger() {
53288
53507
  _tracesSinceLastReflection = 0;
53289
53508
  const { runReflector: runReflector2 } = await Promise.resolve().then(() => (init_reflector(), exports_reflector));
53290
53509
  runReflector2().catch((err) => {
53291
- log36.warn("[tracer] Reflector run failed:", err);
53510
+ log37.warn("[tracer] Reflector run failed:", err);
53292
53511
  });
53293
53512
  }
53294
53513
  function recordLLMUsage(opts) {
@@ -53304,10 +53523,10 @@ function recordLLMUsage(opts) {
53304
53523
  } catch {}
53305
53524
  });
53306
53525
  }
53307
- var log36, REFLECTOR_TRACE_THRESHOLD = 20, _tracesSinceLastReflection = 0;
53526
+ var log37, REFLECTOR_TRACE_THRESHOLD = 20, _tracesSinceLastReflection = 0;
53308
53527
  var init_tracer = __esm(() => {
53309
53528
  init_logger();
53310
- log36 = logger.child("tracer");
53529
+ log37 = logger.child("tracer");
53311
53530
  });
53312
53531
 
53313
53532
  // packages/core/src/gateway/channel-notify.ts
@@ -53318,7 +53537,7 @@ __export(exports_channel_notify, {
53318
53537
  });
53319
53538
  function setChannelSendFn(fn) {
53320
53539
  _sendFn = fn;
53321
- log37.info("[channel-notify] Send function registered");
53540
+ log38.info("[channel-notify] Send function registered");
53322
53541
  }
53323
53542
  function resolveSessionId(userId, channel) {
53324
53543
  try {
@@ -53331,24 +53550,24 @@ function resolveSessionId(userId, channel) {
53331
53550
  }
53332
53551
  async function sendToUserChannel(channel, userId, message) {
53333
53552
  if (!_sendFn) {
53334
- log37.warn("[channel-notify] No send function registered \u2014 message dropped");
53553
+ log38.warn("[channel-notify] No send function registered \u2014 message dropped");
53335
53554
  return { ok: false, error: "Channel send not initialized" };
53336
53555
  }
53337
53556
  const sessionId = resolveSessionId(userId, channel);
53338
- log37.info(`[channel-notify] Sending to ${channel}/${sessionId}: ${message.substring(0, 80)}`);
53557
+ log38.info(`[channel-notify] Sending to ${channel}/${sessionId}: ${message.substring(0, 80)}`);
53339
53558
  try {
53340
53559
  await _sendFn(channel, sessionId, message);
53341
53560
  return { ok: true };
53342
53561
  } catch (err) {
53343
- log37.warn(`[channel-notify] Failed to send: ${err.message}`);
53562
+ log38.warn(`[channel-notify] Failed to send: ${err.message}`);
53344
53563
  return { ok: false, error: err.message };
53345
53564
  }
53346
53565
  }
53347
- var log37, _sendFn = null;
53566
+ var log38, _sendFn = null;
53348
53567
  var init_channel_notify = __esm(() => {
53349
53568
  init_logger();
53350
53569
  init_sqlite();
53351
- log37 = logger.child("channel-notify");
53570
+ log38 = logger.child("channel-notify");
53352
53571
  });
53353
53572
 
53354
53573
  // packages/core/src/agent/compaction.ts
@@ -53372,10 +53591,10 @@ async function maybeCompact(threadId, notify) {
53372
53591
  const totalMessages = getMessageCount(threadId);
53373
53592
  if (summary && summary.last_message_id > totalMessages - KEEP_LAST_N_MESSAGES)
53374
53593
  return;
53375
- log38.info(`[compaction] Compacting thread=${threadId} tokens=${totalTokens}`);
53594
+ log39.info(`[compaction] Compacting thread=${threadId} tokens=${totalTokens}`);
53376
53595
  await compactThread(threadId, notify);
53377
53596
  } catch (err) {
53378
- log38.warn("[compaction] Error during compaction check:", err);
53597
+ log39.warn("[compaction] Error during compaction check:", err);
53379
53598
  }
53380
53599
  }
53381
53600
  async function compactThread(threadId, notify) {
@@ -53387,7 +53606,7 @@ async function compactThread(threadId, notify) {
53387
53606
  cutIndex--;
53388
53607
  }
53389
53608
  if (cutIndex <= 0) {
53390
- log38.info(`[compaction] No clean user-turn boundary found \u2014 skipping`);
53609
+ log39.info(`[compaction] No clean user-turn boundary found \u2014 skipping`);
53391
53610
  return;
53392
53611
  }
53393
53612
  const toSummarize = allMessages.slice(0, cutIndex);
@@ -53428,7 +53647,7 @@ ${transcript}`
53428
53647
  if (!summary)
53429
53648
  return;
53430
53649
  saveSummary(threadId, summary, toSummarize.length, lastSummarizedId);
53431
- log38.info(`[compaction] Thread ${threadId} compacted: ${toSummarize.length} msgs \u2192 ${estimateTokens(summary)} tokens`);
53650
+ log39.info(`[compaction] Thread ${threadId} compacted: ${toSummarize.length} msgs \u2192 ${estimateTokens(summary)} tokens`);
53432
53651
  if (notify?.channel && notify?.userId) {
53433
53652
  try {
53434
53653
  const { sendToUserChannel: sendToUserChannel2 } = await Promise.resolve().then(() => (init_channel_notify(), exports_channel_notify));
@@ -53460,14 +53679,14 @@ function clearOldToolResults(messages, keepLastN = 6) {
53460
53679
  return msg;
53461
53680
  });
53462
53681
  }
53463
- var log38, COMPACT_TOKEN_THRESHOLD = 32000, KEEP_LAST_N_MESSAGES = 5, TOOL_RESULT_MAX_CHARS = 200, MAX_TRANSCRIPT_MSGS = 30, MAX_MSG_CHARS = 300;
53682
+ var log39, COMPACT_TOKEN_THRESHOLD = 32000, KEEP_LAST_N_MESSAGES = 5, TOOL_RESULT_MAX_CHARS = 200, MAX_TRANSCRIPT_MSGS = 30, MAX_MSG_CHARS = 300;
53464
53683
  var init_compaction = __esm(() => {
53465
53684
  init_logger();
53466
53685
  init_conversation_store();
53467
53686
  init_toon();
53468
53687
  init_llm_client();
53469
53688
  init_sqlite();
53470
- log38 = logger.child("compaction");
53689
+ log39 = logger.child("compaction");
53471
53690
  });
53472
53691
 
53473
53692
  // packages/core/src/canvas/emitter.ts
@@ -53513,11 +53732,11 @@ function mcpToolFullName(serverName, toolName) {
53513
53732
  const trimmed = full.length > 64 ? full.substring(0, 64) : full;
53514
53733
  return /^[a-zA-Z_]/.test(trimmed) ? trimmed : `_${trimmed}`.substring(0, 64);
53515
53734
  }
53516
- var log39, STOPWORDS;
53735
+ var log40, STOPWORDS;
53517
53736
  var init_tool_selector = __esm(() => {
53518
53737
  init_sqlite();
53519
53738
  init_logger();
53520
- log39 = logger.child("tool-selector");
53739
+ log40 = logger.child("tool-selector");
53521
53740
  STOPWORDS = new Set([
53522
53741
  "que",
53523
53742
  "con",
@@ -53587,14 +53806,14 @@ function isConversational(message) {
53587
53806
  return true;
53588
53807
  for (const pattern of CONVERSATIONAL_PATTERNS) {
53589
53808
  if (pattern.test(trimmed)) {
53590
- log40.debug(`[skill-selector] Message matched conversational pattern: ${pattern}`);
53809
+ log41.debug(`[skill-selector] Message matched conversational pattern: ${pattern}`);
53591
53810
  return true;
53592
53811
  }
53593
53812
  }
53594
53813
  const words = trimmed.toLowerCase().split(/\s+/);
53595
53814
  const meaningfulWords = words.filter((w2) => w2.length > 2 && !STOPWORDS2.has(w2));
53596
53815
  if (meaningfulWords.length === 0) {
53597
- log40.debug(`[skill-selector] All words are stopwords - conversational`);
53816
+ log41.debug(`[skill-selector] All words are stopwords - conversational`);
53598
53817
  return true;
53599
53818
  }
53600
53819
  return false;
@@ -53615,15 +53834,15 @@ function matchTriggers(message, triggersJson) {
53615
53834
  const lowerMessage = message.toLowerCase();
53616
53835
  return triggers.some((trigger) => lowerMessage.includes(trigger.toLowerCase()));
53617
53836
  } catch (err) {
53618
- log40.warn(`[skill-selector] Failed to parse triggers: ${err.message}`);
53837
+ log41.warn(`[skill-selector] Failed to parse triggers: ${err.message}`);
53619
53838
  return false;
53620
53839
  }
53621
53840
  }
53622
53841
  function selectSkills(userMessage) {
53623
53842
  const startTime = performance.now();
53624
- log40.debug(`[skill-selector] Processing user message: "${userMessage.substring(0, 100)}"`);
53843
+ log41.debug(`[skill-selector] Processing user message: "${userMessage.substring(0, 100)}"`);
53625
53844
  if (isConversational(userMessage)) {
53626
- log40.debug(`[skill-selector] Conversational message, returning empty array`);
53845
+ log41.debug(`[skill-selector] Conversational message, returning empty array`);
53627
53846
  return [];
53628
53847
  }
53629
53848
  const db = getDb();
@@ -53634,16 +53853,16 @@ function selectSkills(userMessage) {
53634
53853
  `).all();
53635
53854
  for (const skill of allSkills) {
53636
53855
  if (skill.triggers && matchTriggers(userMessage, skill.triggers)) {
53637
- log40.info(`[skill-selector] Trigger match found: ${skill.name}`);
53856
+ log41.info(`[skill-selector] Trigger match found: ${skill.name}`);
53638
53857
  return [skill];
53639
53858
  }
53640
53859
  }
53641
53860
  const ftsQuery = buildFTSQuery(userMessage);
53642
53861
  if (!ftsQuery) {
53643
- log40.debug(`[skill-selector] No valid FTS query terms, returning empty array`);
53862
+ log41.debug(`[skill-selector] No valid FTS query terms, returning empty array`);
53644
53863
  return [];
53645
53864
  }
53646
- log40.debug(`[skill-selector] FTS query: "${ftsQuery}"`);
53865
+ log41.debug(`[skill-selector] FTS query: "${ftsQuery}"`);
53647
53866
  const ftsResults = db.query(`
53648
53867
  SELECT id, bm25(skills_fts, 1.0, 4.0, 5.0, 1.0, 1.0, 5.0, 2.0) as bm25_score
53649
53868
  FROM skills_fts
@@ -53652,13 +53871,13 @@ function selectSkills(userMessage) {
53652
53871
  LIMIT 20
53653
53872
  `).all(ftsQuery);
53654
53873
  if (ftsResults.length === 0) {
53655
- log40.debug(`[skill-selector] No FTS matches, returning empty array`);
53874
+ log41.debug(`[skill-selector] No FTS matches, returning empty array`);
53656
53875
  return [];
53657
53876
  }
53658
- log40.info(`[skill-selector] Raw FTS scores: ${ftsResults.slice(0, 10).map((r) => `id=${r.id}, score=${r.bm25_score.toFixed(2)}`).join(", ")}`);
53877
+ log41.info(`[skill-selector] Raw FTS scores: ${ftsResults.slice(0, 10).map((r) => `id=${r.id}, score=${r.bm25_score.toFixed(2)}`).join(", ")}`);
53659
53878
  const relevantResults = ftsResults.filter((r) => r.bm25_score >= MIN_RELEVANCE_THRESHOLD);
53660
53879
  if (relevantResults.length === 0) {
53661
- log40.debug(`[skill-selector] All results below threshold ${MIN_RELEVANCE_THRESHOLD}, returning empty`);
53880
+ log41.debug(`[skill-selector] All results below threshold ${MIN_RELEVANCE_THRESHOLD}, returning empty`);
53662
53881
  return [];
53663
53882
  }
53664
53883
  const skillIds = relevantResults.map((r) => r.id);
@@ -53672,7 +53891,7 @@ function selectSkills(userMessage) {
53672
53891
  AND active = 1
53673
53892
  `).all(...skillIds);
53674
53893
  } catch (err) {
53675
- log40.warn(`[skill-selector] Failed to fetch skills from DB:`, err);
53894
+ log41.warn(`[skill-selector] Failed to fetch skills from DB:`, err);
53676
53895
  return [];
53677
53896
  }
53678
53897
  const skillMap = new Map(dbSkills.map((s2) => [s2.id, s2]));
@@ -53694,9 +53913,9 @@ function selectSkills(userMessage) {
53694
53913
  const result = topSkills.map((t) => skillMap.get(t.id)).filter(Boolean);
53695
53914
  const timing = performance.now() - startTime;
53696
53915
  if (result.length > 0) {
53697
- log40.info(`[skill-selector] Selected ${result.length} skills in ${timing.toFixed(2)}ms:`, result.map((s2) => ({ name: s2.name, category: s2.category })));
53916
+ log41.info(`[skill-selector] Selected ${result.length} skills in ${timing.toFixed(2)}ms:`, result.map((s2) => ({ name: s2.name, category: s2.category })));
53698
53917
  } else {
53699
- log40.debug(`[skill-selector] No skills selected, returning empty array in ${timing.toFixed(2)}ms`);
53918
+ log41.debug(`[skill-selector] No skills selected, returning empty array in ${timing.toFixed(2)}ms`);
53700
53919
  }
53701
53920
  return result;
53702
53921
  }
@@ -53710,18 +53929,18 @@ function getMinimalSkills() {
53710
53929
  WHERE name IN (${placeholders})
53711
53930
  AND active = 1
53712
53931
  `).all(...MINIMAL_SKILL_NAMES);
53713
- log40.info(`[skill-selector] Loaded ${skills.length} minimal skills: ${skills.map((s2) => s2.name).join(", ")}`);
53932
+ log41.info(`[skill-selector] Loaded ${skills.length} minimal skills: ${skills.map((s2) => s2.name).join(", ")}`);
53714
53933
  return skills;
53715
53934
  } catch (err) {
53716
- log40.error(`[skill-selector] Failed to load minimal skills:`, err);
53935
+ log41.error(`[skill-selector] Failed to load minimal skills:`, err);
53717
53936
  return [];
53718
53937
  }
53719
53938
  }
53720
- var log40, MINIMAL_SKILL_NAMES, MAX_SKILLS_PER_TURN = 4, MIN_RELEVANCE_THRESHOLD = -15, STOPWORDS2, CONVERSATIONAL_PATTERNS;
53939
+ var log41, MINIMAL_SKILL_NAMES, MAX_SKILLS_PER_TURN = 4, MIN_RELEVANCE_THRESHOLD = -15, STOPWORDS2, CONVERSATIONAL_PATTERNS;
53721
53940
  var init_skill_selector = __esm(() => {
53722
53941
  init_sqlite();
53723
53942
  init_logger();
53724
- log40 = logger.child("skill-selector");
53943
+ log41 = logger.child("skill-selector");
53725
53944
  MINIMAL_SKILL_NAMES = new Set([
53726
53945
  "busqueda_fts5",
53727
53946
  "memory_manager",
@@ -53807,11 +54026,11 @@ var init_skill_selector = __esm(() => {
53807
54026
  });
53808
54027
 
53809
54028
  // packages/core/src/agent/playbook-selector.ts
53810
- var log41;
54029
+ var log42;
53811
54030
  var init_playbook_selector = __esm(() => {
53812
54031
  init_sqlite();
53813
54032
  init_logger();
53814
- log41 = logger.child("playbook-selector");
54033
+ log42 = logger.child("playbook-selector");
53815
54034
  });
53816
54035
 
53817
54036
  // packages/skills/src/bundled-data.generated.ts
@@ -53822,6 +54041,544 @@ __export(exports_bundled_data_generated, {
53822
54041
  var BUNDLED_SKILLS_DATA;
53823
54042
  var init_bundled_data_generated = __esm(() => {
53824
54043
  BUNDLED_SKILLS_DATA = [
54044
+ {
54045
+ name: "cron_manager",
54046
+ description: `Complete management of cron jobs with cron expressions. Create, list, update, pause, resume, delete, trigger, and view history. Use for reminders, automated reports, periodic checks.`,
54047
+ category: "cron",
54048
+ version: "2.0.0",
54049
+ tools: ["cron.create", "cron.list", "cron.update", "cron.delete", "cron.pause", "cron.resume", "cron.trigger", "cron.history"],
54050
+ triggers: ["program\xE1 una tarea", "schedule task", "cre\xE1 un cron", "create cron", "edit\xE1 el cron", "edit cron", "elimin\xE1 el cron", "remove cron", "lista las tareas", "list cron jobs", "modific\xE1 el cron", "modify cron", "tarea recurrente", "recurring task", "todos los d\xEDas", "daily", "cada semana", "weekly"],
54051
+ body: `
54052
+ # Cron Manager Skill
54053
+
54054
+ ## Cu\xE1ndo se Activa
54055
+
54056
+ Para gestionar tareas programadas (cron jobs): crear, listar, actualizar, pausar, reanudar, eliminar, ejecutar y ver historial.
54057
+
54058
+ ## Herramientas Disponibles
54059
+
54060
+ | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54061
+ |------|----------|---------------|
54062
+ | \`cron.create\` | Crear cron job | Nueva tarea |
54063
+ | \`cron.list\` | Listar todos | Ver existentes |
54064
+ | \`cron.update\` | Actualizar existente | Cambiar horario/instrucci\xF3n |
54065
+ | \`cron.pause\` | Pausar temporalmente | Sin eliminar |
54066
+ | \`cron.resume\` | Reanudar pausado | Continuar ejecuci\xF3n |
54067
+ | \`cron.delete\` | Eliminar permanentemente | Cancelar para siempre |
54068
+ | \`cron.trigger\` | Ejecutar ahora | Forzar ejecuci\xF3n |
54069
+ | \`cron.history\` | Ver historial | Ver logs de ejecuciones |
54070
+
54071
+ ## Campos Principales
54072
+
54073
+ | Campo | Tipo | Descripci\xF3n |
54074
+ |-------|------|-------------|
54075
+ | \`name\` | string | Identificador corto (e.g., 'daily-report') |
54076
+ | \`task\` | string | **REQUERIDO** - Instrucciones para el agente al ejecutarse |
54077
+ | \`task_type\` | string | 'recurring' (repite) o 'one_shot' (una vez) |
54078
+ | \`cron_expression\` | string | Expresi\xF3n cron (solo para recurring) |
54079
+ | \`fire_at\` | string | Datetime ISO (solo para one_shot) |
54080
+ | \`channel\` | string | Canal de notificaci\xF3n |
54081
+ | \`start_at\` | string | Inicio de ventana opcional (Croner startAt) |
54082
+ | \`stop_at\` | string | Fin de ventana opcional (Croner stopAt) |
54083
+ | \`dom_and_dow\` | number | 0=OR (default), 1=AND (d\xEDa mes + d\xEDa semana) |
54084
+
54085
+ ## Cron Expression Format
54086
+
54087
+ \`\`\`
54088
+ * * * * *
54089
+ \u2502 \u2502 \u2502 \u2502 \u2502
54090
+ \u2502 \u2502 \u2502 \u2502 \u2514\u2500\u2500 D\xEDa semana (0-6, 0=Domingo)
54091
+ \u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500 Mes (1-12)
54092
+ \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500 D\xEDa del mes (1-31)
54093
+ \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Hora (0-23)
54094
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Minuto (0-59)
54095
+ \`\`\`
54096
+
54097
+ ## Ejemplos Comunes
54098
+
54099
+ | Expresi\xF3n | Significado |
54100
+ |-----------|-------------|
54101
+ | \`0 9 * * *\` | Diario 9:00 AM |
54102
+ | \`0 7 * * 1-5\` | Lun-Vie 7:00 AM |
54103
+ | \`0 */2 * * *\` | Cada 2 horas |
54104
+ | \`0 0 * * 0\` | Domingos medianoche |
54105
+ | \`0 0 1 * *\` | D\xEDa 1 de cada mes |
54106
+
54107
+ ## C\xF3mo Usar start_at / stop_at
54108
+
54109
+ - \`start_at\`: La tarea no ejecuta antes de esta fecha
54110
+ - \`stop_at\`: La tarea no ejecuta despu\xE9s de esta fecha
54111
+ - Formato ISO: \`'2026-04-01T00:00:00'\`
54112
+
54113
+ ## C\xF3mo Usar dom_and_dow
54114
+
54115
+ - \`0\` (default): Se ejecuta si es el d\xEDa del mes O el d\xEDa de semana
54116
+ - \`1\`: Se ejecuta solo si es EL MISMO d\xEDa del mes Y el d\xEDa de semana
54117
+
54118
+ Ejemplo: \`0 9 15 * *\` con dom_and_dow=1 significa "los 15 de cada mes QUE SEA domingo"
54119
+
54120
+ ## Workflow para Crear
54121
+
54122
+ 1. **Preguntar** \u2192 \xBFone_shot o recurring?
54123
+ 2. **Obtener** \u2192 Hora y canal de notificaci\xF3n
54124
+ 3. **Crear** \u2192 \`cron.create\` con campo \`task\` obligatorio
54125
+ 4. **Confirmar** \u2192 \`cron.list\` mostrar next runs
54126
+
54127
+ ## Errores a Evitar
54128
+
54129
+ - \u274C Olvidar el campo \`task\` \u2014 es obligatorio
54130
+ - \u274C Usar exec para tareas programadas
54131
+ - \u274C No preguntar si es one_shot o recurring
54132
+ - \u274C No mostrar pr\xF3ximos horarios al crear
54133
+ - \u274C Llamar \`cron.update\` sin \`task_id\` \u2014 siempre hacer \`cron.list\` primero`
54134
+ },
54135
+ {
54136
+ name: "browser_automate",
54137
+ description: `Automate web workflows with navigation, clicks, form filling, and visual verification`,
54138
+ category: "web",
54139
+ version: "1.0.0",
54140
+ tools: ["browser_navigate", "browser_click", "browser_type", "browser_screenshot"],
54141
+ triggers: ["automatiz\xE1 el navegador", "automate browser", "complet\xE1 el formulario", "fill form", "hac\xE9 clic en", "click on", "inici\xE1 sesi\xF3n", "login", "registrate", "sign up", "interactu\xE1 con la web", "interact with website", "flujo web", "web workflow"],
54142
+ body: `
54143
+ # Browser Automate Skill
54144
+
54145
+ ## Cu\xE1ndo se Activa
54146
+
54147
+ Esta skill se activa para automatizar flujos de interacci\xF3n con aplicaciones web: logins, formularios, navegaci\xF3n program\xE1tica.
54148
+
54149
+ ## Herramientas Disponibles
54150
+
54151
+ | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54152
+ |------|----------|---------------|
54153
+ | \`browser_navigate\` | Navega a URL | Inicio de flujo |
54154
+ | \`browser_click\` | Click en elementos | Botones, enlaces, triggers |
54155
+ | \`browser_type\` | Escribe en inputs | Formularios, b\xFAsquedas |
54156
+ | \`browser_screenshot\` | Captura estado | Verificaci\xF3n visual |
54157
+
54158
+ ## Workflow T\xEDpico
54159
+
54160
+ 1. **Navegar** \u2192 URL inicial
54161
+ 2. **Interactuar** \u2192 click/type seg\xFAn flujo
54162
+ 3. **Verificar** \u2192 screenshot despu\xE9s de acciones cr\xEDticas
54163
+ 4. **Repetir** \u2192 para flujos multi-paso
54164
+
54165
+ ## Mejores Pr\xE1cticas
54166
+
54167
+ - Selectores estables (IDs > classes > XPath)
54168
+ - Esperar carga despu\xE9s de navegaci\xF3n
54169
+ - Verificar estado visual con screenshots
54170
+ - Manejar errores de elementos no encontrados
54171
+
54172
+ ## Errores a Evitar
54173
+
54174
+ - \u274C Selectores fr\xE1giles que cambian
54175
+ - \u274C No esperar carga de p\xE1gina
54176
+ - \u274C Ignorar errores de elementos
54177
+ - \u274C No verificar estado despu\xE9s de acciones
54178
+ `
54179
+ },
54180
+ {
54181
+ name: "web_research",
54182
+ description: `Search and synthesize information from multiple web sources into structured reports`,
54183
+ category: "web",
54184
+ version: "1.0.0",
54185
+ tools: ["web_search", "web_fetch"],
54186
+ triggers: ["investig\xE1 sobre", "research", "busc\xE1 informaci\xF3n de", "find information about", "qu\xE9 es", "what is", "explicame", "explain", "\xFAltimos avances", "latest advances", "tendencias de", "trends in", "informaci\xF3n actualizada", "current information"],
54187
+ body: `
54188
+ # Web Research Skill
54189
+
54190
+ ## Cu\xE1ndo se Activa
54191
+
54192
+ Esta skill se activa cuando el usuario necesita informaci\xF3n actualizada de internet, verificar datos, o investigar temas espec\xEDficos.
54193
+
54194
+ ## Herramientas Disponibles
54195
+
54196
+ | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54197
+ |------|----------|---------------|
54198
+ | \`web_search\` | Busca en internet, devuelve t\xEDtulos, URLs, snippets | B\xFAsqueda inicial, encontrar fuentes |
54199
+ | \`web_fetch\` | Descarga contenido completo de URL (HTML\u2192Markdown) | Profundizar en resultados espec\xEDficos |
54200
+
54201
+ ## Workflow
54202
+
54203
+ 1. **B\xFAsqueda inicial** \u2192 \`web_search({ query, numResults: 8 })\`
54204
+ 2. **Fetch contenido** \u2192 \`web_fetch({ urls: top 2-3 })\`
54205
+ 3. **B\xFAsqueda complementaria** \u2192 Segundo search si hay gaps
54206
+ 4. **S\xEDntesis** \u2192 summary + key points + sources
54207
+
54208
+ ## Mejores Pr\xE1cticas
54209
+
54210
+ - Queries espec\xEDficos (m\xE1x 6 palabras)
54211
+ - M\xEDnimo 2-3 fuentes independientes
54212
+ - Priorizar contenido reciente (<1 a\xF1o)
54213
+ - Citas con URLs completas
54214
+
54215
+ ## Errores a Evitar
54216
+
54217
+ - \u274C Inventar datos no encontrados
54218
+ - \u274C Concluir con una sola b\xFAsqueda
54219
+ - \u274C No verificar fecha de fuentes
54220
+ - \u274C Copiar contenido literal (usar par\xE1frasis)
54221
+ `
54222
+ },
54223
+ {
54224
+ name: "web_monitor",
54225
+ description: `Monitor changes in web sources and track updates over time with persistent memory`,
54226
+ category: "web",
54227
+ version: "1.0.0",
54228
+ tools: ["web_search", "web_fetch", "memory_write", "memory_read"],
54229
+ triggers: ["monitore\xE1", "monitor", "segu\xED los cambios", "track changes", "avisame si cambia", "notify if changes", "actualizaci\xF3n de", "update on", "novedades de", "news about", "cambios en", "changes in"],
54230
+ body: `
54231
+ # Web Monitor Skill
54232
+
54233
+ ## Cu\xE1ndo se Activa
54234
+
54235
+ Esta skill se activa cuando el usuario necesita:
54236
+ - Monitorear cambios en una URL espec\xEDfica
54237
+ - Recibir notificaciones de actualizaciones
54238
+ - Seguir novedades sobre un tema
54239
+ - Trackear evoluci\xF3n de contenido
54240
+
54241
+ ## Herramientas Disponibles
54242
+
54243
+ | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54244
+ |------|----------|---------------|
54245
+ | \`web_fetch\` | Descarga contenido de URL | Obtener contenido actual |
54246
+ | \`web_search\` | Busca novedades | Monitoreo por tema (no URL fija) |
54247
+ | \`memory_write\` | Guarda baseline | Almacenar contenido para comparaci\xF3n |
54248
+ | \`memory_read\` | Recupera baseline anterior | Comparar con contenido actual |
54249
+
54250
+ ## Workflow
54251
+
54252
+ 1. **Primera ejecuci\xF3n**: \`web_fetch\` \u2192 \`memory_write\` (baseline)
54253
+ 2. **Chequeos siguientes**: \`memory_read\` \u2192 \`web_fetch\` \u2192 comparar \u2192 \`notify\` si cambia
54254
+ 3. **Actualizar baseline**: \`memory_write\` con nuevo contenido
54255
+
54256
+ ## Mejores Pr\xE1cticas
54257
+
54258
+ - Ignorar cambios menores (timestamps, ads, contenido din\xE1mico irrelevante)
54259
+ - Notificar solo cambios significativos
54260
+ - Para monitoreo peri\xF3dico, combinar con \`cron.create\`
54261
+
54262
+ ## Errores a Evitar
54263
+
54264
+ - \u274C No almacenar baseline inicial
54265
+ - \u274C Notificar por cambios triviales
54266
+ - \u274C No actualizar timestamp de baseline
54267
+ `
54268
+ },
54269
+ {
54270
+ name: "browser_scrape",
54271
+ description: `Navigate to web pages and capture rendered content including screenshots for dynamic sites`,
54272
+ category: "web",
54273
+ version: "1.0.0",
54274
+ tools: ["browser_navigate", "browser_screenshot", "web_fetch"],
54275
+ triggers: ["captur\xE1 el contenido", "scrape content", "obten\xE9 la p\xE1gina renderizada", "get rendered page", "sitios din\xE1micos", "dynamic sites", "web con javascript", "javascript websites", "tom\xE1 screenshot y contenido", "screenshot and content"],
54276
+ body: `
54277
+ # Browser Scrape Skill
54278
+
54279
+ ## Cu\xE1ndo se Activa
54280
+
54281
+ Esta skill se activa para sitios web din\xE1micos que requieren JavaScript rendering, donde el contenido no est\xE1 disponible en HTML est\xE1tico.
54282
+
54283
+ ## Herramientas Disponibles
54284
+
54285
+ | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54286
+ |------|----------|---------------|
54287
+ | \`browser_navigate\` | Navega y renderiza p\xE1gina completa | Sitios con JavaScript/SPA |
54288
+ | \`browser_screenshot\` | Captura estado visual | Evidencia de contenido renderizado |
54289
+ | \`web_fetch\` | Extrae texto como markdown | Contenido textual de p\xE1gina renderizada |
54290
+
54291
+ ## Workflow
54292
+
54293
+ 1. **Navegar** \u2192 \`browser_navigate({ url })\` + esperar renderizado JS
54294
+ 2. **Capturar visual** \u2192 \`browser_screenshot()\`
54295
+ 3. **Extraer texto** \u2192 \`web_fetch()\`
54296
+ 4. **Combinar** \u2192 screenshot + texto para scrape completo
54297
+
54298
+ ## Mejores Pr\xE1cticas
54299
+
54300
+ - Esperar renderizado completo de JavaScript
54301
+ - Para infinite scroll: hacer scroll y m\xFAltiples screenshots
54302
+ - Capturar antes y despu\xE9s de interacciones si es din\xE1mico
54303
+
54304
+ ## Errores a Evitar
54305
+
54306
+ - \u274C No esperar renderizado JavaScript
54307
+ - \u274C Solo capturar HTML est\xE1tico para sitios SPA
54308
+ - \u274C Ignorar t\xE9rminos de servicio del sitio
54309
+ `
54310
+ },
54311
+ {
54312
+ name: "busqueda_fts5",
54313
+ description: `Core discovery skill - find any capability with a single keyword`,
54314
+ category: "core",
54315
+ version: "1.2.0",
54316
+ tools: ["search_knowledge"],
54317
+ triggers: ["c\xF3mo busco herramientas", "c\xF3mo encuentro skills", "how to find tools", "search knowledge", "discovery", "buscar en la base", "encontrar herramientas"],
54318
+ body: `
54319
+ # busqueda_fts5 \u2014 Sistema de Discovery
54320
+
54321
+ Arranc\xE1s con solo 4 herramientas. Todo lo dem\xE1s se descubre con **search_knowledge**.
54322
+
54323
+ ## Regla de oro: UNA PALABRA, busca TODO
54324
+
54325
+ \`\`\`
54326
+ search_knowledge(query="email")
54327
+ \`\`\`
54328
+
54329
+ Eso solo \u2014 sin type, sin frases largas \u2014 devuelve tools, skills, MCP y playbook relacionados con "email".
54330
+
54331
+ **NO hagas esto:** \`search_knowledge(type="tools", query="enviar correo electr\xF3nico")\` \u2014 AND entre palabras no encuentra nada.
54332
+
54333
+ **S\xCD hagas esto:** \`search_knowledge(query="email")\` \u2014 encuentra todo lo relacionado.
54334
+
54335
+ ## Cu\xE1ndo especificar type
54336
+
54337
+ Solo si quer\xE9s filtrar resultados que ya son muchos:
54338
+
54339
+ \`\`\`
54340
+ search_knowledge(query="email", type="mcp") \u2192 solo herramientas externas de email
54341
+ search_knowledge(query="email", type="tools") \u2192 solo herramientas nativas de email
54342
+ \`\`\`
54343
+
54344
+ Por defecto type="all" \u2014 no hace falta especificarlo.
54345
+
54346
+ ## Regla de prioridad
54347
+
54348
+ **Prefer\xED herramientas nativas sobre MCP** cuando ambas sirven.
54349
+ - Nativas: m\xE1s r\xE1pidas, sin red, siempre disponibles
54350
+ - MCP: cuando no hay equivalente nativo
54351
+
54352
+ ## Flujo de uso
54353
+
54354
+ 1. Identific\xE1 la palabra clave de lo que necesit\xE1s
54355
+ 2. \`search_knowledge(query="<palabra>")\` \u2192 resultados de todos los tipos
54356
+ 3. Las tools encontradas se inyectan autom\xE1ticamente en tu contexto
54357
+ 4. Us\xE1s las tools en el siguiente paso
54358
+
54359
+ ---
54360
+
54361
+ ## Ejemplos
54362
+
54363
+ \`\`\`
54364
+ search_knowledge(query="pdf") \u2192 tools para leer/escribir PDFs
54365
+ search_knowledge(query="browser") \u2192 tools de navegaci\xF3n web
54366
+ search_knowledge(query="github") \u2192 tools MCP de GitHub si est\xE1n configuradas
54367
+ search_knowledge(query="calendar") \u2192 tools de Google Calendar
54368
+ search_knowledge(query="canvas") \u2192 skills de visualizaci\xF3n
54369
+ search_knowledge(query="slack") \u2192 tools de Slack si est\xE1n configuradas
54370
+ \`\`\`
54371
+ `
54372
+ },
54373
+ {
54374
+ name: "api_client",
54375
+ description: `Make HTTP requests to REST APIs using curl-like methods (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS)`,
54376
+ category: "api",
54377
+ version: "1.0.0",
54378
+ tools: ["api_request"],
54379
+ triggers: ["llama a la api", "llama al api", "consume la api", "haz una petici\xF3n", "haz un request", "env\xEDa un post", "env\xEDa un put", "env\xEDa un delete", "curl", "api request", "rest api", "endpoint", "webhook", "integrar con api", "conectar con api", "obtener datos de api", "enviar datos a api"],
54380
+ body: `
54381
+ # API Client Skill
54382
+
54383
+ ## Cu\xE1ndo se Activa
54384
+
54385
+ Esta skill se activa cuando el usuario necesita interactuar con una API REST: consultar datos, crear recursos, actualizar, eliminar, o cualquier operaci\xF3n HTTP.
54386
+
54387
+ ## Herramientas Disponibles
54388
+
54389
+ | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54390
+ |------|----------|---------------|
54391
+ | \`api_request\` | Realiza peticiones HTTP completas (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) con headers, body, query params y timeout | Siempre que necesites llamar un endpoint REST, webhook, o servicio externo |
54392
+
54393
+ ## Par\xE1metros de api_request
54394
+
54395
+ - \`method\` (requerido): GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
54396
+ - \`url\` (requerido): URL completa del endpoint
54397
+ - \`headers\` (opcional): objeto con headers HTTP. Ej: \`{ "Authorization": "Bearer TOKEN", "Content-Type": "application/json" }\`
54398
+ - \`body\` (opcional): cuerpo de la petici\xF3n como string. Para JSON, enviar JSON.stringify(objeto)
54399
+ - \`query_params\` (opcional): par\xE1metros de query que se codificar\xE1n autom\xE1ticamente en la URL
54400
+ - \`timeout_ms\` (opcional): timeout en ms. Default: 30000. M\xE1x: 120000
54401
+
54402
+ ## Diferencia con web_fetch
54403
+
54404
+ - \`web_fetch\`: solo GET, sin headers custom, ideal para scraping de p\xE1ginas web
54405
+ - \`api_request\`: cualquier m\xE9todo HTTP, headers custom, body, query params \u2014 ideal para APIs REST
54406
+
54407
+ ## Workflow
54408
+
54409
+ 1. **Identificar endpoint y m\xE9todo** \u2192 Determinar URL, m\xE9todo, headers necesarios
54410
+ 2. **Construir request** \u2192 \`api_request({ method, url, headers, body })\`
54411
+ 3. **Validar respuesta** \u2192 Si 2xx: extraer datos. Si error: analizar y sugerir fix
54412
+ 4. **Presentar resultados** \u2192 JSON parseado en formato legible, no crudo a menos que se pida
54413
+
54414
+ ## Mejores Pr\xE1cticas
54415
+
54416
+ - Siempre enviar \`Content-Type: application/json\` cuando el body es JSON
54417
+ - Usar \`query_params\` en lugar de append manual a la URL
54418
+ - No exponer tokens/secrets en la respuesta final al usuario
54419
+ - Si la API requiere auth, pedirla al usuario o usar variables de entorno
54420
+ - Para errores 4xx, revisar: auth, formato del body, campos requeridos, rate limits
54421
+
54422
+ ## Errores a Evitar
54423
+
54424
+ - \u274C Usar web_fetch para POST/PUT/DELETE con headers
54425
+ - \u274C Enviar objetos directamente en body (debe ser string)
54426
+ - \u274C Olvidar Content-Type al enviar JSON
54427
+ - \u274C Exponer API keys en la respuesta visible
54428
+ `
54429
+ },
54430
+ {
54431
+ name: "file_manager",
54432
+ description: `Explore project structure and locate files using glob patterns and directory listing`,
54433
+ category: "filesystem",
54434
+ version: "1.0.0",
54435
+ tools: ["fs_list", "fs_glob", "fs_exists"],
54436
+ triggers: ["lista los archivos", "list files", "busc\xE1 archivos", "find files", "explor\xE1 el proyecto", "explore project", "qu\xE9 archivos hay", "what files exist", "busc\xE1 por patr\xF3n", "search by pattern", "existe este archivo", "file exists", "d\xF3nde est\xE1", "where is"],
54437
+ body: `
54438
+ # File Manager Skill
54439
+
54440
+ ## Cu\xE1ndo se Activa
54441
+
54442
+ Esta skill se activa cuando el usuario necesita:
54443
+ - Explorar la estructura del proyecto
54444
+ - Buscar archivos por extensi\xF3n o patr\xF3n
54445
+ - Verificar si existe un archivo o directorio
54446
+ - Encontrar la ubicaci\xF3n de un archivo
54447
+
54448
+ ## Herramientas Disponibles
54449
+
54450
+ | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54451
+ |------|----------|---------------|
54452
+ | \`fs_list\` | Lista directorios y archivos | Exploraci\xF3n inicial |
54453
+ | \`fs_glob\` | Busca archivos por patr\xF3n wildcard | B\xFAsqueda por extensi\xF3n/patr\xF3n |
54454
+ | \`fs_exists\` | Verifica existencia | Pre-check antes de operaciones |
54455
+
54456
+ ## Workflow
54457
+
54458
+ 1. **Explorar** \u2192 \`fs_list({ path })\` para estructura general
54459
+ 2. **Buscar por patr\xF3n** \u2192 \`fs_glob({ pattern })\` para tipos espec\xEDficos
54460
+ 3. **Verificar** \u2192 \`fs_exists({ path })\` para confirmaci\xF3n
54461
+
54462
+ ## Patrones Glob Comunes
54463
+
54464
+ | Patr\xF3n | Encuentra |
54465
+ |--------|-----------|
54466
+ | \`**/*.ts\` | Todos los TypeScript |
54467
+ | \`**/*.test.ts\` | Solo tests |
54468
+ | \`**/*.md\` | Documentaci\xF3n |
54469
+ | \`**/package.json\` | Todos los package.json |
54470
+ | \`src/**/*.tsx\` | React components en src |
54471
+
54472
+ ## Errores a Evitar
54473
+
54474
+ - \u274C No verificar existencia antes de leer/editar
54475
+ - \u274C Usar fs_list cuando se conoce el patr\xF3n (usar glob)
54476
+ - \u274C Patrones muy amplios sin filtrado
54477
+ `
54478
+ },
54479
+ {
54480
+ name: "file_writer",
54481
+ description: `Create, modify, and delete files with safe edit operations and confirmation for large changes`,
54482
+ category: "filesystem",
54483
+ version: "1.0.0",
54484
+ tools: ["project_read", "project_write", "project_edit", "project_exists"],
54485
+ triggers: ["cre\xE1 un archivo", "create a file", "escrib\xED en", "write to", "edit\xE1 este archivo", "edit this file", "modific\xE1", "modify", "elimin\xE1 el archivo", "delete file", "guard\xE1 esto", "save this", "actualiz\xE1 el archivo", "update file"],
54486
+ body: `
54487
+ # File Writer Skill
54488
+
54489
+ ## Cu\xE1ndo se Activa
54490
+
54491
+ Esta skill se activa cuando el usuario necesita:
54492
+ - Crear nuevos archivos
54493
+ - Modificar contenido existente
54494
+ - Eliminar archivos
54495
+ - Guardar cambios
54496
+
54497
+ ## Herramientas Disponibles
54498
+
54499
+ | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54500
+ |------|----------|---------------|
54501
+ | \`project_read\` | Lee archivo existente | Antes de editar para entender estructura |
54502
+ | \`project_write\` | Crea o sobreescribe archivo | Archivos nuevos o reescritura completa |
54503
+ | \`project_edit\` | Edita secciones espec\xEDficas | Cambios puntuales (find/replace) |
54504
+ | \`project_exists\` | Verifica existencia | Para decidir crear vs editar |
54505
+
54506
+ ## Workflow
54507
+
54508
+ ### Crear Archivo Nuevo
54509
+ 1. \`project_exists({ path })\` \u2192 verificar no existe
54510
+ 2. \`project_write({ path, content })\` \u2192 crear
54511
+
54512
+ ### Editar Archivo Existente
54513
+ 1. \`project_exists({ path })\` \u2192 verificar existe
54514
+ 2. \`project_read({ path })\` \u2192 entender estructura
54515
+ 3. \`project_edit({ path, old_string, new_string })\` \u2192 modificar
54516
+ 4. \`canvas_confirm()\` si cambios >50 l\xEDneas
54517
+
54518
+ ### Eliminar Archivo
54519
+ 1. \`project_exists({ path })\` \u2192 verificar existe
54520
+ 2. \`canvas_confirm({ message: '\xBFEliminar archivo?' })\` \u2192 confirmar
54521
+ 3. Operaci\xF3n de delete
54522
+
54523
+ ## Mejores Pr\xE1cticas
54524
+
54525
+ - **Leer antes de editar**: Nunca modificar sin entender estructura
54526
+ - **Edit vs Write**: Usar edit para cambios peque\xF1os, write para nuevos archivos
54527
+ - **Confirmar cambios grandes**: >50 l\xEDneas requiere confirmaci\xF3n expl\xEDcita
54528
+ - **Paths seguros**: Trabajar dentro del workspace por defecto
54529
+
54530
+ ## Errores a Evitar
54531
+
54532
+ - \u274C Editar sin leer primero
54533
+ - \u274C Sobreescribir sin confirmar si es cambio grande
54534
+ - \u274C Eliminar sin confirmaci\xF3n expl\xEDcita
54535
+ - \u274C Usar write cuando edit es suficiente
54536
+ `
54537
+ },
54538
+ {
54539
+ name: "file_read_and_summarize",
54540
+ description: `Read and understand file content with automatic summarization for large files`,
54541
+ category: "filesystem",
54542
+ version: "1.0.0",
54543
+ tools: ["project_read"],
54544
+ triggers: ["le\xE9 este archivo", "read this file", "mostrame el contenido", "show content", "qu\xE9 dice este archivo", "resum\xED este archivo", "summarize this file", "entend\xE9 este c\xF3digo", "understand this code"],
54545
+ body: `
54546
+ # File Read and Summarize Skill
54547
+
54548
+ ## Cu\xE1ndo se Activa
54549
+
54550
+ Esta skill se activa cuando el usuario necesita leer y entender el contenido de un archivo, especialmente cuando:
54551
+ - El archivo es grande y necesita resumen
54552
+ - Se requiere comprensi\xF3n del contenido (no solo lectura)
54553
+ - El usuario pide "qu\xE9 dice", "resum\xED", "entend\xE9"
54554
+
54555
+ ## Herramientas Disponibles
54556
+
54557
+ | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54558
+ |------|----------|---------------|
54559
+ | \`project_read\` | Lee contenido de archivo del workspace | Lectura de cualquier archivo |
54560
+
54561
+ ## Workflow
54562
+
54563
+ 1. **Verificar existencia** \u2192 \`project_exists({ path })\`
54564
+ 2. **Leer contenido** \u2192 \`project_read({ path, offset, limit })\`
54565
+ 3. **Sintetizar** \u2192 Resumir si es grande, extraer puntos clave
54566
+
54567
+ ## Mejores Pr\xE1cticas
54568
+
54569
+ - Para archivos >1000 l\xEDneas, usar \`offset\` y \`limit\`
54570
+ - Identificar tipo de archivo por extensi\xF3n y adaptar formato de resumen
54571
+ - Para c\xF3digo: identificar funciones, clases, exports principales
54572
+ - Para config: explicar settings clave en lenguaje simple
54573
+ - Para texto: extraer ideas principales
54574
+
54575
+ ## Errores a Evitar
54576
+
54577
+ - \u274C Leer sin verificar existencia
54578
+ - \u274C Retornar archivo completo sin resumir si es muy grande
54579
+ - \u274C No identificar tipo de archivo para adaptar resumen
54580
+ `
54581
+ },
53825
54582
  {
53826
54583
  name: "office_document_manager",
53827
54584
  description: `Leer, crear y manipular archivos Office (PDF, Word, Excel, PowerPoint) desde el workspace`,
@@ -53921,6 +54678,225 @@ Esta skill se activa cuando el usuario necesita:
53921
54678
  - \u274C Pasar un array de arrays como \`datos\` de XLSX cuando se esperan objetos con claves
53922
54679
  - \u274C Intentar leer PDF de m\xE1s de 100 p\xE1ginas sin especificar rango (usar \`pagina_inicio\`/\`pagina_fin\`)
53923
54680
  `
54681
+ },
54682
+ {
54683
+ name: "cron_reminder",
54684
+ description: `Schedule a reminder for yourself at a specific time. Creates a one_shot cron job that sends a notification message via your preferred channel.`,
54685
+ category: "cron",
54686
+ version: "2.0.0",
54687
+ tools: ["cron.create", "notify"],
54688
+ triggers: ["recordame", "remind me", "recordatorio", "reminder", "alerta", "alert", "av\xEDsame", "notify me", "program\xE1", "schedule", "para ma\xF1ana", "for tomorrow", "en 30 minutos", "in 30 minutes"],
54689
+ body: `
54690
+ # Cron Reminder Skill
54691
+
54692
+ ## Cu\xE1ndo se Activa
54693
+
54694
+ Para crear recordatorios de una sola ejecuci\xF3n (one_shot): "recuerdame a las 3pm", "av\xEDsame en 30 minutos", etc.
54695
+
54696
+ ## Herramientas
54697
+
54698
+ | Tool | Qu\xE9 hace |
54699
+ |------|----------|
54700
+ | \`cron.create\` | Crear recordatorio one_shot |
54701
+ | \`notify\` | Enviar notificaci\xF3n directa |
54702
+
54703
+ ## C\xF3mo Funciona
54704
+
54705
+ 1. **Preguntar** \u2192 \xBFDe qu\xE9 te aviso? \xBFA qu\xE9 hora? \xBFPor qu\xE9 canal?
54706
+ 2. **Crear** \u2192 \`cron.create\` con \`task_type: 'one_shot'\` y \`fire_at\` en formato ISO
54707
+ 3. **Confirmar** \u2192 Mostrar hora programada
54708
+
54709
+ ## Par\xE1metros
54710
+
54711
+ | Campo | Descripci\xF3n |
54712
+ |-------|-------------|
54713
+ | \`task\` | **REQUERIDO** - Mensaje del recordatorio |
54714
+ | \`task_type\` | Siempre \`'one_shot'\` |
54715
+ | \`fire_at\` | Fecha/hora ISO (ej: \`'2026-04-20T15:00:00'\`) |
54716
+ | \`channel\` | Canal (telegram, discord, whatsapp, webchat) |
54717
+
54718
+ ## Errores Comunes
54719
+
54720
+ - \u274C Olvidar el campo \`task\` \u2014 obligatorio para que el agente sepa qu\xE9 enviar
54721
+ - \u274C Usar expresiones cron para recordatorios (usar \`fire_at\` en vez de \`cron_expression\`)
54722
+ - \u274C Poner \`fire_at\` en el pasado`
54723
+ },
54724
+ {
54725
+ name: "canvas_dashboard",
54726
+ description: `Real-time visual dashboard for monitoring task status, progress, and system state`,
54727
+ category: "canvas",
54728
+ version: "1.0.0",
54729
+ tools: ["canvas_render", "canvas_show_progress", "canvas_clear"],
54730
+ triggers: ["mostr\xE1 el dashboard", "show dashboard", "estado en tiempo real", "real-time status", "monitoreo visual", "visual monitoring", "panel de control", "control panel", "limpi\xE1 el canvas", "clear canvas", "actualiz\xE1 el dashboard", "update dashboard"],
54731
+ body: `
54732
+ # Canvas Dashboard Skill
54733
+
54734
+ ## Cu\xE1ndo se Activa
54735
+
54736
+ Para mostrar dashboards visuales de monitoreo en tiempo real de tareas, proyectos, o estado del sistema.
54737
+
54738
+ ## Herramientas Disponibles
54739
+
54740
+ | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54741
+ |------|----------|---------------|
54742
+ | \`canvas_render\` | Renderiza componentes | Layout del dashboard |
54743
+ | \`canvas_show_progress\` | Barras de progreso | Estado de tasks |
54744
+ | \`canvas_clear\` | Limpia canvas | Antes de nuevo dashboard |
54745
+
54746
+ ## Workflow
54747
+
54748
+ 1. **Clear** \u2192 \`canvas_clear()\` \u2014 limpiar previo
54749
+ 2. **Render layout** \u2192 \`canvas_render({ sections })\`
54750
+ 3. **Update progress** \u2192 \`canvas_show_progress()\` en tiempo real
54751
+ 4. **Refresh** \u2192 \`canvas_render({ updates })\` para cambios
54752
+
54753
+ ## Estructura de Dashboard
54754
+
54755
+ \`\`\`javascript
54756
+ canvas_render({
54757
+ component: {
54758
+ id: "dashboard-main",
54759
+ type: "markdown",
54760
+ props: { content: "## Dashboard\\n..." },
54761
+ span: "full" // \u2190 ancho completo del canvas
54762
+ }
54763
+ })
54764
+
54765
+ // O con tarjetas individuales:
54766
+ canvas_show_card({ title: "M\xE9tricas", span: "full", items: [...] })
54767
+ canvas_show_progress({ tasks: [...], span: "full" })
54768
+ \`\`\`
54769
+
54770
+ ## Color Coding
54771
+
54772
+ | Color | Estado |
54773
+ |-------|--------|
54774
+ | \uD83D\uDFE2 Verde | Complete |
54775
+ | \uD83D\uDD35 Azul | In Progress |
54776
+ | \uD83D\uDD34 Rojo | Error/Blocked |
54777
+ | \uD83D\uDFE1 Amarillo | Pending |
54778
+
54779
+ ## Mejores Pr\xE1cticas
54780
+
54781
+ - Clear antes de renderizar nuevo dashboard
54782
+ - Layout consistente (header, progress, status, metrics)
54783
+ - Update en tiempo real con progreso
54784
+ - Solo informaci\xF3n cr\xEDtica (no sobrecargar)
54785
+
54786
+ ## Errores a Evitar
54787
+
54788
+ - \u274C No clear entre dashboards (clutter)
54789
+ - \u274C Demasiada informaci\xF3n (sobrecarga visual)
54790
+ - \u274C No actualizar en tiempo real
54791
+ - \u274C Sin color coding para estados
54792
+ `
54793
+ },
54794
+ {
54795
+ name: "a2ui_interactive",
54796
+ description: `Create multi-step interactive workflows using A2UI v0.9 protocol with tabs, modals, choice pickers, and dynamic updates based on user actions`,
54797
+ category: "canvas",
54798
+ version: "1.0.0",
54799
+ tools: ["a2ui_create_surface", "a2ui_update_components", "a2ui_update_data_model", "a2ui_delete_surface"],
54800
+ triggers: ["interfaz interactiva A2UI", "A2UI interactive UI", "flujo A2UI", "A2UI workflow", "asistente A2UI", "A2UI assistant", "wizard A2UI", "flujo multi-paso A2UI", "multi-step flow A2UI", "workflow interactivo", "interactive workflow", "asistente paso a paso", "step-by-step assistant", "A2UI con tabs y modales"],
54801
+ body: `
54802
+ # A2UI Interactive Skill
54803
+
54804
+ ## Cu\xE1ndo se Activa
54805
+
54806
+ Para crear flujos interactivos multi-paso usando A2UI v0.9. Usar cuando se necesita:
54807
+ - Wizards paso a paso
54808
+ - Flujos de onboarding
54809
+ - Asistentes de reserva/configuraci\xF3n
54810
+ - Formularios con selections din\xE1micas
54811
+ - Interacciones con modales de confirmaci\xF3n
54812
+ - UIs que cambian seg\xFAn las acciones del usuario
54813
+
54814
+ ## Herramientes Disponibles
54815
+
54816
+ | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54817
+ |------|----------|---------------|
54818
+ | \`a2ui_create_surface\` | Crea la superficie A2UI | Siempre primero |
54819
+ | \`a2ui_update_components\` | Env\xEDa/actualiza componentes | Para layout y cambios de UI |
54820
+ | \`a2ui_update_data_model\` | Actualiza datos | Para estado del workflow |
54821
+ | \`a2ui_delete_surface\` | Elimina la superficie | Al terminar flujo |
54822
+
54823
+ ## Flujo Obligatorio
54824
+
54825
+ \`\`\`
54826
+ 1. a2ui_create_surface(surfaceId, catalogId, theme)
54827
+ 2. a2ui_update_components(surfaceId, components[])
54828
+ 3. a2ui_update_data_model(surfaceId, path, value) // estado inicial
54829
+ 4. [recibir acci\xF3n del usuario]
54830
+ 5. a2ui_update_data_model(...) // actualizar estado con respuesta
54831
+ 6. a2ui_update_components(...) // cambiar UI al siguiente paso
54832
+ 7. ... repetir 4-6 seg\xFAn necesidad ...
54833
+ 8. a2ui_delete_surface(surfaceId) // al terminar
54834
+ \`\`\`
54835
+
54836
+ ## Patrones de Flujo Interactivo
54837
+
54838
+ ### Wizard con Tabs (multi-paso)
54839
+
54840
+ \`\`\`json
54841
+ [
54842
+ {id: "root", component: "Column", children: ["step_indicator", "tabs"]},
54843
+ {id: "step_indicator", component: "Text", text: {path: "/stepLabel"}, variant: "caption"},
54844
+ {id: "tabs", component: "Tabs", tabs: [
54845
+ {title: "Servicio", child: "step1"},
54846
+ {title: "Fecha", child: "step2"},
54847
+ {title: "Confirmar", child: "step3"}
54848
+ ]},
54849
+ {id: "step1", component: "Column", children: ["svc_label", "svc_picker"]},
54850
+ {id: "svc_label", component: "Text", text: "Seleccion\xE1 un servicio", variant: "h3"},
54851
+ {id: "svc_picker", component: "ChoicePicker", variant: "mutuallyExclusive", options: [...], value: {path: "/data/service"}},
54852
+ // ... m\xE1s pasos
54853
+ ]
54854
+ \`\`\`
54855
+
54856
+ ### Confirmaci\xF3n con Modal
54857
+
54858
+ \`\`\`json
54859
+ [
54860
+ {id: "confirm_modal", component: "Modal", trigger: "confirm_btn", content: "confirm_dialog"},
54861
+ {id: "confirm_btn", component: "Button", child: "confirm_btn_text", action: {}},
54862
+ {id: "confirm_btn_text", component: "Text", text: "Confirmar Reserva"},
54863
+ {id: "confirm_dialog", component: "Column", children: ["confirm_msg", "confirm_yes", "confirm_no"]},
54864
+ {id: "confirm_msg", component: "Text", text: "\xBFConfirm\xE1s tu reserva?"},
54865
+ {id: "confirm_yes", component: "Button", child: "yes_text", variant: "primary", action: {event: {name: "confirm_booking", context: {service: {path: "/data/service"}}}}},
54866
+ {id: "yes_text", component: "Text", text: "S\xED, confirmar"},
54867
+ {id: "confirm_no", component: "Button", child: "no_text", variant: "borderless", action: {event: {name: "cancel"}}}},
54868
+ {id: "no_text", component: "Text", text: "Cancelar"}
54869
+ ]
54870
+ \`\`\`
54871
+
54872
+ ### Selecci\xF3n con ChoicePicker
54873
+
54874
+ \`\`\`json
54875
+ [
54876
+ {id: "service_picker", component: "ChoicePicker",
54877
+ variant: "mutuallyExclusive",
54878
+ options: [
54879
+ {label: "Consulta General", value: "general"},
54880
+ {label: "Especializada", value: "specialist"},
54881
+ {label: "Urgencia", value: "urgent"}
54882
+ ],
54883
+ value: {path: "/data/serviceType"},
54884
+ action: {event: {name: "service_selected", context: {service: {path: "/data/serviceType"}}}}
54885
+ }
54886
+ ]
54887
+ \`\`\`
54888
+
54889
+ ## Mejores Pr\xE1cticas
54890
+
54891
+ - Usar Tabs para wizards multi-paso
54892
+ - Usar Modal para confirmaciones antes de acciones cr\xEDticas
54893
+ - Usar ChoicePicker con \`variant: "mutuallyExclusive"\` para selecci\xF3n \xFAnica
54894
+ - Mostrar indicador de progreso (paso X de Y)
54895
+ - Actualizar data model despu\xE9s de cada acci\xF3n del usuario
54896
+ - Usar \`a2ui_update_components\` para cambiar la UI entre pasos
54897
+ - Agregar validaci\xF3n con \`checks\` en TextField
54898
+ - Mantener el estado del flujo en el data model (\`/data/step\`, \`/data/serviceType\`, etc.)
54899
+ - Eliminar surfaces con \`a2ui_delete_surface\` al completar o cancelar`
53924
54900
  },
53925
54901
  {
53926
54902
  name: "canvas_interact",
@@ -54003,73 +54979,81 @@ canvas_ask({
54003
54979
  `
54004
54980
  },
54005
54981
  {
54006
- name: "canvas_dashboard",
54007
- description: `Real-time visual dashboard for monitoring task status, progress, and system state`,
54982
+ name: "canvas_report",
54983
+ description: `Display structured results to users using cards, lists, and progress indicators`,
54008
54984
  category: "canvas",
54009
54985
  version: "1.0.0",
54010
- tools: ["canvas_render", "canvas_show_progress", "canvas_clear"],
54011
- triggers: ["mostr\xE1 el dashboard", "show dashboard", "estado en tiempo real", "real-time status", "monitoreo visual", "visual monitoring", "panel de control", "control panel", "limpi\xE1 el canvas", "clear canvas", "actualiz\xE1 el dashboard", "update dashboard"],
54986
+ tools: ["canvas_show_card", "canvas_show_list", "canvas_show_progress"],
54987
+ triggers: ["mostrame en el canvas", "show on canvas", "mostr\xE1 los resultados", "show results", "tarjeta informativa", "info card", "lista los resultados", "list results", "barra de progreso", "progress bar", "dashboard", "estado visual", "visual status"],
54012
54988
  body: `
54013
- # Canvas Dashboard Skill
54989
+ # Canvas Report Skill
54014
54990
 
54015
54991
  ## Cu\xE1ndo se Activa
54016
54992
 
54017
- Para mostrar dashboards visuales de monitoreo en tiempo real de tareas, proyectos, o estado del sistema.
54993
+ Para mostrar resultados estructurados visualmente en el canvas del usuario.
54018
54994
 
54019
54995
  ## Herramientas Disponibles
54020
54996
 
54021
54997
  | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54022
54998
  |------|----------|---------------|
54023
- | \`canvas_render\` | Renderiza componentes | Layout del dashboard |
54024
- | \`canvas_show_progress\` | Barras de progreso | Estado de tasks |
54025
- | \`canvas_clear\` | Limpia canvas | Antes de nuevo dashboard |
54999
+ | \`canvas_show_card\` | Muestra informaci\xF3n estructurada | Resultados con items etiquetados |
55000
+ | \`canvas_show_list\` | Lista clave-valor | Configuraciones, datos simples |
55001
+ | \`canvas_show_progress\` | Barras de progreso | Estado de tasks m\xFAltiples |
54026
55002
 
54027
55003
  ## Workflow
54028
55004
 
54029
- 1. **Clear** \u2192 \`canvas_clear()\` \u2014 limpiar previo
54030
- 2. **Render layout** \u2192 \`canvas_render({ sections })\`
54031
- 3. **Update progress** \u2192 \`canvas_show_progress()\` en tiempo real
54032
- 4. **Refresh** \u2192 \`canvas_render({ updates })\` para cambios
55005
+ 1. **Determinar formato** \u2192 Card vs List vs Progress
55006
+ 2. **Renderizar** \u2192 \`canvas_show_*\` apropiado
55007
+ 3. **Clear** \u2192 Si cambio de contexto significativo
54033
55008
 
54034
- ## Estructura de Dashboard
55009
+ ## Formatos
54035
55010
 
55011
+ ### Card
54036
55012
  \`\`\`javascript
54037
- canvas_render({
54038
- component: {
54039
- id: "dashboard-main",
54040
- type: "markdown",
54041
- props: { content: "## Dashboard\\n..." },
54042
- span: "full" // \u2190 ancho completo del canvas
54043
- }
55013
+ canvas_show_card({
55014
+ title: "Research Results",
55015
+ items: [
55016
+ { label: "Trends Found", value: "7" },
55017
+ { label: "Sources", value: "5 URLs" },
55018
+ { label: "Time", value: "2.5 min" }
55019
+ ]
54044
55020
  })
54045
55021
 
54046
- // O con tarjetas individuales:
54047
- canvas_show_card({ title: "M\xE9tricas", span: "full", items: [...] })
54048
- canvas_show_progress({ tasks: [...], span: "full" })
55022
+ // Full-width card (ocupa todo el ancho del canvas):
55023
+ canvas_show_card({
55024
+ title: "Full Report",
55025
+ span: "full",
55026
+ items: [...]
55027
+ })
54049
55028
  \`\`\`
54050
55029
 
54051
- ## Color Coding
54052
-
54053
- | Color | Estado |
54054
- |-------|--------|
54055
- | \uD83D\uDFE2 Verde | Complete |
54056
- | \uD83D\uDD35 Azul | In Progress |
54057
- | \uD83D\uDD34 Rojo | Error/Blocked |
54058
- | \uD83D\uDFE1 Amarillo | Pending |
54059
-
54060
- ## Mejores Pr\xE1cticas
55030
+ ### List
55031
+ \`\`\`javascript
55032
+ canvas_show_list({
55033
+ items: {
55034
+ "Language": "Spanish",
55035
+ "Timezone": "UTC-3",
55036
+ "Channel": "Telegram"
55037
+ }
55038
+ })
55039
+ \`\`\`
54061
55040
 
54062
- - Clear antes de renderizar nuevo dashboard
54063
- - Layout consistente (header, progress, status, metrics)
54064
- - Update en tiempo real con progreso
54065
- - Solo informaci\xF3n cr\xEDtica (no sobrecargar)
55041
+ ### Progress
55042
+ \`\`\`javascript
55043
+ canvas_show_progress({
55044
+ bars: [
55045
+ { label: "Research", value: 100 },
55046
+ { label: "Content", value: 60 },
55047
+ { label: "Email", value: 0 }
55048
+ ]
55049
+ })
55050
+ \`\`\`
54066
55051
 
54067
55052
  ## Errores a Evitar
54068
55053
 
54069
- - \u274C No clear entre dashboards (clutter)
54070
- - \u274C Demasiada informaci\xF3n (sobrecarga visual)
54071
- - \u274C No actualizar en tiempo real
54072
- - \u274C Sin color coding para estados
55054
+ - \u274C Cards con demasiados items (>7)
55055
+ - \u274C Labels vagos sin contexto
55056
+ - \u274C No clear entre contextos diferentes
54073
55057
  `
54074
55058
  },
54075
55059
  {
@@ -54270,314 +55254,244 @@ a2ui_update_data_model(surfaceId: "dash", path: "/", value: {metrics: {completio
54270
55254
  - Eliminar surfaces al terminar para evitar memory leaks`
54271
55255
  },
54272
55256
  {
54273
- name: "a2ui_interactive",
54274
- description: `Create multi-step interactive workflows using A2UI v0.9 protocol with tabs, modals, choice pickers, and dynamic updates based on user actions`,
54275
- category: "canvas",
55257
+ name: "voice_input",
55258
+ description: `Transcribe audio input to text using STT (Speech-to-Text) providers like Groq Whisper or OpenAI Whisper`,
55259
+ category: "voice",
54276
55260
  version: "1.0.0",
54277
- tools: ["a2ui_create_surface", "a2ui_update_components", "a2ui_update_data_model", "a2ui_delete_surface"],
54278
- triggers: ["interfaz interactiva A2UI", "A2UI interactive UI", "flujo A2UI", "A2UI workflow", "asistente A2UI", "A2UI assistant", "wizard A2UI", "flujo multi-paso A2UI", "multi-step flow A2UI", "workflow interactivo", "interactive workflow", "asistente paso a paso", "step-by-step assistant", "A2UI con tabs y modales"],
55261
+ tools: ["voice_transcribe"],
55262
+ triggers: ["transcrib\xED este audio", "transcribe audio", "convert\xED voz a texto", "convert voice to text", "qu\xE9 dice el audio", "what does audio say", "escuch\xE1 esto", "listen to this", "audio a texto", "audio to text", "reconocimiento de voz", "speech recognition", "nota de voz", "voice note"],
54279
55263
  body: `
54280
- # A2UI Interactive Skill
55264
+ # Voice Input Skill
54281
55265
 
54282
55266
  ## Cu\xE1ndo se Activa
54283
55267
 
54284
- Para crear flujos interactivos multi-paso usando A2UI v0.9. Usar cuando se necesita:
54285
- - Wizards paso a paso
54286
- - Flujos de onboarding
54287
- - Asistentes de reserva/configuraci\xF3n
54288
- - Formularios con selections din\xE1micas
54289
- - Interacciones con modales de confirmaci\xF3n
54290
- - UIs que cambian seg\xFAn las acciones del usuario
55268
+ Esta skill se activa cuando el usuario env\xEDa audio y necesita transcripci\xF3n a texto: notas de voz, grabaciones, comandos de voz.
54291
55269
 
54292
- ## Herramientes Disponibles
55270
+ ## Herramientas Disponibles
54293
55271
 
54294
55272
  | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54295
55273
  |------|----------|---------------|
54296
- | \`a2ui_create_surface\` | Crea la superficie A2UI | Siempre primero |
54297
- | \`a2ui_update_components\` | Env\xEDa/actualiza componentes | Para layout y cambios de UI |
54298
- | \`a2ui_update_data_model\` | Actualiza datos | Para estado del workflow |
54299
- | \`a2ui_delete_surface\` | Elimina la superficie | Al terminar flujo |
55274
+ | \`voice_transcribe\` | Convierte audio \u2192 texto | Transcripci\xF3n de cualquier audio |
54300
55275
 
54301
- ## Flujo Obligatorio
55276
+ ## Workflow
54302
55277
 
54303
- \`\`\`
54304
- 1. a2ui_create_surface(surfaceId, catalogId, theme)
54305
- 2. a2ui_update_components(surfaceId, components[])
54306
- 3. a2ui_update_data_model(surfaceId, path, value) // estado inicial
54307
- 4. [recibir acci\xF3n del usuario]
54308
- 5. a2ui_update_data_model(...) // actualizar estado con respuesta
54309
- 6. a2ui_update_components(...) // cambiar UI al siguiente paso
54310
- 7. ... repetir 4-6 seg\xFAn necesidad ...
54311
- 8. a2ui_delete_surface(surfaceId) // al terminar
54312
- \`\`\`
55278
+ ### Transcripci\xF3n
55279
+ \`\`\`javascript
55280
+ // 1. Recibir audio
55281
+ // - File upload
55282
+ // - Voice message (Telegram, WhatsApp)
55283
+ // - Stream en vivo
54313
55284
 
54314
- ## Patrones de Flujo Interactivo
55285
+ // 2. Transcribir
55286
+ const result = voice_transcribe({
55287
+ audio: audioBuffer,
55288
+ language: "es" // o "auto" para detectar
55289
+ })
54315
55290
 
54316
- ### Wizard con Tabs (multi-paso)
55291
+ // 3. Formatear
55292
+ // - Agregar puntuaci\xF3n
55293
+ // - Capitalizar
55294
+ // - Marcar speakers si hay m\xFAltiples
54317
55295
 
54318
- \`\`\`json
54319
- [
54320
- {id: "root", component: "Column", children: ["step_indicator", "tabs"]},
54321
- {id: "step_indicator", component: "Text", text: {path: "/stepLabel"}, variant: "caption"},
54322
- {id: "tabs", component: "Tabs", tabs: [
54323
- {title: "Servicio", child: "step1"},
54324
- {title: "Fecha", child: "step2"},
54325
- {title: "Confirmar", child: "step3"}
54326
- ]},
54327
- {id: "step1", component: "Column", children: ["svc_label", "svc_picker"]},
54328
- {id: "svc_label", component: "Text", text: "Seleccion\xE1 un servicio", variant: "h3"},
54329
- {id: "svc_picker", component: "ChoicePicker", variant: "mutuallyExclusive", options: [...], value: {path: "/data/service"}},
54330
- // ... m\xE1s pasos
54331
- ]
55296
+ // 4. Entregar resultado
54332
55297
  \`\`\`
54333
55298
 
54334
- ### Confirmaci\xF3n con Modal
55299
+ ## Proveedores STT Soportados
54335
55300
 
54336
- \`\`\`json
54337
- [
54338
- {id: "confirm_modal", component: "Modal", trigger: "confirm_btn", content: "confirm_dialog"},
54339
- {id: "confirm_btn", component: "Button", child: "confirm_btn_text", action: {}},
54340
- {id: "confirm_btn_text", component: "Text", text: "Confirmar Reserva"},
54341
- {id: "confirm_dialog", component: "Column", children: ["confirm_msg", "confirm_yes", "confirm_no"]},
54342
- {id: "confirm_msg", component: "Text", text: "\xBFConfirm\xE1s tu reserva?"},
54343
- {id: "confirm_yes", component: "Button", child: "yes_text", variant: "primary", action: {event: {name: "confirm_booking", context: {service: {path: "/data/service"}}}}},
54344
- {id: "yes_text", component: "Text", text: "S\xED, confirmar"},
54345
- {id: "confirm_no", component: "Button", child: "no_text", variant: "borderless", action: {event: {name: "cancel"}}}},
54346
- {id: "no_text", component: "Text", text: "Cancelar"}
54347
- ]
54348
- \`\`\`
55301
+ | Provider | Modelos | Idiomas |
55302
+ |----------|---------|---------|
55303
+ | Groq | whisper-large-v3, turbo | Multi |
55304
+ | OpenAI | whisper-1 | Multi |
54349
55305
 
54350
- ### Selecci\xF3n con ChoicePicker
55306
+ ## Configuraci\xF3n por Canal
54351
55307
 
54352
- \`\`\`json
54353
- [
54354
- {id: "service_picker", component: "ChoicePicker",
54355
- variant: "mutuallyExclusive",
54356
- options: [
54357
- {label: "Consulta General", value: "general"},
54358
- {label: "Especializada", value: "specialist"},
54359
- {label: "Urgencia", value: "urgent"}
54360
- ],
54361
- value: {path: "/data/serviceType"},
54362
- action: {event: {name: "service_selected", context: {service: {path: "/data/serviceType"}}}}
54363
- }
54364
- ]
54365
- \`\`\`
55308
+ Cada canal puede configurar su proveedor STT preferido:
55309
+ - \`stt_provider\`: "groq-whisper" | "openai-whisper"
54366
55310
 
54367
55311
  ## Mejores Pr\xE1cticas
54368
55312
 
54369
- - Usar Tabs para wizards multi-paso
54370
- - Usar Modal para confirmaciones antes de acciones cr\xEDticas
54371
- - Usar ChoicePicker con \`variant: "mutuallyExclusive"\` para selecci\xF3n \xFAnica
54372
- - Mostrar indicador de progreso (paso X de Y)
54373
- - Actualizar data model despu\xE9s de cada acci\xF3n del usuario
54374
- - Usar \`a2ui_update_components\` para cambiar la UI entre pasos
54375
- - Agregar validaci\xF3n con \`checks\` en TextField
54376
- - Mantener el estado del flujo en el data model (\`/data/step\`, \`/data/serviceType\`, etc.)
54377
- - Eliminar surfaces con \`a2ui_delete_surface\` al completar o cancelar`
55313
+ - Detectar idioma autom\xE1ticamente
55314
+ - Agregar puntuaci\xF3n para legibilidad
55315
+ - Marcar segmentos inaudibles
55316
+ - Preservar idioma original
55317
+
55318
+ ## Errores a Evitar
55319
+
55320
+ - \u274C Traducir sin pedir (mantener idioma)
55321
+ - \u274C Omitir puntuaci\xF3n
55322
+ - \u274C No indicar baja confianza
55323
+ - \u274C Ignorar ruido de fondo que afecta calidad
55324
+ `
54378
55325
  },
54379
55326
  {
54380
- name: "canvas_report",
54381
- description: `Display structured results to users using cards, lists, and progress indicators`,
54382
- category: "canvas",
55327
+ name: "voice_assistant",
55328
+ description: `Full voice-to-voice interaction: transcribe user speech, process request, and respond with synthesized speech`,
55329
+ category: "voice",
54383
55330
  version: "1.0.0",
54384
- tools: ["canvas_show_card", "canvas_show_list", "canvas_show_progress"],
54385
- triggers: ["mostrame en el canvas", "show on canvas", "mostr\xE1 los resultados", "show results", "tarjeta informativa", "info card", "lista los resultados", "list results", "barra de progreso", "progress bar", "dashboard", "estado visual", "visual status"],
55331
+ tools: ["voice_transcribe", "voice_speak"],
55332
+ triggers: ["modo voz", "voice mode", "asistente de voz", "voice assistant", "habl\xE1 conmigo", "talk to me", "interacci\xF3n por voz", "voice interaction", "respuesta hablada", "spoken response", "comando de voz", "voice command", "di\xE1logo por voz", "voice dialogue"],
54386
55333
  body: `
54387
- # Canvas Report Skill
55334
+ # Voice Assistant Skill
54388
55335
 
54389
55336
  ## Cu\xE1ndo se Activa
54390
55337
 
54391
- Para mostrar resultados estructurados visualmente en el canvas del usuario.
55338
+ Esta skill se activa para interacci\xF3n completa voz a voz: el usuario habla, el asistente procesa y responde con voz.
54392
55339
 
54393
55340
  ## Herramientas Disponibles
54394
55341
 
54395
55342
  | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54396
55343
  |------|----------|---------------|
54397
- | \`canvas_show_card\` | Muestra informaci\xF3n estructurada | Resultados con items etiquetados |
54398
- | \`canvas_show_list\` | Lista clave-valor | Configuraciones, datos simples |
54399
- | \`canvas_show_progress\` | Barras de progreso | Estado de tasks m\xFAltiples |
55344
+ | \`voice_transcribe\` | Audio \u2192 texto | Input del usuario |
55345
+ | \`voice_speak\` | Texto \u2192 audio | Respuesta del asistente |
54400
55346
 
54401
55347
  ## Workflow
54402
55348
 
54403
- 1. **Determinar formato** \u2192 Card vs List vs Progress
54404
- 2. **Renderizar** \u2192 \`canvas_show_*\` apropiado
54405
- 3. **Clear** \u2192 Si cambio de contexto significativo
54406
-
54407
- ## Formatos
54408
-
54409
- ### Card
55349
+ ### Voice-to-Voice
54410
55350
  \`\`\`javascript
54411
- canvas_show_card({
54412
- title: "Research Results",
54413
- items: [
54414
- { label: "Trends Found", value: "7" },
54415
- { label: "Sources", value: "5 URLs" },
54416
- { label: "Time", value: "2.5 min" }
54417
- ]
54418
- })
55351
+ // 1. Usuario habla
55352
+ const userAudio = receiveAudio()
54419
55353
 
54420
- // Full-width card (ocupa todo el ancho del canvas):
54421
- canvas_show_card({
54422
- title: "Full Report",
54423
- span: "full",
54424
- items: [...]
55354
+ // 2. Transcribir
55355
+ const userText = voice_transcribe({
55356
+ audio: userAudio,
55357
+ language: "auto"
54425
55358
  })
54426
- \`\`\`
55359
+ // \u2192 "\xBFCu\xE1l es el clima hoy?"
54427
55360
 
54428
- ### List
54429
- \`\`\`javascript
54430
- canvas_show_list({
54431
- items: {
54432
- "Language": "Spanish",
54433
- "Timezone": "UTC-3",
54434
- "Channel": "Telegram"
54435
- }
54436
- })
54437
- \`\`\`
55361
+ // 3. Procesar request
55362
+ // - Entender intenci\xF3n
55363
+ // - Ejecutar acci\xF3n (ej. consultar API clima)
55364
+ // - Generar respuesta
55365
+ const responseText = "Hoy hay 25 grados y soleado en Buenos Aires"
54438
55366
 
54439
- ### Progress
54440
- \`\`\`javascript
54441
- canvas_show_progress({
54442
- bars: [
54443
- { label: "Research", value: 100 },
54444
- { label: "Content", value: 60 },
54445
- { label: "Email", value: 0 }
54446
- ]
55367
+ // 4. Sintetizar respuesta
55368
+ const responseAudio = voice_speak({
55369
+ text: responseText,
55370
+ voice_id: "eleven_flash_v2_5",
55371
+ language: "es"
54447
55372
  })
54448
- \`\`\`
54449
-
54450
- ## Errores a Evitar
54451
55373
 
54452
- - \u274C Cards con demasiados items (>7)
54453
- - \u274C Labels vagos sin contexto
54454
- - \u274C No clear entre contextos diferentes
54455
- `
54456
- },
54457
- {
54458
- name: "meeting_transcription",
54459
- description: `Transcribir reuniones en tiempo real y generar informes gerenciales con decisiones, action items y pr\xF3ximos pasos`,
54460
- category: "meeting",
54461
- version: "1.0.0",
54462
- tools: ["meeting_start", "meeting_add_segment", "meeting_stop", "meeting_report", "office_escribir_docx", "notify", "report_progress"],
54463
- triggers: ["transcribir reuni\xF3n", "iniciar transcripci\xF3n", "meeting transcription", "grabar reuni\xF3n", "iniciar reuni\xF3n", "start meeting", "detener reuni\xF3n", "stop meeting", "reporte de reuni\xF3n", "generar reporte reuni\xF3n", "informe de reuni\xF3n", "acta de reuni\xF3n", "transcripci\xF3n de reuni\xF3n", "meeting report"],
54464
- body: `
54465
- # Meeting Transcription Skill
54466
-
54467
- ## Cu\xE1ndo se Activa
54468
-
54469
- Esta skill se activa para gesti\xF3n completa del ciclo de vida de una reuni\xF3n: inicio, transcripci\xF3n en tiempo real, detenci\xF3n y generaci\xF3n de informe gerencial.
55374
+ // 5. Enviar audio
55375
+ sendAudio(responseAudio)
55376
+ \`\`\`
54470
55377
 
54471
- ## Herramientas Disponibles
55378
+ ## Casos de Uso
54472
55379
 
54473
- | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54474
- |------|----------|---------------|
54475
- | \`meeting_start\` | Crea una sesi\xF3n en DB \u2192 devuelve session_id | Al iniciar la reuni\xF3n |
54476
- | \`meeting_add_segment\` | Transcribe un chunk de audio y lo persiste | Por cada audio recibido |
54477
- | \`meeting_stop\` | Marca la sesi\xF3n como detenida | Cuando termina la reuni\xF3n |
54478
- | \`meeting_report\` | Lee todos los segmentos y arma el transcript | Para generar el reporte |
54479
- | \`office_escribir_docx\` | Guarda el reporte como archivo Word | Al finalizar el an\xE1lisis |
54480
- | \`notify\` | Env\xEDa mensajes en tiempo real al canal | Para mostrar transcripciones y el reporte |
54481
- | \`report_progress\` | Muestra progreso en barra | Durante transcripci\xF3n larga |
55380
+ | Caso | Flujo |
55381
+ |------|-------|
55382
+ | Pregunta simple | Transcribe \u2192 responde \u2192 sintetiza |
55383
+ | Comando | Transcribe \u2192 ejecuta \u2192 confirma por voz |
55384
+ | Di\xE1logo | Mantener contexto entre exchanges |
55385
+ | Wake word | Escuchar "hey bee" \u2192 activar \u2192 procesar |
54482
55386
 
54483
- ## Workflow Completo
55387
+ ## Configuraci\xF3n
54484
55388
 
55389
+ ### Wake Word
55390
+ \`\`\`json
55391
+ {
55392
+ "voice_wake_word": "hey bee",
55393
+ "voice_wake_enabled": true
55394
+ }
54485
55395
  \`\`\`
54486
- Usuario: "transcribir reuni\xF3n"
54487
- \u2192 Agente pregunta t\xEDtulo
54488
- \u2192 meeting_start(title) \u2192 session_id: "abc123"
54489
- \u2192 Agente: "\u2705 Sesi\xF3n abc123 iniciada. Habla cuando quieras."
54490
-
54491
- [Usuario graba audio en la UI]
54492
- \u2192 meeting_add_segment(session_id, audio_base64)
54493
- \u2192 notify: "[Speaker]: Texto transcrito..."
54494
-
54495
- Usuario: "detener reuni\xF3n"
54496
- \u2192 meeting_stop(session_id)
54497
- \u2192 Agente: "\u23F9\uFE0F 47 segmentos transcritos. \xBFGenero el reporte?"
54498
55396
 
54499
- Usuario: "s\xED"
54500
- \u2192 meeting_report(session_id) \u2192 transcript completo
54501
- \u2192 LLM analiza \u2192 secciones estructuradas
54502
- \u2192 office_escribir_docx \u2192 informe_reunion_abc123.docx
54503
- \u2192 notify: [Markdown del informe completo]
54504
- \u2192 Agente: "\u2705 DOCX guardado en workspace."
55397
+ ### Canal Voice
55398
+ \`\`\`json
55399
+ {
55400
+ "voice_enabled": true,
55401
+ "tts_enabled": true,
55402
+ "stt_provider": "groq-whisper",
55403
+ "tts_provider": "elevenlabs",
55404
+ "tts_voice_id": "eleven_flash_v2_5"
55405
+ }
54505
55406
  \`\`\`
54506
55407
 
54507
- ## Formato del Informe Gerencial
54508
-
54509
- El informe generado incluye:
55408
+ ## Mejores Pr\xE1cticas
54510
55409
 
54511
- 1. **Resumen Ejecutivo** \u2014 Captura la esencia en 3-5 oraciones
54512
- 2. **Participantes** \u2014 Detectados autom\xE1ticamente del transcript
54513
- 3. **Decisiones Tomadas** \u2014 Lista numerada de cada decisi\xF3n
54514
- 4. **Action Items** \u2014 Tabla con Tarea / Responsable / Fecha
54515
- 5. **Pr\xF3ximos Pasos** \u2014 Acciones inmediatas
54516
- 6. **Temas de Seguimiento** \u2014 Pendientes para futuras reuniones
55410
+ - Respuestas cortas y naturales (<60s)
55411
+ - Mantener contexto conversacional
55412
+ - Indicadores de procesamiento
55413
+ - Fallback a texto si falla voz
54517
55414
 
54518
- ## Consideraciones
55415
+ ## Errores a Evitar
54519
55416
 
54520
- - El informe se entrega en dos formatos: **Markdown en chat** + **DOCX descargable**
54521
- - El idioma del informe es siempre **espa\xF1ol**
54522
- - La latencia de transcripci\xF3n es ~4s por chunk de 3s de audio (normal para Whisper)
54523
- - El session_id debe conservarse durante toda la reuni\xF3n
55417
+ - \u274C Respuestas muy largas para audio
55418
+ - \u274C Perder contexto entre exchanges
55419
+ - \u274C No indicar que est\xE1 procesando
55420
+ - \u274C No tener fallback si falla TTS/STT
54524
55421
  `
54525
55422
  },
54526
55423
  {
54527
- name: "api_client",
54528
- description: `Make HTTP requests to REST APIs using curl-like methods (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS)`,
54529
- category: "api",
55424
+ name: "voice_output",
55425
+ description: `Convert text to synthesized speech using TTS (Text-to-Speech) providers like ElevenLabs, OpenAI TTS, or Gemini TTS`,
55426
+ category: "voice",
54530
55427
  version: "1.0.0",
54531
- tools: ["api_request"],
54532
- triggers: ["llama a la api", "llama al api", "consume la api", "haz una petici\xF3n", "haz un request", "env\xEDa un post", "env\xEDa un put", "env\xEDa un delete", "curl", "api request", "rest api", "endpoint", "webhook", "integrar con api", "conectar con api", "obtener datos de api", "enviar datos a api"],
55428
+ tools: ["voice_speak"],
55429
+ triggers: ["le\xE9 esto en voz alta", "read this aloud", "convert\xED a voz", "convert to speech", "habl\xE1 este texto", "speak this text", "texto a voz", "text to speech", "gener\xE1 audio", "generate audio", "s\xEDntesis de voz", "voice synthesis", "escuch\xE1 la respuesta", "listen to response"],
54533
55430
  body: `
54534
- # API Client Skill
55431
+ # Voice Output Skill
54535
55432
 
54536
55433
  ## Cu\xE1ndo se Activa
54537
55434
 
54538
- Esta skill se activa cuando el usuario necesita interactuar con una API REST: consultar datos, crear recursos, actualizar, eliminar, o cualquier operaci\xF3n HTTP.
55435
+ Esta skill se activa cuando el usuario necesita convertir texto a voz: leer respuestas, generar audio, s\xEDntesis de voz.
54539
55436
 
54540
55437
  ## Herramientas Disponibles
54541
55438
 
54542
55439
  | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54543
55440
  |------|----------|---------------|
54544
- | \`api_request\` | Realiza peticiones HTTP completas (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) con headers, body, query params y timeout | Siempre que necesites llamar un endpoint REST, webhook, o servicio externo |
55441
+ | \`voice_speak\` | Convierte texto \u2192 audio | S\xEDntesis de voz |
54545
55442
 
54546
- ## Par\xE1metros de api_request
55443
+ ## Workflow
54547
55444
 
54548
- - \`method\` (requerido): GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
54549
- - \`url\` (requerido): URL completa del endpoint
54550
- - \`headers\` (opcional): objeto con headers HTTP. Ej: \`{ "Authorization": "Bearer TOKEN", "Content-Type": "application/json" }\`
54551
- - \`body\` (opcional): cuerpo de la petici\xF3n como string. Para JSON, enviar JSON.stringify(objeto)
54552
- - \`query_params\` (opcional): par\xE1metros de query que se codificar\xE1n autom\xE1ticamente en la URL
54553
- - \`timeout_ms\` (opcional): timeout en ms. Default: 30000. M\xE1x: 120000
55445
+ ### Text-to-Speech
55446
+ \`\`\`javascript
55447
+ // 1. Recibir texto
55448
+ const text = "Hola, \xBFc\xF3mo est\xE1s?"
54554
55449
 
54555
- ## Diferencia con web_fetch
55450
+ // 2. Preprocesar
55451
+ // - Expandir n\xFAmeros: "5" \u2192 "cinco"
55452
+ // - Expandir fechas: "01/01" \u2192 "primero de enero"
55453
+ // - Expandir abbreviaturas: "Dr." \u2192 "Doctor"
54556
55454
 
54557
- - \`web_fetch\`: solo GET, sin headers custom, ideal para scraping de p\xE1ginas web
54558
- - \`api_request\`: cualquier m\xE9todo HTTP, headers custom, body, query params \u2014 ideal para APIs REST
55455
+ // 3. Sintetizar
55456
+ const audio = voice_speak({
55457
+ text: optimizedText,
55458
+ voice_id: "eleven_flash_v2_5", // o configured voice
55459
+ language: "es"
55460
+ })
54559
55461
 
54560
- ## Workflow
55462
+ // 4. Entregar audio
55463
+ // - Enviar como archivo
55464
+ // - Streaming si el canal lo soporta
55465
+ \`\`\`
54561
55466
 
54562
- 1. **Identificar endpoint y m\xE9todo** \u2192 Determinar URL, m\xE9todo, headers necesarios
54563
- 2. **Construir request** \u2192 \`api_request({ method, url, headers, body })\`
54564
- 3. **Validar respuesta** \u2192 Si 2xx: extraer datos. Si error: analizar y sugerir fix
54565
- 4. **Presentar resultados** \u2192 JSON parseado en formato legible, no crudo a menos que se pida
55467
+ ## Proveedores TTS Soportados
55468
+
55469
+ | Provider | Modelos | Voces |
55470
+ |----------|---------|-------|
55471
+ | ElevenLabs | Flash V2.5, Turbo V2.5, Multilingual V2, V3 | 1000+ |
55472
+ | OpenAI | tts-1, tts-1-hd, gpt-4o-mini-tts | 6+ |
55473
+ | Gemini | 2.5 Flash TTS, 2.5 Pro TTS | Multi |
55474
+ | Qwen | Qwen TTS Flash, Instruct | Multi |
55475
+
55476
+ ## Configuraci\xF3n por Canal
55477
+
55478
+ Cada canal configura su proveedor TTS:
55479
+ - \`tts_provider\`: "elevenlabs" | "openai-tts" | "gemini-tts"
55480
+ - \`tts_voice_id\`: ID espec\xEDfico de voz (ej. ElevenLabs voice ID)
54566
55481
 
54567
55482
  ## Mejores Pr\xE1cticas
54568
55483
 
54569
- - Siempre enviar \`Content-Type: application/json\` cuando el body es JSON
54570
- - Usar \`query_params\` en lugar de append manual a la URL
54571
- - No exponer tokens/secrets en la respuesta final al usuario
54572
- - Si la API requiere auth, pedirla al usuario o usar variables de entorno
54573
- - Para errores 4xx, revisar: auth, formato del body, campos requeridos, rate limits
55484
+ - Preprocesar texto para naturalidad
55485
+ - Usar voz configurada por usuario
55486
+ - Cachear respuestas frecuentes
55487
+ - Split de textos largos
54574
55488
 
54575
55489
  ## Errores a Evitar
54576
55490
 
54577
- - \u274C Usar web_fetch para POST/PUT/DELETE con headers
54578
- - \u274C Enviar objetos directamente en body (debe ser string)
54579
- - \u274C Olvidar Content-Type al enviar JSON
54580
- - \u274C Exponer API keys en la respuesta visible
55491
+ - \u274C Enviar texto crudo sin preprocesar
55492
+ - \u274C Ignorar preferencia de voz
55493
+ - \u274C No manejar l\xEDmites de longitud
55494
+ - \u274C No cachear (costo API)
54581
55495
  `
54582
55496
  },
54583
55497
  {
@@ -54719,71 +55633,6 @@ const result = task_status({ task_id })
54719
55633
  - \u274C No monitorear ejecuci\xF3n larga
54720
55634
  - \u274C Ignorar errores del subagente
54721
55635
  - \u274C No verificar que el c\xF3digo cumple requisitos
54722
- `
54723
- },
54724
- {
54725
- name: "memory_manager",
54726
- description: `Complete management of persistent memory including write, read, search, list, and delete operations`,
54727
- category: "agents",
54728
- version: "1.0.0",
54729
- tools: ["memory_write", "memory_read", "memory_list", "memory_search", "memory_delete"],
54730
- triggers: ["guard\xE1 en memoria", "save to memory", "record\xE1 esto", "remember this", "le\xE9 la memoria", "read memory", "qu\xE9 hay en memoria", "what's in memory", "busc\xE1 en memoria", "search memory", "lista las memorias", "list memories", "elimin\xE1 de memoria", "delete from memory", "preferencias", "preferences", "datos persistentes", "persistent data"],
54731
- body: `
54732
- # Memory Manager Skill
54733
-
54734
- ## Cu\xE1ndo se Activa
54735
-
54736
- Para guardar, recuperar, buscar, listar o eliminar informaci\xF3n persistente entre sesiones.
54737
-
54738
- ## Herramientas Disponibles
54739
-
54740
- | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
54741
- |------|----------|---------------|
54742
- | \`memory_write\` | Almacena con t\xEDtulo \xFAnico | Guardar preferencias, datos |
54743
- | \`memory_read\` | Recupera por t\xEDtulo exacto | Cuando conoc\xE9s el t\xEDtulo |
54744
- | \`memory_list\` | Lista todos los t\xEDtulos | Explorar qu\xE9 hay guardado |
54745
- | \`memory_search\` | Busca por keywords | Cuando no record\xE1s t\xEDtulo exacto |
54746
- | \`memory_delete\` | Elimina entrada | Limpiar datos obsoletos |
54747
-
54748
- ## Workflow
54749
-
54750
- ### Write
54751
- \`\`\`javascript
54752
- memory_write({
54753
- title: "Preferencias de Desarrollo",
54754
- content: "TypeScript, VS Code, Prettier single quotes"
54755
- })
54756
- \`\`\`
54757
-
54758
- ### Read/Search
54759
- \`\`\`javascript
54760
- memory_read({ title: "Preferencias" }) // T\xEDtulo exacto
54761
- memory_search({ query: "preferencias" }) // Fuzzy match
54762
- \`\`\`
54763
-
54764
- ### List
54765
- \`\`\`javascript
54766
- memory_list({}) // Todos los t\xEDtulos
54767
- \`\`\`
54768
-
54769
- ### Delete
54770
- \`\`\`javascript
54771
- memory_delete({ title: "Datos Temporales" })
54772
- \`\`\`
54773
-
54774
- ## Mejores Pr\xE1cticas
54775
-
54776
- - T\xEDtulos descriptivos y \xFAnicos
54777
- - Agrupar datos relacionados en misma entrada
54778
- - Confirmar antes de sobrescribir
54779
- - No guardar datos sensibles
54780
-
54781
- ## Errores a Evitar
54782
-
54783
- - \u274C Datos sensibles (passwords, API keys)
54784
- - \u274C T\xEDtulos gen\xE9ricos ("Config", "Datos")
54785
- - \u274C Sobrescribir sin confirmar
54786
- - \u274C Entradas gigantes (split por tema)
54787
55636
  `
54788
55637
  },
54789
55638
  {
@@ -54953,241 +55802,137 @@ bus_read() \u2192 [{ from: "writer", content: "Need research results" }]
54953
55802
  `
54954
55803
  },
54955
55804
  {
54956
- name: "busqueda_fts5",
54957
- description: `Core discovery skill - find any capability with a single keyword`,
54958
- category: "core",
54959
- version: "1.2.0",
54960
- tools: ["search_knowledge"],
54961
- triggers: ["c\xF3mo busco herramientas", "c\xF3mo encuentro skills", "how to find tools", "search knowledge", "discovery", "buscar en la base", "encontrar herramientas"],
54962
- body: `
54963
- # busqueda_fts5 \u2014 Sistema de Discovery
54964
-
54965
- Arranc\xE1s con solo 4 herramientas. Todo lo dem\xE1s se descubre con **search_knowledge**.
54966
-
54967
- ## Regla de oro: UNA PALABRA, busca TODO
54968
-
54969
- \`\`\`
54970
- search_knowledge(query="email")
54971
- \`\`\`
54972
-
54973
- Eso solo \u2014 sin type, sin frases largas \u2014 devuelve tools, skills, MCP y playbook relacionados con "email".
54974
-
54975
- **NO hagas esto:** \`search_knowledge(type="tools", query="enviar correo electr\xF3nico")\` \u2014 AND entre palabras no encuentra nada.
54976
-
54977
- **S\xCD hagas esto:** \`search_knowledge(query="email")\` \u2014 encuentra todo lo relacionado.
54978
-
54979
- ## Cu\xE1ndo especificar type
54980
-
54981
- Solo si quer\xE9s filtrar resultados que ya son muchos:
54982
-
54983
- \`\`\`
54984
- search_knowledge(query="email", type="mcp") \u2192 solo herramientas externas de email
54985
- search_knowledge(query="email", type="tools") \u2192 solo herramientas nativas de email
54986
- \`\`\`
54987
-
54988
- Por defecto type="all" \u2014 no hace falta especificarlo.
54989
-
54990
- ## Regla de prioridad
54991
-
54992
- **Prefer\xED herramientas nativas sobre MCP** cuando ambas sirven.
54993
- - Nativas: m\xE1s r\xE1pidas, sin red, siempre disponibles
54994
- - MCP: cuando no hay equivalente nativo
54995
-
54996
- ## Flujo de uso
54997
-
54998
- 1. Identific\xE1 la palabra clave de lo que necesit\xE1s
54999
- 2. \`search_knowledge(query="<palabra>")\` \u2192 resultados de todos los tipos
55000
- 3. Las tools encontradas se inyectan autom\xE1ticamente en tu contexto
55001
- 4. Us\xE1s las tools en el siguiente paso
55002
-
55003
- ---
55004
-
55005
- ## Ejemplos
55006
-
55007
- \`\`\`
55008
- search_knowledge(query="pdf") \u2192 tools para leer/escribir PDFs
55009
- search_knowledge(query="browser") \u2192 tools de navegaci\xF3n web
55010
- search_knowledge(query="github") \u2192 tools MCP de GitHub si est\xE1n configuradas
55011
- search_knowledge(query="calendar") \u2192 tools de Google Calendar
55012
- search_knowledge(query="canvas") \u2192 skills de visualizaci\xF3n
55013
- search_knowledge(query="slack") \u2192 tools de Slack si est\xE1n configuradas
55014
- \`\`\`
55015
- `
55016
- },
55017
- {
55018
- name: "web_monitor",
55019
- description: `Monitor changes in web sources and track updates over time with persistent memory`,
55020
- category: "web",
55805
+ name: "memory_manager",
55806
+ description: `Complete management of persistent memory including write, read, search, list, and delete operations`,
55807
+ category: "agents",
55021
55808
  version: "1.0.0",
55022
- tools: ["web_search", "web_fetch", "memory_write", "memory_read"],
55023
- triggers: ["monitore\xE1", "monitor", "segu\xED los cambios", "track changes", "avisame si cambia", "notify if changes", "actualizaci\xF3n de", "update on", "novedades de", "news about", "cambios en", "changes in"],
55809
+ tools: ["memory_write", "memory_read", "memory_list", "memory_search", "memory_delete"],
55810
+ triggers: ["guard\xE1 en memoria", "save to memory", "record\xE1 esto", "remember this", "le\xE9 la memoria", "read memory", "qu\xE9 hay en memoria", "what's in memory", "busc\xE1 en memoria", "search memory", "lista las memorias", "list memories", "elimin\xE1 de memoria", "delete from memory", "preferencias", "preferences", "datos persistentes", "persistent data"],
55024
55811
  body: `
55025
- # Web Monitor Skill
55812
+ # Memory Manager Skill
55026
55813
 
55027
55814
  ## Cu\xE1ndo se Activa
55028
55815
 
55029
- Esta skill se activa cuando el usuario necesita:
55030
- - Monitorear cambios en una URL espec\xEDfica
55031
- - Recibir notificaciones de actualizaciones
55032
- - Seguir novedades sobre un tema
55033
- - Trackear evoluci\xF3n de contenido
55816
+ Para guardar, recuperar, buscar, listar o eliminar informaci\xF3n persistente entre sesiones.
55034
55817
 
55035
55818
  ## Herramientas Disponibles
55036
55819
 
55037
55820
  | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
55038
55821
  |------|----------|---------------|
55039
- | \`web_fetch\` | Descarga contenido de URL | Obtener contenido actual |
55040
- | \`web_search\` | Busca novedades | Monitoreo por tema (no URL fija) |
55041
- | \`memory_write\` | Guarda baseline | Almacenar contenido para comparaci\xF3n |
55042
- | \`memory_read\` | Recupera baseline anterior | Comparar con contenido actual |
55822
+ | \`memory_write\` | Almacena con t\xEDtulo \xFAnico | Guardar preferencias, datos |
55823
+ | \`memory_read\` | Recupera por t\xEDtulo exacto | Cuando conoc\xE9s el t\xEDtulo |
55824
+ | \`memory_list\` | Lista todos los t\xEDtulos | Explorar qu\xE9 hay guardado |
55825
+ | \`memory_search\` | Busca por keywords | Cuando no record\xE1s t\xEDtulo exacto |
55826
+ | \`memory_delete\` | Elimina entrada | Limpiar datos obsoletos |
55043
55827
 
55044
55828
  ## Workflow
55045
55829
 
55046
- 1. **Primera ejecuci\xF3n**: \`web_fetch\` \u2192 \`memory_write\` (baseline)
55047
- 2. **Chequeos siguientes**: \`memory_read\` \u2192 \`web_fetch\` \u2192 comparar \u2192 \`notify\` si cambia
55048
- 3. **Actualizar baseline**: \`memory_write\` con nuevo contenido
55049
-
55050
- ## Mejores Pr\xE1cticas
55051
-
55052
- - Ignorar cambios menores (timestamps, ads, contenido din\xE1mico irrelevante)
55053
- - Notificar solo cambios significativos
55054
- - Para monitoreo peri\xF3dico, combinar con \`cron.create\`
55055
-
55056
- ## Errores a Evitar
55057
-
55058
- - \u274C No almacenar baseline inicial
55059
- - \u274C Notificar por cambios triviales
55060
- - \u274C No actualizar timestamp de baseline
55061
- `
55062
- },
55063
- {
55064
- name: "web_research",
55065
- description: `Search and synthesize information from multiple web sources into structured reports`,
55066
- category: "web",
55067
- version: "1.0.0",
55068
- tools: ["web_search", "web_fetch"],
55069
- triggers: ["investig\xE1 sobre", "research", "busc\xE1 informaci\xF3n de", "find information about", "qu\xE9 es", "what is", "explicame", "explain", "\xFAltimos avances", "latest advances", "tendencias de", "trends in", "informaci\xF3n actualizada", "current information"],
55070
- body: `
55071
- # Web Research Skill
55072
-
55073
- ## Cu\xE1ndo se Activa
55074
-
55075
- Esta skill se activa cuando el usuario necesita informaci\xF3n actualizada de internet, verificar datos, o investigar temas espec\xEDficos.
55076
-
55077
- ## Herramientas Disponibles
55830
+ ### Write
55831
+ \`\`\`javascript
55832
+ memory_write({
55833
+ title: "Preferencias de Desarrollo",
55834
+ content: "TypeScript, VS Code, Prettier single quotes"
55835
+ })
55836
+ \`\`\`
55078
55837
 
55079
- | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
55080
- |------|----------|---------------|
55081
- | \`web_search\` | Busca en internet, devuelve t\xEDtulos, URLs, snippets | B\xFAsqueda inicial, encontrar fuentes |
55082
- | \`web_fetch\` | Descarga contenido completo de URL (HTML\u2192Markdown) | Profundizar en resultados espec\xEDficos |
55838
+ ### Read/Search
55839
+ \`\`\`javascript
55840
+ memory_read({ title: "Preferencias" }) // T\xEDtulo exacto
55841
+ memory_search({ query: "preferencias" }) // Fuzzy match
55842
+ \`\`\`
55083
55843
 
55084
- ## Workflow
55844
+ ### List
55845
+ \`\`\`javascript
55846
+ memory_list({}) // Todos los t\xEDtulos
55847
+ \`\`\`
55085
55848
 
55086
- 1. **B\xFAsqueda inicial** \u2192 \`web_search({ query, numResults: 8 })\`
55087
- 2. **Fetch contenido** \u2192 \`web_fetch({ urls: top 2-3 })\`
55088
- 3. **B\xFAsqueda complementaria** \u2192 Segundo search si hay gaps
55089
- 4. **S\xEDntesis** \u2192 summary + key points + sources
55849
+ ### Delete
55850
+ \`\`\`javascript
55851
+ memory_delete({ title: "Datos Temporales" })
55852
+ \`\`\`
55090
55853
 
55091
55854
  ## Mejores Pr\xE1cticas
55092
55855
 
55093
- - Queries espec\xEDficos (m\xE1x 6 palabras)
55094
- - M\xEDnimo 2-3 fuentes independientes
55095
- - Priorizar contenido reciente (<1 a\xF1o)
55096
- - Citas con URLs completas
55856
+ - T\xEDtulos descriptivos y \xFAnicos
55857
+ - Agrupar datos relacionados en misma entrada
55858
+ - Confirmar antes de sobrescribir
55859
+ - No guardar datos sensibles
55097
55860
 
55098
55861
  ## Errores a Evitar
55099
55862
 
55100
- - \u274C Inventar datos no encontrados
55101
- - \u274C Concluir con una sola b\xFAsqueda
55102
- - \u274C No verificar fecha de fuentes
55103
- - \u274C Copiar contenido literal (usar par\xE1frasis)
55863
+ - \u274C Datos sensibles (passwords, API keys)
55864
+ - \u274C T\xEDtulos gen\xE9ricos ("Config", "Datos")
55865
+ - \u274C Sobrescribir sin confirmar
55866
+ - \u274C Entradas gigantes (split por tema)
55104
55867
  `
55105
55868
  },
55106
55869
  {
55107
- name: "browser_automate",
55108
- description: `Automate web workflows with navigation, clicks, form filling, and visual verification`,
55109
- category: "web",
55870
+ name: "meeting_transcription",
55871
+ description: `Transcribir reuniones en tiempo real y generar informes gerenciales con decisiones, action items y pr\xF3ximos pasos`,
55872
+ category: "meeting",
55110
55873
  version: "1.0.0",
55111
- tools: ["browser_navigate", "browser_click", "browser_type", "browser_screenshot"],
55112
- triggers: ["automatiz\xE1 el navegador", "automate browser", "complet\xE1 el formulario", "fill form", "hac\xE9 clic en", "click on", "inici\xE1 sesi\xF3n", "login", "registrate", "sign up", "interactu\xE1 con la web", "interact with website", "flujo web", "web workflow"],
55874
+ tools: ["meeting_start", "meeting_add_segment", "meeting_stop", "meeting_report", "office_escribir_docx", "notify", "report_progress"],
55875
+ triggers: ["transcribir reuni\xF3n", "iniciar transcripci\xF3n", "meeting transcription", "grabar reuni\xF3n", "iniciar reuni\xF3n", "start meeting", "detener reuni\xF3n", "stop meeting", "reporte de reuni\xF3n", "generar reporte reuni\xF3n", "informe de reuni\xF3n", "acta de reuni\xF3n", "transcripci\xF3n de reuni\xF3n", "meeting report"],
55113
55876
  body: `
55114
- # Browser Automate Skill
55877
+ # Meeting Transcription Skill
55115
55878
 
55116
55879
  ## Cu\xE1ndo se Activa
55117
55880
 
55118
- Esta skill se activa para automatizar flujos de interacci\xF3n con aplicaciones web: logins, formularios, navegaci\xF3n program\xE1tica.
55881
+ Esta skill se activa para gesti\xF3n completa del ciclo de vida de una reuni\xF3n: inicio, transcripci\xF3n en tiempo real, detenci\xF3n y generaci\xF3n de informe gerencial.
55119
55882
 
55120
55883
  ## Herramientas Disponibles
55121
55884
 
55122
55885
  | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
55123
55886
  |------|----------|---------------|
55124
- | \`browser_navigate\` | Navega a URL | Inicio de flujo |
55125
- | \`browser_click\` | Click en elementos | Botones, enlaces, triggers |
55126
- | \`browser_type\` | Escribe en inputs | Formularios, b\xFAsquedas |
55127
- | \`browser_screenshot\` | Captura estado | Verificaci\xF3n visual |
55128
-
55129
- ## Workflow T\xEDpico
55130
-
55131
- 1. **Navegar** \u2192 URL inicial
55132
- 2. **Interactuar** \u2192 click/type seg\xFAn flujo
55133
- 3. **Verificar** \u2192 screenshot despu\xE9s de acciones cr\xEDticas
55134
- 4. **Repetir** \u2192 para flujos multi-paso
55135
-
55136
- ## Mejores Pr\xE1cticas
55137
-
55138
- - Selectores estables (IDs > classes > XPath)
55139
- - Esperar carga despu\xE9s de navegaci\xF3n
55140
- - Verificar estado visual con screenshots
55141
- - Manejar errores de elementos no encontrados
55142
-
55143
- ## Errores a Evitar
55144
-
55145
- - \u274C Selectores fr\xE1giles que cambian
55146
- - \u274C No esperar carga de p\xE1gina
55147
- - \u274C Ignorar errores de elementos
55148
- - \u274C No verificar estado despu\xE9s de acciones
55149
- `
55150
- },
55151
- {
55152
- name: "browser_scrape",
55153
- description: `Navigate to web pages and capture rendered content including screenshots for dynamic sites`,
55154
- category: "web",
55155
- version: "1.0.0",
55156
- tools: ["browser_navigate", "browser_screenshot", "web_fetch"],
55157
- triggers: ["captur\xE1 el contenido", "scrape content", "obten\xE9 la p\xE1gina renderizada", "get rendered page", "sitios din\xE1micos", "dynamic sites", "web con javascript", "javascript websites", "tom\xE1 screenshot y contenido", "screenshot and content"],
55158
- body: `
55159
- # Browser Scrape Skill
55887
+ | \`meeting_start\` | Crea una sesi\xF3n en DB \u2192 devuelve session_id | Al iniciar la reuni\xF3n |
55888
+ | \`meeting_add_segment\` | Transcribe un chunk de audio y lo persiste | Por cada audio recibido |
55889
+ | \`meeting_stop\` | Marca la sesi\xF3n como detenida | Cuando termina la reuni\xF3n |
55890
+ | \`meeting_report\` | Lee todos los segmentos y arma el transcript | Para generar el reporte |
55891
+ | \`office_escribir_docx\` | Guarda el reporte como archivo Word | Al finalizar el an\xE1lisis |
55892
+ | \`notify\` | Env\xEDa mensajes en tiempo real al canal | Para mostrar transcripciones y el reporte |
55893
+ | \`report_progress\` | Muestra progreso en barra | Durante transcripci\xF3n larga |
55160
55894
 
55161
- ## Cu\xE1ndo se Activa
55895
+ ## Workflow Completo
55162
55896
 
55163
- Esta skill se activa para sitios web din\xE1micos que requieren JavaScript rendering, donde el contenido no est\xE1 disponible en HTML est\xE1tico.
55897
+ \`\`\`
55898
+ Usuario: "transcribir reuni\xF3n"
55899
+ \u2192 Agente pregunta t\xEDtulo
55900
+ \u2192 meeting_start(title) \u2192 session_id: "abc123"
55901
+ \u2192 Agente: "\u2705 Sesi\xF3n abc123 iniciada. Habla cuando quieras."
55164
55902
 
55165
- ## Herramientas Disponibles
55903
+ [Usuario graba audio en la UI]
55904
+ \u2192 meeting_add_segment(session_id, audio_base64)
55905
+ \u2192 notify: "[Speaker]: Texto transcrito..."
55166
55906
 
55167
- | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
55168
- |------|----------|---------------|
55169
- | \`browser_navigate\` | Navega y renderiza p\xE1gina completa | Sitios con JavaScript/SPA |
55170
- | \`browser_screenshot\` | Captura estado visual | Evidencia de contenido renderizado |
55171
- | \`web_fetch\` | Extrae texto como markdown | Contenido textual de p\xE1gina renderizada |
55907
+ Usuario: "detener reuni\xF3n"
55908
+ \u2192 meeting_stop(session_id)
55909
+ \u2192 Agente: "\u23F9\uFE0F 47 segmentos transcritos. \xBFGenero el reporte?"
55172
55910
 
55173
- ## Workflow
55911
+ Usuario: "s\xED"
55912
+ \u2192 meeting_report(session_id) \u2192 transcript completo
55913
+ \u2192 LLM analiza \u2192 secciones estructuradas
55914
+ \u2192 office_escribir_docx \u2192 informe_reunion_abc123.docx
55915
+ \u2192 notify: [Markdown del informe completo]
55916
+ \u2192 Agente: "\u2705 DOCX guardado en workspace."
55917
+ \`\`\`
55174
55918
 
55175
- 1. **Navegar** \u2192 \`browser_navigate({ url })\` + esperar renderizado JS
55176
- 2. **Capturar visual** \u2192 \`browser_screenshot()\`
55177
- 3. **Extraer texto** \u2192 \`web_fetch()\`
55178
- 4. **Combinar** \u2192 screenshot + texto para scrape completo
55919
+ ## Formato del Informe Gerencial
55179
55920
 
55180
- ## Mejores Pr\xE1cticas
55921
+ El informe generado incluye:
55181
55922
 
55182
- - Esperar renderizado completo de JavaScript
55183
- - Para infinite scroll: hacer scroll y m\xFAltiples screenshots
55184
- - Capturar antes y despu\xE9s de interacciones si es din\xE1mico
55923
+ 1. **Resumen Ejecutivo** \u2014 Captura la esencia en 3-5 oraciones
55924
+ 2. **Participantes** \u2014 Detectados autom\xE1ticamente del transcript
55925
+ 3. **Decisiones Tomadas** \u2014 Lista numerada de cada decisi\xF3n
55926
+ 4. **Action Items** \u2014 Tabla con Tarea / Responsable / Fecha
55927
+ 5. **Pr\xF3ximos Pasos** \u2014 Acciones inmediatas
55928
+ 6. **Temas de Seguimiento** \u2014 Pendientes para futuras reuniones
55185
55929
 
55186
- ## Errores a Evitar
55930
+ ## Consideraciones
55187
55931
 
55188
- - \u274C No esperar renderizado JavaScript
55189
- - \u274C Solo capturar HTML est\xE1tico para sitios SPA
55190
- - \u274C Ignorar t\xE9rminos de servicio del sitio
55932
+ - El informe se entrega en dos formatos: **Markdown en chat** + **DOCX descargable**
55933
+ - El idioma del informe es siempre **espa\xF1ol**
55934
+ - La latencia de transcripci\xF3n es ~4s por chunk de 3s de audio (normal para Whisper)
55935
+ - El session_id debe conservarse durante toda la reuni\xF3n
55191
55936
  `
55192
55937
  },
55193
55938
  {
@@ -55301,532 +56046,6 @@ Para ejecutar comandos y guardar el output en archivos para logging o procesamie
55301
56046
  - \u274C Filenames gen\xE9ricos sin timestamp
55302
56047
  - \u274C No capturar stderr
55303
56048
  `
55304
- },
55305
- {
55306
- name: "voice_output",
55307
- description: `Convert text to synthesized speech using TTS (Text-to-Speech) providers like ElevenLabs, OpenAI TTS, or Gemini TTS`,
55308
- category: "voice",
55309
- version: "1.0.0",
55310
- tools: ["voice_speak"],
55311
- triggers: ["le\xE9 esto en voz alta", "read this aloud", "convert\xED a voz", "convert to speech", "habl\xE1 este texto", "speak this text", "texto a voz", "text to speech", "gener\xE1 audio", "generate audio", "s\xEDntesis de voz", "voice synthesis", "escuch\xE1 la respuesta", "listen to response"],
55312
- body: `
55313
- # Voice Output Skill
55314
-
55315
- ## Cu\xE1ndo se Activa
55316
-
55317
- Esta skill se activa cuando el usuario necesita convertir texto a voz: leer respuestas, generar audio, s\xEDntesis de voz.
55318
-
55319
- ## Herramientas Disponibles
55320
-
55321
- | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
55322
- |------|----------|---------------|
55323
- | \`voice_speak\` | Convierte texto \u2192 audio | S\xEDntesis de voz |
55324
-
55325
- ## Workflow
55326
-
55327
- ### Text-to-Speech
55328
- \`\`\`javascript
55329
- // 1. Recibir texto
55330
- const text = "Hola, \xBFc\xF3mo est\xE1s?"
55331
-
55332
- // 2. Preprocesar
55333
- // - Expandir n\xFAmeros: "5" \u2192 "cinco"
55334
- // - Expandir fechas: "01/01" \u2192 "primero de enero"
55335
- // - Expandir abbreviaturas: "Dr." \u2192 "Doctor"
55336
-
55337
- // 3. Sintetizar
55338
- const audio = voice_speak({
55339
- text: optimizedText,
55340
- voice_id: "eleven_flash_v2_5", // o configured voice
55341
- language: "es"
55342
- })
55343
-
55344
- // 4. Entregar audio
55345
- // - Enviar como archivo
55346
- // - Streaming si el canal lo soporta
55347
- \`\`\`
55348
-
55349
- ## Proveedores TTS Soportados
55350
-
55351
- | Provider | Modelos | Voces |
55352
- |----------|---------|-------|
55353
- | ElevenLabs | Flash V2.5, Turbo V2.5, Multilingual V2, V3 | 1000+ |
55354
- | OpenAI | tts-1, tts-1-hd, gpt-4o-mini-tts | 6+ |
55355
- | Gemini | 2.5 Flash TTS, 2.5 Pro TTS | Multi |
55356
- | Qwen | Qwen TTS Flash, Instruct | Multi |
55357
-
55358
- ## Configuraci\xF3n por Canal
55359
-
55360
- Cada canal configura su proveedor TTS:
55361
- - \`tts_provider\`: "elevenlabs" | "openai-tts" | "gemini-tts"
55362
- - \`tts_voice_id\`: ID espec\xEDfico de voz (ej. ElevenLabs voice ID)
55363
-
55364
- ## Mejores Pr\xE1cticas
55365
-
55366
- - Preprocesar texto para naturalidad
55367
- - Usar voz configurada por usuario
55368
- - Cachear respuestas frecuentes
55369
- - Split de textos largos
55370
-
55371
- ## Errores a Evitar
55372
-
55373
- - \u274C Enviar texto crudo sin preprocesar
55374
- - \u274C Ignorar preferencia de voz
55375
- - \u274C No manejar l\xEDmites de longitud
55376
- - \u274C No cachear (costo API)
55377
- `
55378
- },
55379
- {
55380
- name: "voice_assistant",
55381
- description: `Full voice-to-voice interaction: transcribe user speech, process request, and respond with synthesized speech`,
55382
- category: "voice",
55383
- version: "1.0.0",
55384
- tools: ["voice_transcribe", "voice_speak"],
55385
- triggers: ["modo voz", "voice mode", "asistente de voz", "voice assistant", "habl\xE1 conmigo", "talk to me", "interacci\xF3n por voz", "voice interaction", "respuesta hablada", "spoken response", "comando de voz", "voice command", "di\xE1logo por voz", "voice dialogue"],
55386
- body: `
55387
- # Voice Assistant Skill
55388
-
55389
- ## Cu\xE1ndo se Activa
55390
-
55391
- Esta skill se activa para interacci\xF3n completa voz a voz: el usuario habla, el asistente procesa y responde con voz.
55392
-
55393
- ## Herramientas Disponibles
55394
-
55395
- | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
55396
- |------|----------|---------------|
55397
- | \`voice_transcribe\` | Audio \u2192 texto | Input del usuario |
55398
- | \`voice_speak\` | Texto \u2192 audio | Respuesta del asistente |
55399
-
55400
- ## Workflow
55401
-
55402
- ### Voice-to-Voice
55403
- \`\`\`javascript
55404
- // 1. Usuario habla
55405
- const userAudio = receiveAudio()
55406
-
55407
- // 2. Transcribir
55408
- const userText = voice_transcribe({
55409
- audio: userAudio,
55410
- language: "auto"
55411
- })
55412
- // \u2192 "\xBFCu\xE1l es el clima hoy?"
55413
-
55414
- // 3. Procesar request
55415
- // - Entender intenci\xF3n
55416
- // - Ejecutar acci\xF3n (ej. consultar API clima)
55417
- // - Generar respuesta
55418
- const responseText = "Hoy hay 25 grados y soleado en Buenos Aires"
55419
-
55420
- // 4. Sintetizar respuesta
55421
- const responseAudio = voice_speak({
55422
- text: responseText,
55423
- voice_id: "eleven_flash_v2_5",
55424
- language: "es"
55425
- })
55426
-
55427
- // 5. Enviar audio
55428
- sendAudio(responseAudio)
55429
- \`\`\`
55430
-
55431
- ## Casos de Uso
55432
-
55433
- | Caso | Flujo |
55434
- |------|-------|
55435
- | Pregunta simple | Transcribe \u2192 responde \u2192 sintetiza |
55436
- | Comando | Transcribe \u2192 ejecuta \u2192 confirma por voz |
55437
- | Di\xE1logo | Mantener contexto entre exchanges |
55438
- | Wake word | Escuchar "hey bee" \u2192 activar \u2192 procesar |
55439
-
55440
- ## Configuraci\xF3n
55441
-
55442
- ### Wake Word
55443
- \`\`\`json
55444
- {
55445
- "voice_wake_word": "hey bee",
55446
- "voice_wake_enabled": true
55447
- }
55448
- \`\`\`
55449
-
55450
- ### Canal Voice
55451
- \`\`\`json
55452
- {
55453
- "voice_enabled": true,
55454
- "tts_enabled": true,
55455
- "stt_provider": "groq-whisper",
55456
- "tts_provider": "elevenlabs",
55457
- "tts_voice_id": "eleven_flash_v2_5"
55458
- }
55459
- \`\`\`
55460
-
55461
- ## Mejores Pr\xE1cticas
55462
-
55463
- - Respuestas cortas y naturales (<60s)
55464
- - Mantener contexto conversacional
55465
- - Indicadores de procesamiento
55466
- - Fallback a texto si falla voz
55467
-
55468
- ## Errores a Evitar
55469
-
55470
- - \u274C Respuestas muy largas para audio
55471
- - \u274C Perder contexto entre exchanges
55472
- - \u274C No indicar que est\xE1 procesando
55473
- - \u274C No tener fallback si falla TTS/STT
55474
- `
55475
- },
55476
- {
55477
- name: "voice_input",
55478
- description: `Transcribe audio input to text using STT (Speech-to-Text) providers like Groq Whisper or OpenAI Whisper`,
55479
- category: "voice",
55480
- version: "1.0.0",
55481
- tools: ["voice_transcribe"],
55482
- triggers: ["transcrib\xED este audio", "transcribe audio", "convert\xED voz a texto", "convert voice to text", "qu\xE9 dice el audio", "what does audio say", "escuch\xE1 esto", "listen to this", "audio a texto", "audio to text", "reconocimiento de voz", "speech recognition", "nota de voz", "voice note"],
55483
- body: `
55484
- # Voice Input Skill
55485
-
55486
- ## Cu\xE1ndo se Activa
55487
-
55488
- Esta skill se activa cuando el usuario env\xEDa audio y necesita transcripci\xF3n a texto: notas de voz, grabaciones, comandos de voz.
55489
-
55490
- ## Herramientas Disponibles
55491
-
55492
- | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
55493
- |------|----------|---------------|
55494
- | \`voice_transcribe\` | Convierte audio \u2192 texto | Transcripci\xF3n de cualquier audio |
55495
-
55496
- ## Workflow
55497
-
55498
- ### Transcripci\xF3n
55499
- \`\`\`javascript
55500
- // 1. Recibir audio
55501
- // - File upload
55502
- // - Voice message (Telegram, WhatsApp)
55503
- // - Stream en vivo
55504
-
55505
- // 2. Transcribir
55506
- const result = voice_transcribe({
55507
- audio: audioBuffer,
55508
- language: "es" // o "auto" para detectar
55509
- })
55510
-
55511
- // 3. Formatear
55512
- // - Agregar puntuaci\xF3n
55513
- // - Capitalizar
55514
- // - Marcar speakers si hay m\xFAltiples
55515
-
55516
- // 4. Entregar resultado
55517
- \`\`\`
55518
-
55519
- ## Proveedores STT Soportados
55520
-
55521
- | Provider | Modelos | Idiomas |
55522
- |----------|---------|---------|
55523
- | Groq | whisper-large-v3, turbo | Multi |
55524
- | OpenAI | whisper-1 | Multi |
55525
-
55526
- ## Configuraci\xF3n por Canal
55527
-
55528
- Cada canal puede configurar su proveedor STT preferido:
55529
- - \`stt_provider\`: "groq-whisper" | "openai-whisper"
55530
-
55531
- ## Mejores Pr\xE1cticas
55532
-
55533
- - Detectar idioma autom\xE1ticamente
55534
- - Agregar puntuaci\xF3n para legibilidad
55535
- - Marcar segmentos inaudibles
55536
- - Preservar idioma original
55537
-
55538
- ## Errores a Evitar
55539
-
55540
- - \u274C Traducir sin pedir (mantener idioma)
55541
- - \u274C Omitir puntuaci\xF3n
55542
- - \u274C No indicar baja confianza
55543
- - \u274C Ignorar ruido de fondo que afecta calidad
55544
- `
55545
- },
55546
- {
55547
- name: "cron_manager",
55548
- description: `Complete management of cron jobs with cron expressions. Create, list, update, pause, resume, delete, trigger, and view history. Use for reminders, automated reports, periodic checks.`,
55549
- category: "cron",
55550
- version: "2.0.0",
55551
- tools: ["cron.create", "cron.list", "cron.update", "cron.delete", "cron.pause", "cron.resume", "cron.trigger", "cron.history"],
55552
- triggers: ["program\xE1 una tarea", "schedule task", "cre\xE1 un cron", "create cron", "edit\xE1 el cron", "edit cron", "elimin\xE1 el cron", "remove cron", "lista las tareas", "list cron jobs", "modific\xE1 el cron", "modify cron", "tarea recurrente", "recurring task", "todos los d\xEDas", "daily", "cada semana", "weekly"],
55553
- body: `
55554
- # Cron Manager Skill
55555
-
55556
- ## Cu\xE1ndo se Activa
55557
-
55558
- Para gestionar tareas programadas (cron jobs): crear, listar, actualizar, pausar, reanudar, eliminar, ejecutar y ver historial.
55559
-
55560
- ## Herramientas Disponibles
55561
-
55562
- | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
55563
- |------|----------|---------------|
55564
- | \`cron.create\` | Crear cron job | Nueva tarea |
55565
- | \`cron.list\` | Listar todos | Ver existentes |
55566
- | \`cron.update\` | Actualizar existente | Cambiar horario/instrucci\xF3n |
55567
- | \`cron.pause\` | Pausar temporalmente | Sin eliminar |
55568
- | \`cron.resume\` | Reanudar pausado | Continuar ejecuci\xF3n |
55569
- | \`cron.delete\` | Eliminar permanentemente | Cancelar para siempre |
55570
- | \`cron.trigger\` | Ejecutar ahora | Forzar ejecuci\xF3n |
55571
- | \`cron.history\` | Ver historial | Ver logs de ejecuciones |
55572
-
55573
- ## Campos Principales
55574
-
55575
- | Campo | Tipo | Descripci\xF3n |
55576
- |-------|------|-------------|
55577
- | \`name\` | string | Identificador corto (e.g., 'daily-report') |
55578
- | \`task\` | string | **REQUERIDO** - Instrucciones para el agente al ejecutarse |
55579
- | \`task_type\` | string | 'recurring' (repite) o 'one_shot' (una vez) |
55580
- | \`cron_expression\` | string | Expresi\xF3n cron (solo para recurring) |
55581
- | \`fire_at\` | string | Datetime ISO (solo para one_shot) |
55582
- | \`channel\` | string | Canal de notificaci\xF3n |
55583
- | \`start_at\` | string | Inicio de ventana opcional (Croner startAt) |
55584
- | \`stop_at\` | string | Fin de ventana opcional (Croner stopAt) |
55585
- | \`dom_and_dow\` | number | 0=OR (default), 1=AND (d\xEDa mes + d\xEDa semana) |
55586
-
55587
- ## Cron Expression Format
55588
-
55589
- \`\`\`
55590
- * * * * *
55591
- \u2502 \u2502 \u2502 \u2502 \u2502
55592
- \u2502 \u2502 \u2502 \u2502 \u2514\u2500\u2500 D\xEDa semana (0-6, 0=Domingo)
55593
- \u2502 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500 Mes (1-12)
55594
- \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500 D\xEDa del mes (1-31)
55595
- \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Hora (0-23)
55596
- \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Minuto (0-59)
55597
- \`\`\`
55598
-
55599
- ## Ejemplos Comunes
55600
-
55601
- | Expresi\xF3n | Significado |
55602
- |-----------|-------------|
55603
- | \`0 9 * * *\` | Diario 9:00 AM |
55604
- | \`0 7 * * 1-5\` | Lun-Vie 7:00 AM |
55605
- | \`0 */2 * * *\` | Cada 2 horas |
55606
- | \`0 0 * * 0\` | Domingos medianoche |
55607
- | \`0 0 1 * *\` | D\xEDa 1 de cada mes |
55608
-
55609
- ## C\xF3mo Usar start_at / stop_at
55610
-
55611
- - \`start_at\`: La tarea no ejecuta antes de esta fecha
55612
- - \`stop_at\`: La tarea no ejecuta despu\xE9s de esta fecha
55613
- - Formato ISO: \`'2026-04-01T00:00:00'\`
55614
-
55615
- ## C\xF3mo Usar dom_and_dow
55616
-
55617
- - \`0\` (default): Se ejecuta si es el d\xEDa del mes O el d\xEDa de semana
55618
- - \`1\`: Se ejecuta solo si es EL MISMO d\xEDa del mes Y el d\xEDa de semana
55619
-
55620
- Ejemplo: \`0 9 15 * *\` con dom_and_dow=1 significa "los 15 de cada mes QUE SEA domingo"
55621
-
55622
- ## Workflow para Crear
55623
-
55624
- 1. **Preguntar** \u2192 \xBFone_shot o recurring?
55625
- 2. **Obtener** \u2192 Hora y canal de notificaci\xF3n
55626
- 3. **Crear** \u2192 \`cron.create\` con campo \`task\` obligatorio
55627
- 4. **Confirmar** \u2192 \`cron.list\` mostrar next runs
55628
-
55629
- ## Errores a Evitar
55630
-
55631
- - \u274C Olvidar el campo \`task\` \u2014 es obligatorio
55632
- - \u274C Usar exec para tareas programadas
55633
- - \u274C No preguntar si es one_shot o recurring
55634
- - \u274C No mostrar pr\xF3ximos horarios al crear
55635
- - \u274C Llamar \`cron.update\` sin \`task_id\` \u2014 siempre hacer \`cron.list\` primero`
55636
- },
55637
- {
55638
- name: "file_writer",
55639
- description: `Create, modify, and delete files with safe edit operations and confirmation for large changes`,
55640
- category: "filesystem",
55641
- version: "1.0.0",
55642
- tools: ["project_read", "project_write", "project_edit", "project_exists"],
55643
- triggers: ["cre\xE1 un archivo", "create a file", "escrib\xED en", "write to", "edit\xE1 este archivo", "edit this file", "modific\xE1", "modify", "elimin\xE1 el archivo", "delete file", "guard\xE1 esto", "save this", "actualiz\xE1 el archivo", "update file"],
55644
- body: `
55645
- # File Writer Skill
55646
-
55647
- ## Cu\xE1ndo se Activa
55648
-
55649
- Esta skill se activa cuando el usuario necesita:
55650
- - Crear nuevos archivos
55651
- - Modificar contenido existente
55652
- - Eliminar archivos
55653
- - Guardar cambios
55654
-
55655
- ## Herramientas Disponibles
55656
-
55657
- | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
55658
- |------|----------|---------------|
55659
- | \`project_read\` | Lee archivo existente | Antes de editar para entender estructura |
55660
- | \`project_write\` | Crea o sobreescribe archivo | Archivos nuevos o reescritura completa |
55661
- | \`project_edit\` | Edita secciones espec\xEDficas | Cambios puntuales (find/replace) |
55662
- | \`project_exists\` | Verifica existencia | Para decidir crear vs editar |
55663
-
55664
- ## Workflow
55665
-
55666
- ### Crear Archivo Nuevo
55667
- 1. \`project_exists({ path })\` \u2192 verificar no existe
55668
- 2. \`project_write({ path, content })\` \u2192 crear
55669
-
55670
- ### Editar Archivo Existente
55671
- 1. \`project_exists({ path })\` \u2192 verificar existe
55672
- 2. \`project_read({ path })\` \u2192 entender estructura
55673
- 3. \`project_edit({ path, old_string, new_string })\` \u2192 modificar
55674
- 4. \`canvas_confirm()\` si cambios >50 l\xEDneas
55675
-
55676
- ### Eliminar Archivo
55677
- 1. \`project_exists({ path })\` \u2192 verificar existe
55678
- 2. \`canvas_confirm({ message: '\xBFEliminar archivo?' })\` \u2192 confirmar
55679
- 3. Operaci\xF3n de delete
55680
-
55681
- ## Mejores Pr\xE1cticas
55682
-
55683
- - **Leer antes de editar**: Nunca modificar sin entender estructura
55684
- - **Edit vs Write**: Usar edit para cambios peque\xF1os, write para nuevos archivos
55685
- - **Confirmar cambios grandes**: >50 l\xEDneas requiere confirmaci\xF3n expl\xEDcita
55686
- - **Paths seguros**: Trabajar dentro del workspace por defecto
55687
-
55688
- ## Errores a Evitar
55689
-
55690
- - \u274C Editar sin leer primero
55691
- - \u274C Sobreescribir sin confirmar si es cambio grande
55692
- - \u274C Eliminar sin confirmaci\xF3n expl\xEDcita
55693
- - \u274C Usar write cuando edit es suficiente
55694
- `
55695
- },
55696
- {
55697
- name: "file_read_and_summarize",
55698
- description: `Read and understand file content with automatic summarization for large files`,
55699
- category: "filesystem",
55700
- version: "1.0.0",
55701
- tools: ["project_read"],
55702
- triggers: ["le\xE9 este archivo", "read this file", "mostrame el contenido", "show content", "qu\xE9 dice este archivo", "resum\xED este archivo", "summarize this file", "entend\xE9 este c\xF3digo", "understand this code"],
55703
- body: `
55704
- # File Read and Summarize Skill
55705
-
55706
- ## Cu\xE1ndo se Activa
55707
-
55708
- Esta skill se activa cuando el usuario necesita leer y entender el contenido de un archivo, especialmente cuando:
55709
- - El archivo es grande y necesita resumen
55710
- - Se requiere comprensi\xF3n del contenido (no solo lectura)
55711
- - El usuario pide "qu\xE9 dice", "resum\xED", "entend\xE9"
55712
-
55713
- ## Herramientas Disponibles
55714
-
55715
- | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
55716
- |------|----------|---------------|
55717
- | \`project_read\` | Lee contenido de archivo del workspace | Lectura de cualquier archivo |
55718
-
55719
- ## Workflow
55720
-
55721
- 1. **Verificar existencia** \u2192 \`project_exists({ path })\`
55722
- 2. **Leer contenido** \u2192 \`project_read({ path, offset, limit })\`
55723
- 3. **Sintetizar** \u2192 Resumir si es grande, extraer puntos clave
55724
-
55725
- ## Mejores Pr\xE1cticas
55726
-
55727
- - Para archivos >1000 l\xEDneas, usar \`offset\` y \`limit\`
55728
- - Identificar tipo de archivo por extensi\xF3n y adaptar formato de resumen
55729
- - Para c\xF3digo: identificar funciones, clases, exports principales
55730
- - Para config: explicar settings clave en lenguaje simple
55731
- - Para texto: extraer ideas principales
55732
-
55733
- ## Errores a Evitar
55734
-
55735
- - \u274C Leer sin verificar existencia
55736
- - \u274C Retornar archivo completo sin resumir si es muy grande
55737
- - \u274C No identificar tipo de archivo para adaptar resumen
55738
- `
55739
- },
55740
- {
55741
- name: "file_manager",
55742
- description: `Explore project structure and locate files using glob patterns and directory listing`,
55743
- category: "filesystem",
55744
- version: "1.0.0",
55745
- tools: ["fs_list", "fs_glob", "fs_exists"],
55746
- triggers: ["lista los archivos", "list files", "busc\xE1 archivos", "find files", "explor\xE1 el proyecto", "explore project", "qu\xE9 archivos hay", "what files exist", "busc\xE1 por patr\xF3n", "search by pattern", "existe este archivo", "file exists", "d\xF3nde est\xE1", "where is"],
55747
- body: `
55748
- # File Manager Skill
55749
-
55750
- ## Cu\xE1ndo se Activa
55751
-
55752
- Esta skill se activa cuando el usuario necesita:
55753
- - Explorar la estructura del proyecto
55754
- - Buscar archivos por extensi\xF3n o patr\xF3n
55755
- - Verificar si existe un archivo o directorio
55756
- - Encontrar la ubicaci\xF3n de un archivo
55757
-
55758
- ## Herramientas Disponibles
55759
-
55760
- | Tool | Qu\xE9 hace | Cu\xE1ndo usarla |
55761
- |------|----------|---------------|
55762
- | \`fs_list\` | Lista directorios y archivos | Exploraci\xF3n inicial |
55763
- | \`fs_glob\` | Busca archivos por patr\xF3n wildcard | B\xFAsqueda por extensi\xF3n/patr\xF3n |
55764
- | \`fs_exists\` | Verifica existencia | Pre-check antes de operaciones |
55765
-
55766
- ## Workflow
55767
-
55768
- 1. **Explorar** \u2192 \`fs_list({ path })\` para estructura general
55769
- 2. **Buscar por patr\xF3n** \u2192 \`fs_glob({ pattern })\` para tipos espec\xEDficos
55770
- 3. **Verificar** \u2192 \`fs_exists({ path })\` para confirmaci\xF3n
55771
-
55772
- ## Patrones Glob Comunes
55773
-
55774
- | Patr\xF3n | Encuentra |
55775
- |--------|-----------|
55776
- | \`**/*.ts\` | Todos los TypeScript |
55777
- | \`**/*.test.ts\` | Solo tests |
55778
- | \`**/*.md\` | Documentaci\xF3n |
55779
- | \`**/package.json\` | Todos los package.json |
55780
- | \`src/**/*.tsx\` | React components en src |
55781
-
55782
- ## Errores a Evitar
55783
-
55784
- - \u274C No verificar existencia antes de leer/editar
55785
- - \u274C Usar fs_list cuando se conoce el patr\xF3n (usar glob)
55786
- - \u274C Patrones muy amplios sin filtrado
55787
- `
55788
- },
55789
- {
55790
- name: "cron_reminder",
55791
- description: `Schedule a reminder for yourself at a specific time. Creates a one_shot cron job that sends a notification message via your preferred channel.`,
55792
- category: "cron",
55793
- version: "2.0.0",
55794
- tools: ["cron.create", "notify"],
55795
- triggers: ["recordame", "remind me", "recordatorio", "reminder", "alerta", "alert", "av\xEDsame", "notify me", "program\xE1", "schedule", "para ma\xF1ana", "for tomorrow", "en 30 minutos", "in 30 minutes"],
55796
- body: `
55797
- # Cron Reminder Skill
55798
-
55799
- ## Cu\xE1ndo se Activa
55800
-
55801
- Para crear recordatorios de una sola ejecuci\xF3n (one_shot): "recuerdame a las 3pm", "av\xEDsame en 30 minutos", etc.
55802
-
55803
- ## Herramientas
55804
-
55805
- | Tool | Qu\xE9 hace |
55806
- |------|----------|
55807
- | \`cron.create\` | Crear recordatorio one_shot |
55808
- | \`notify\` | Enviar notificaci\xF3n directa |
55809
-
55810
- ## C\xF3mo Funciona
55811
-
55812
- 1. **Preguntar** \u2192 \xBFDe qu\xE9 te aviso? \xBFA qu\xE9 hora? \xBFPor qu\xE9 canal?
55813
- 2. **Crear** \u2192 \`cron.create\` con \`task_type: 'one_shot'\` y \`fire_at\` en formato ISO
55814
- 3. **Confirmar** \u2192 Mostrar hora programada
55815
-
55816
- ## Par\xE1metros
55817
-
55818
- | Campo | Descripci\xF3n |
55819
- |-------|-------------|
55820
- | \`task\` | **REQUERIDO** - Mensaje del recordatorio |
55821
- | \`task_type\` | Siempre \`'one_shot'\` |
55822
- | \`fire_at\` | Fecha/hora ISO (ej: \`'2026-04-20T15:00:00'\`) |
55823
- | \`channel\` | Canal (telegram, discord, whatsapp, webchat) |
55824
-
55825
- ## Errores Comunes
55826
-
55827
- - \u274C Olvidar el campo \`task\` \u2014 obligatorio para que el agente sepa qu\xE9 enviar
55828
- - \u274C Usar expresiones cron para recordatorios (usar \`fire_at\` en vez de \`cron_expression\`)
55829
- - \u274C Poner \`fire_at\` en el pasado`
55830
56049
  }
55831
56050
  ];
55832
56051
  });
@@ -56069,7 +56288,7 @@ var init_src = __esm(() => {
56069
56288
  });
56070
56289
 
56071
56290
  // packages/core/src/storage/seed.ts
56072
- var SEED_DATA, log42, INITIAL_PLAYBOOK_RULES;
56291
+ var SEED_DATA, log43, INITIAL_PLAYBOOK_RULES;
56073
56292
  var init_seed = __esm(() => {
56074
56293
  init_sqlite();
56075
56294
  init_logger();
@@ -56157,7 +56376,8 @@ var init_seed = __esm(() => {
56157
56376
  { id: "nvidia", name: "NVIDIA NIM", baseUrl: "https://integrate.api.nvidia.com/v1" },
56158
56377
  { id: "minimax", name: "MiniMax", baseUrl: "https://api.minimaxi.com/v1" },
56159
56378
  { id: "opencode-go", name: "OpenCode Go", baseUrl: "https://opencode.ai/zen/go/v1" },
56160
- { id: "piper", name: "Piper (Local TTS)" }
56379
+ { id: "piper", name: "Piper (Local TTS)" },
56380
+ { id: "hiveagents", name: "HiveAgents LLM (Cloudflare)", baseUrl: "https://llm.hiveagents.io/v1", category: "llm" }
56161
56381
  ],
56162
56382
  models: [
56163
56383
  { id: "claude-opus-4-6", providerId: "anthropic", name: "Claude Opus 4.6", modelType: "llm", contextWindow: 200000, capabilities: JSON.stringify(["chat", "vision", "json_mode", "function_calling", "streaming", "code", "reasoning"]) },
@@ -56282,7 +56502,16 @@ var init_seed = __esm(() => {
56282
56502
  { id: "opencode-go/mimo-v2-omni", providerId: "opencode-go", name: "MiMo-V2 Omni", modelType: "llm", contextWindow: 128000, capabilities: JSON.stringify(["chat", "code", "function_calling", "streaming"]) },
56283
56503
  { id: "opencode-go/mimo-v2.5-pro", providerId: "opencode-go", name: "MiMo-V2.5 Pro", modelType: "llm", contextWindow: 128000, capabilities: JSON.stringify(["chat", "code", "function_calling", "streaming", "reasoning"]) },
56284
56504
  { id: "opencode-go/mimo-v2.5", providerId: "opencode-go", name: "MiMo-V2.5", modelType: "llm", contextWindow: 128000, capabilities: JSON.stringify(["chat", "code", "function_calling", "streaming"]) },
56285
- { id: "opencode-go/hy3-preview", providerId: "opencode-go", name: "Hunyuan 3 Preview", modelType: "llm", contextWindow: 128000, capabilities: JSON.stringify(["chat", "code", "function_calling", "streaming"]) }
56505
+ { id: "opencode-go/hy3-preview", providerId: "opencode-go", name: "Hunyuan 3 Preview", modelType: "llm", contextWindow: 128000, capabilities: JSON.stringify(["chat", "code", "function_calling", "streaming"]) },
56506
+ { id: "Qwen3.6-35B-A3B-UD-Q6_K.gguf", providerId: "hiveagents", name: "Qwen3.6 35B MoE (Recomendado)", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming", "reasoning"]) },
56507
+ { id: "Qwen3.6-35B-A3B-UD-Q4_K_M.gguf", providerId: "hiveagents", name: "Qwen3.6 35B MoE (Q4_K_M)", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming", "reasoning"]) },
56508
+ { id: "Qwen3.6-27B-UD-Q4_K_XL.gguf", providerId: "hiveagents", name: "Qwen3.6 27B + MTP", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming", "reasoning"]) },
56509
+ { id: "Qwen3-Coder-Next-UD-Q4_K_M.gguf", providerId: "hiveagents", name: "Qwen3 Coder Next", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming", "code"]) },
56510
+ { id: "Qwopus3.6-27B-v2-MTP-Q6_K.gguf", providerId: "hiveagents", name: "Qwopus3.6 27B v2 (Q6_K)", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming", "reasoning"]) },
56511
+ { id: "Qwopus3.6-27B-v2-MTP-Q4_K_S.gguf", providerId: "hiveagents", name: "Qwopus3.6 27B v2 (Q4_K_S)", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming", "reasoning"]) },
56512
+ { id: "gemma-4-31B-it-UD-Q4_K_XL.gguf", providerId: "hiveagents", name: "Gemma 4 31B Dense", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming"]) },
56513
+ { id: "gemma-4-26B-A4B-it-UD-Q4_K_M.gguf", providerId: "hiveagents", name: "Gemma 4 26B MoE", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming"]) },
56514
+ { id: "gemma-4-12b-it-UD-Q4_K_XL.gguf", providerId: "hiveagents", name: "Gemma 4 12B Dense", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming"]) }
56286
56515
  ],
56287
56516
  mcpServers: [],
56288
56517
  channels: [
@@ -56320,7 +56549,7 @@ Estos lineamientos tienen M\xC1XIMA prioridad sobre cualquier otra instrucci\xF3
56320
56549
  }
56321
56550
  ]
56322
56551
  };
56323
- log42 = logger.child("seed");
56552
+ log43 = logger.child("seed");
56324
56553
  INITIAL_PLAYBOOK_RULES = [
56325
56554
  {
56326
56555
  rule: "Cuando el usuario pida buscar noticias recientes, usa web_search con filtros de fecha en lugar de http_client gen\xE9rico",
@@ -56372,7 +56601,7 @@ function getSingleUserId() {
56372
56601
  const result = db.query("SELECT id FROM users LIMIT 1").get();
56373
56602
  return result?.id || null;
56374
56603
  } catch (e) {
56375
- log43.warn("[getSingleUserId] \u26A0\uFE0F Error getting user ID:", e.message);
56604
+ log44.warn("[getSingleUserId] \u26A0\uFE0F Error getting user ID:", e.message);
56376
56605
  return null;
56377
56606
  }
56378
56607
  }
@@ -56382,7 +56611,7 @@ function getUserIdFromChannelIdentity(channel, channelUserId) {
56382
56611
  const result = db.query("SELECT user_id FROM user_identities WHERE channel = ? AND channel_user_id = ? LIMIT 1").get(channel, channelUserId);
56383
56612
  return result?.user_id || null;
56384
56613
  } catch (e) {
56385
- log43.warn("[getUserIdFromChannelIdentity] \u26A0\uFE0F Error getting user ID from channel identity:", e.message);
56614
+ log44.warn("[getUserIdFromChannelIdentity] \u26A0\uFE0F Error getting user ID from channel identity:", e.message);
56386
56615
  return null;
56387
56616
  }
56388
56617
  }
@@ -56412,7 +56641,7 @@ function getDefaultAgentId() {
56412
56641
  const firstAgent = db.query("SELECT id FROM agents WHERE enabled = 1 LIMIT 1").get();
56413
56642
  return firstAgent?.id || null;
56414
56643
  } catch (e) {
56415
- log43.warn("[getDefaultAgentId] \u26A0\uFE0F Error getting default agent ID:", e.message);
56644
+ log44.warn("[getDefaultAgentId] \u26A0\uFE0F Error getting default agent ID:", e.message);
56416
56645
  return null;
56417
56646
  }
56418
56647
  }
@@ -56422,14 +56651,14 @@ function resolveAgentId(agentId) {
56422
56651
  }
56423
56652
  return getDefaultAgentId();
56424
56653
  }
56425
- var log43;
56654
+ var log44;
56426
56655
  var init_onboarding = __esm(() => {
56427
56656
  init_logger();
56428
56657
  init_sqlite();
56429
56658
  init_crypto();
56430
56659
  init_seed();
56431
56660
  init_src();
56432
- log43 = logger.child("onboarding");
56661
+ log44 = logger.child("onboarding");
56433
56662
  });
56434
56663
 
56435
56664
  // packages/core/src/agent/prompt-builder.ts
@@ -56455,7 +56684,7 @@ ${rule.content}`;
56455
56684
  ${ethicsContent}
56456
56685
 
56457
56686
  `;
56458
- log44.info(`[prompt-builder] Loaded ${ethicsRules.length} ethics rules`);
56687
+ log45.info(`[prompt-builder] Loaded ${ethicsRules.length} ethics rules`);
56459
56688
  } else {
56460
56689
  ethicsSection = `# \xC9TICA Y REGLAS CONSTITUCIONALES
56461
56690
 
@@ -56567,20 +56796,20 @@ ${agent.system_prompt}
56567
56796
  `;
56568
56797
  }
56569
56798
  const systemPrompt = `${ethicsSection}${agentSection}${userSection}`.trim();
56570
- log44.info(`[prompt-builder] Built system prompt for agent=${agent.name} role=${agent.role}`);
56799
+ log45.info(`[prompt-builder] Built system prompt for agent=${agent.name} role=${agent.role}`);
56571
56800
  return systemPrompt;
56572
56801
  }
56573
56802
  async function buildSystemPromptWithProjects(opts) {
56574
56803
  const userId = opts.userId || resolveUserId({}) || "default";
56575
56804
  return buildSystemPrompt({ agentId: opts.agentId, userId });
56576
56805
  }
56577
- var log44;
56806
+ var log45;
56578
56807
  var init_prompt_builder = __esm(() => {
56579
56808
  init_sqlite();
56580
56809
  init_logger();
56581
56810
  init_toon();
56582
56811
  init_onboarding();
56583
- log44 = logger.child("prompt-builder");
56812
+ log45 = logger.child("prompt-builder");
56584
56813
  });
56585
56814
 
56586
56815
  // packages/core/src/mcp/singleton.ts
@@ -56602,7 +56831,7 @@ function syncMCPToolsToDB(serverId, serverName, tools) {
56602
56831
  const deleteExisting = db.prepare("DELETE FROM mcp_tools WHERE server_id = ?");
56603
56832
  deleteExisting.run(serverId);
56604
56833
  if (tools.length === 0) {
56605
- log45.debug(`[mcp:tool-sync] No tools to persist for server ${serverName}`);
56834
+ log46.debug(`[mcp:tool-sync] No tools to persist for server ${serverName}`);
56606
56835
  return;
56607
56836
  }
56608
56837
  const insertTool = db.prepare(`
@@ -56615,9 +56844,9 @@ function syncMCPToolsToDB(serverId, serverName, tools) {
56615
56844
  insertTool.run(id, serverId, serverName, tool.name, tool.description || "");
56616
56845
  count++;
56617
56846
  }
56618
- log45.info(`[mcp:tool-sync] Persisted ${count} MCP tools for server ${serverName} to mcp_tools`);
56847
+ log46.info(`[mcp:tool-sync] Persisted ${count} MCP tools for server ${serverName} to mcp_tools`);
56619
56848
  } catch (err) {
56620
- log45.error(`[mcp:tool-sync] Failed to persist MCP tools for server ${serverName}:`, err);
56849
+ log46.error(`[mcp:tool-sync] Failed to persist MCP tools for server ${serverName}:`, err);
56621
56850
  }
56622
56851
  }
56623
56852
  async function syncMCPToolsToFTS() {
@@ -56635,7 +56864,7 @@ async function syncMCPToolsToFTS() {
56635
56864
  WHERE active = 1
56636
56865
  `).all();
56637
56866
  if (mcpTools.length === 0) {
56638
- log45.debug(`[mcp:tool-sync] No MCP tools to sync to FTS5`);
56867
+ log46.debug(`[mcp:tool-sync] No MCP tools to sync to FTS5`);
56639
56868
  return;
56640
56869
  }
56641
56870
  const insert = db.prepare(`
@@ -56645,18 +56874,18 @@ async function syncMCPToolsToFTS() {
56645
56874
  for (const tool of mcpTools) {
56646
56875
  insert.run(tool.id, tool.server_name, tool.tool_name, tool.description, tool.category);
56647
56876
  }
56648
- log45.info(`[mcp:tool-sync] Synced ${mcpTools.length} MCP tools to mcp_tools_fts`);
56877
+ log46.info(`[mcp:tool-sync] Synced ${mcpTools.length} MCP tools to mcp_tools_fts`);
56649
56878
  });
56650
56879
  syncTransaction();
56651
56880
  } catch (err) {
56652
- log45.error(`[mcp:tool-sync] Failed to sync MCP tools to FTS5:`, err);
56881
+ log46.error(`[mcp:tool-sync] Failed to sync MCP tools to FTS5:`, err);
56653
56882
  }
56654
56883
  }
56655
- var log45;
56884
+ var log46;
56656
56885
  var init_tool_sync = __esm(() => {
56657
56886
  init_sqlite();
56658
56887
  init_logger();
56659
- log45 = logger.child("mcp:tool-sync");
56888
+ log46 = logger.child("mcp:tool-sync");
56660
56889
  });
56661
56890
 
56662
56891
  // packages/core/src/utils/date.ts
@@ -56703,7 +56932,7 @@ async function compileContext(opts) {
56703
56932
  const effectiveMcpManager = mcpManager ?? (() => {
56704
56933
  const singletonMcp = getMCPManager();
56705
56934
  if (singletonMcp) {
56706
- log46.info(`[context-compiler] Using MCP Manager from singleton`);
56935
+ log47.info(`[context-compiler] Using MCP Manager from singleton`);
56707
56936
  return singletonMcp;
56708
56937
  }
56709
56938
  return null;
@@ -56713,19 +56942,19 @@ async function compileContext(opts) {
56713
56942
  channel: opts.channel,
56714
56943
  channelUserId: threadId
56715
56944
  }) || threadId || "";
56716
- log46.info(`[context-compiler] [STEP-1] Loading agent config for id=${agentId}`);
56945
+ log47.info(`[context-compiler] [STEP-1] Loading agent config for id=${agentId}`);
56717
56946
  let agent;
56718
56947
  try {
56719
56948
  agent = db.query("SELECT * FROM agents WHERE id = ?").get(agentId);
56720
56949
  } catch (err) {
56721
- log46.error(`[context-compiler] [STEP-1] \u274C FAILED loading agent: ${JSON.stringify(err)}`);
56950
+ log47.error(`[context-compiler] [STEP-1] \u274C FAILED loading agent: ${JSON.stringify(err)}`);
56722
56951
  throw err;
56723
56952
  }
56724
56953
  if (!agent) {
56725
56954
  throw new Error(`Agent not found: ${agentId}`);
56726
56955
  }
56727
56956
  const isWorker = agent.role === "worker" || !!isolated;
56728
- log46.info(`[context-compiler] [STEP-1] \u2705 Compiling for ${isWorker ? "worker" : "coordinator"} agent=${agent.name}`);
56957
+ log47.info(`[context-compiler] [STEP-1] \u2705 Compiling for ${isWorker ? "worker" : "coordinator"} agent=${agent.name}`);
56729
56958
  let modelContextWindow = DEFAULT_CONTEXT_WINDOW;
56730
56959
  if (agent.model_id) {
56731
56960
  try {
@@ -56734,16 +56963,16 @@ async function compileContext(opts) {
56734
56963
  modelContextWindow = mRow.context_window;
56735
56964
  } catch {}
56736
56965
  }
56737
- log46.info(`[context-compiler] [STEP-2] Loading scratchpad...`);
56966
+ log47.info(`[context-compiler] [STEP-2] Loading scratchpad...`);
56738
56967
  let scratchpadNotes = [];
56739
56968
  try {
56740
56969
  scratchpadNotes = getScratchpad(threadId);
56741
- log46.info(`[context-compiler] [STEP-2] \u2705 Loaded ${scratchpadNotes.length} scratchpad notes`);
56970
+ log47.info(`[context-compiler] [STEP-2] \u2705 Loaded ${scratchpadNotes.length} scratchpad notes`);
56742
56971
  } catch (err) {
56743
- log46.error(`[context-compiler] [STEP-2] \u274C FAILED loading scratchpad: ${JSON.stringify(err)}`);
56972
+ log47.error(`[context-compiler] [STEP-2] \u274C FAILED loading scratchpad: ${JSON.stringify(err)}`);
56744
56973
  throw err;
56745
56974
  }
56746
- log46.info(`[context-compiler] [STEP-3c] Loading MCP tools...`);
56975
+ log47.info(`[context-compiler] [STEP-3c] Loading MCP tools...`);
56747
56976
  const mcpToolExecutors = [];
56748
56977
  if (effectiveMcpManager) {
56749
56978
  try {
@@ -56754,9 +56983,13 @@ async function compileContext(opts) {
56754
56983
  serverTools = effectiveMcpManager.getServerTools(server.name);
56755
56984
  }
56756
56985
  if (serverTools && serverTools.length > 0) {
56757
- log46.info(`[context-compiler] [STEP-3c] Server ${server.name}: ${serverTools.length} tools`);
56986
+ log47.info(`[context-compiler] [STEP-3c] Server ${server.name}: ${serverTools.length} tools`);
56758
56987
  for (const mcpTool of serverTools) {
56759
56988
  const fullName = mcpToolFullName(server.name, mcpTool.name);
56989
+ if (!fullName || !/^[a-zA-Z0-9_-]{1,64}$/.test(fullName)) {
56990
+ log47.warn(`[context-compiler] Skipping MCP tool with unsupported name: "${mcpTool.name}" (server: ${server.name}, sanitized: "${fullName}")`);
56991
+ continue;
56992
+ }
56760
56993
  mcpToolExecutors.push({
56761
56994
  name: fullName,
56762
56995
  description: mcpTool.description || `Tool from ${server.name}`,
@@ -56767,10 +57000,10 @@ async function compileContext(opts) {
56767
57000
  });
56768
57001
  }
56769
57002
  } else {
56770
- log46.warn(`[context-compiler] [STEP-3c] Server ${server.name} has no tools (not connected yet)`);
57003
+ log47.warn(`[context-compiler] [STEP-3c] Server ${server.name} has no tools (not connected yet)`);
56771
57004
  }
56772
57005
  }
56773
- log46.info(`[context-compiler] [STEP-3c] \u2705 Loaded ${mcpToolExecutors.length} MCP tools`);
57006
+ log47.info(`[context-compiler] [STEP-3c] \u2705 Loaded ${mcpToolExecutors.length} MCP tools`);
56774
57007
  if (mcpToolExecutors.length > 0) {
56775
57008
  try {
56776
57009
  for (const server of dbServers) {
@@ -56783,18 +57016,18 @@ async function compileContext(opts) {
56783
57016
  }
56784
57017
  }
56785
57018
  await syncMCPToolsToFTS();
56786
- log46.info(`[context-compiler] [STEP-3c] \u2705 Persisted MCP tools to DB + FTS5`);
57019
+ log47.info(`[context-compiler] [STEP-3c] \u2705 Persisted MCP tools to DB + FTS5`);
56787
57020
  } catch (syncErr) {
56788
- log46.warn(`[context-compiler] [STEP-3c] \u26A0\uFE0F Failed to persist MCP tools to DB: ${syncErr.message}`);
57021
+ log47.warn(`[context-compiler] [STEP-3c] \u26A0\uFE0F Failed to persist MCP tools to DB: ${syncErr.message}`);
56789
57022
  }
56790
57023
  }
56791
57024
  } catch (err) {
56792
- log46.error(`[context-compiler] [STEP-3c] \u274C Failed: ${err.message}`);
57025
+ log47.error(`[context-compiler] [STEP-3c] \u274C Failed: ${err.message}`);
56793
57026
  }
56794
57027
  } else {
56795
- log46.info(`[context-compiler] [STEP-3c] \u26A0\uFE0F No MCP manager, skipping MCP tools`);
57028
+ log47.info(`[context-compiler] [STEP-3c] \u26A0\uFE0F No MCP manager, skipping MCP tools`);
56796
57029
  }
56797
- log46.info(`[context-compiler] [STEP-4] Building minimal tool set`);
57030
+ log47.info(`[context-compiler] [STEP-4] Building minimal tool set`);
56798
57031
  const config2 = { tools: {} };
56799
57032
  const allNativeTools = createAllTools(config2);
56800
57033
  const nativeTools = allNativeTools.map((t) => ({
@@ -56814,24 +57047,24 @@ async function compileContext(opts) {
56814
57047
  }
56815
57048
  }));
56816
57049
  const toolsForLLM = nativeToolsForLLM;
56817
- log46.info(`[context-compiler] [STEP-4] Minimal native tool set: ${filteredNativeTools.length} tools`);
56818
- log46.info(`[context-compiler] [STEP-4b] MCP tools available via search_knowledge: ${mcpToolExecutors.length} (not injected)`);
56819
- log46.info(`[context-compiler] [STEP-8] \u2705 Combined tools: ${allTools.length} total executors, ${toolsForLLM.length} in LLM context`);
56820
- log46.info(`[context-compiler] [STEP-8b] Building skill loadout...`);
57050
+ log47.info(`[context-compiler] [STEP-4] Minimal native tool set: ${filteredNativeTools.length} tools`);
57051
+ log47.info(`[context-compiler] [STEP-4b] MCP tools available via search_knowledge: ${mcpToolExecutors.length} (not injected)`);
57052
+ log47.info(`[context-compiler] [STEP-8] \u2705 Combined tools: ${allTools.length} total executors, ${toolsForLLM.length} in LLM context`);
57053
+ log47.info(`[context-compiler] [STEP-8b] Building skill loadout...`);
56821
57054
  let minimalSkills = [];
56822
57055
  let discoveredSkills = [];
56823
57056
  try {
56824
57057
  minimalSkills = getMinimalSkills();
56825
- log46.info(`[context-compiler] [STEP-8b] \u2705 Loaded ${minimalSkills.length} minimal skills`);
57058
+ log47.info(`[context-compiler] [STEP-8b] \u2705 Loaded ${minimalSkills.length} minimal skills`);
56826
57059
  if (!isWorker) {
56827
57060
  const inputForSkills = taskContext || userMessage;
56828
57061
  const textMessage = typeof inputForSkills === "string" ? inputForSkills : Array.isArray(inputForSkills) ? inputForSkills.filter((p2) => p2.type === "text").map((p2) => p2.text).join(`
56829
57062
  `) : String(inputForSkills);
56830
57063
  discoveredSkills = selectSkills(textMessage);
56831
- log46.info(`[context-compiler] [STEP-8b] \u2705 Discovered ${discoveredSkills.length} additional skills via FTS5`);
57064
+ log47.info(`[context-compiler] [STEP-8b] \u2705 Discovered ${discoveredSkills.length} additional skills via FTS5`);
56832
57065
  }
56833
57066
  } catch (err) {
56834
- log46.warn(`[context-compiler] [STEP-8b] \u26A0\uFE0F Skill loadout failed: ${err.message}`);
57067
+ log47.warn(`[context-compiler] [STEP-8b] \u26A0\uFE0F Skill loadout failed: ${err.message}`);
56835
57068
  }
56836
57069
  const skillMap = new Map;
56837
57070
  for (const skill of minimalSkills) {
@@ -56843,20 +57076,20 @@ async function compileContext(opts) {
56843
57076
  }
56844
57077
  }
56845
57078
  const allSkills = Array.from(skillMap.values());
56846
- log46.info(`[context-compiler] [STEP-9] Loading conversation history...`);
57079
+ log47.info(`[context-compiler] [STEP-9] Loading conversation history...`);
56847
57080
  let recentMessages = [];
56848
57081
  try {
56849
57082
  recentMessages = getRecentMessages(threadId, KEEP_LAST_N_MESSAGES2);
56850
- log46.info(`[context-compiler] [STEP-9] \u2705 Loaded ${recentMessages.length} recent messages`);
57083
+ log47.info(`[context-compiler] [STEP-9] \u2705 Loaded ${recentMessages.length} recent messages`);
56851
57084
  } catch (err) {
56852
- log46.error(`[context-compiler] [STEP-9] \u274C FAILED loading history: ${JSON.stringify(err)}`);
57085
+ log47.error(`[context-compiler] [STEP-9] \u274C FAILED loading history: ${JSON.stringify(err)}`);
56853
57086
  throw err;
56854
57087
  }
56855
57088
  let summary = null;
56856
57089
  try {
56857
57090
  summary = getSummary(threadId);
56858
57091
  } catch (err) {
56859
- log46.error(`[context-compiler] [STEP-9b] \u274C FAILED loading summary: ${JSON.stringify(err)}`);
57092
+ log47.error(`[context-compiler] [STEP-9b] \u274C FAILED loading summary: ${JSON.stringify(err)}`);
56860
57093
  throw err;
56861
57094
  }
56862
57095
  const totalTokens = recentMessages.reduce((sum, m2) => sum + estimateTokens(m2.content), 0);
@@ -56867,17 +57100,17 @@ async function compileContext(opts) {
56867
57100
  { role: "system", content: `[Conversation Summary]: ${summary.summary}` },
56868
57101
  ...toAPIMessages(recentMessages)
56869
57102
  ];
56870
- log46.info(`[context-compiler] [STEP-9c] Using summary (${summary.messages_covered} messages compressed)`);
57103
+ log47.info(`[context-compiler] [STEP-9c] Using summary (${summary.messages_covered} messages compressed)`);
56871
57104
  } else {
56872
57105
  messages = toAPIMessages(recentMessages);
56873
57106
  }
56874
- log46.info(`[context-compiler] [STEP-10] Building system prompt...`);
57107
+ log47.info(`[context-compiler] [STEP-10] Building system prompt...`);
56875
57108
  let systemPrompt;
56876
57109
  try {
56877
57110
  systemPrompt = await buildSystemPromptWithProjects({ agentId, userId });
56878
- log46.info(`[context-compiler] [STEP-10] \u2705 System prompt built (${systemPrompt.length} chars)`);
57111
+ log47.info(`[context-compiler] [STEP-10] \u2705 System prompt built (${systemPrompt.length} chars)`);
56879
57112
  } catch (err) {
56880
- log46.error(`[context-compiler] [STEP-10] \u274C FAILED building system prompt: ${JSON.stringify(err)}`);
57113
+ log47.error(`[context-compiler] [STEP-10] \u274C FAILED building system prompt: ${JSON.stringify(err)}`);
56881
57114
  throw err;
56882
57115
  }
56883
57116
  const userRow = db.query("SELECT timezone FROM users WHERE id = ?").get(userId);
@@ -56894,7 +57127,7 @@ async function compileContext(opts) {
56894
57127
  **Hora**: ${hora}
56895
57128
  **Zona horaria**: ${userTimezone}${workspaceLine}
56896
57129
  `;
56897
- log46.info(`[context-compiler] [STEP-10b] \u2705 Injected current date/time: ${fecha} ${hora} (${userTimezone})`);
57130
+ log47.info(`[context-compiler] [STEP-10b] \u2705 Injected current date/time: ${fecha} ${hora} (${userTimezone})`);
56898
57131
  if (scratchpadNotes.length > 0) {
56899
57132
  const scratchpadData = {};
56900
57133
  for (const n of scratchpadNotes) {
@@ -56947,7 +57180,7 @@ ${skill.body}
56947
57180
  }
56948
57181
  systemPrompt += discoveredSection;
56949
57182
  }
56950
- log46.info(`[context-compiler] [STEP-10d] Injected ${minimalWithBody.length} minimal skill bodies + ${discoveredOnly.length} discovered skills`);
57183
+ log47.info(`[context-compiler] [STEP-10d] Injected ${minimalWithBody.length} minimal skill bodies + ${discoveredOnly.length} discovered skills`);
56951
57184
  }
56952
57185
  }
56953
57186
  if (isWorker && opts.taskContext) {
@@ -56970,14 +57203,14 @@ Focus ONLY on this task. Do not deviate.`;
56970
57203
  systemPrompt = systemPrompt.substring(0, maxSystemPromptChars) + `
56971
57204
 
56972
57205
  [... System prompt truncated (${originalLen} chars \u2192 ${maxSystemPromptChars} chars) ...]`;
56973
- log46.info(`[context-compiler] System prompt truncated: ${originalLen} \u2192 ${maxSystemPromptChars} chars`);
57206
+ log47.info(`[context-compiler] System prompt truncated: ${originalLen} \u2192 ${maxSystemPromptChars} chars`);
56974
57207
  }
56975
57208
  const estimatedSystemTokens = estimateTokens(systemPrompt);
56976
57209
  const estimatedMsgTokens = messages.reduce((sum, m2) => sum + estimateTokens(typeof m2.content === "string" ? m2.content : JSON.stringify(m2.content)), 0);
56977
57210
  const estimatedToolTokens = toolsForLLM.reduce((sum, t) => sum + estimateTokens(JSON.stringify(t)), 0);
56978
57211
  const estimatedTotal = estimatedSystemTokens + estimatedMsgTokens + estimatedToolTokens;
56979
57212
  const budgetPct = modelContextWindow > 0 ? Math.round(estimatedTotal / modelContextWindow * 100) : 0;
56980
- log46.info(`[context-compiler] \u2705 DONE: ${allTools.length} total tools, ` + `${toolsForLLM.length} selected tools, ${messages.length} messages, ` + `${allSkills.length} skills, isolated=${isWorker}, ` + `est.tokens: sys=${estimatedSystemTokens} msgs=${estimatedMsgTokens} tools=${estimatedToolTokens} ` + `total=${estimatedTotal}/${modelContextWindow} (${budgetPct}%)`);
57213
+ log47.info(`[context-compiler] \u2705 DONE: ${allTools.length} total tools, ` + `${toolsForLLM.length} selected tools, ${messages.length} messages, ` + `${allSkills.length} skills, isolated=${isWorker}, ` + `est.tokens: sys=${estimatedSystemTokens} msgs=${estimatedMsgTokens} tools=${estimatedToolTokens} ` + `total=${estimatedTotal}/${modelContextWindow} (${budgetPct}%)`);
56981
57214
  return {
56982
57215
  systemPrompt,
56983
57216
  messages,
@@ -56986,7 +57219,7 @@ Focus ONLY on this task. Do not deviate.`;
56986
57219
  skills: allSkills
56987
57220
  };
56988
57221
  }
56989
- var log46, KEEP_LAST_N_MESSAGES2 = 30, DEFAULT_CONTEXT_WINDOW = 250000, COMPACT_RATIO = 0.8, MAX_SYSTEM_PROMPT_CHARS_CAP = 128000, MINIMAL_TOOLS, MINIMAL_SKILL_NAMES2;
57222
+ var log47, KEEP_LAST_N_MESSAGES2 = 30, DEFAULT_CONTEXT_WINDOW = 250000, COMPACT_RATIO = 0.8, MAX_SYSTEM_PROMPT_CHARS_CAP = 128000, MINIMAL_TOOLS, MINIMAL_SKILL_NAMES2;
56990
57223
  var init_context_compiler = __esm(() => {
56991
57224
  init_sqlite();
56992
57225
  init_logger();
@@ -56999,7 +57232,7 @@ var init_context_compiler = __esm(() => {
56999
57232
  init_tools();
57000
57233
  init_onboarding();
57001
57234
  init_tool_sync();
57002
- log46 = logger.child("context-compiler");
57235
+ log47 = logger.child("context-compiler");
57003
57236
  MINIMAL_TOOLS = new Set([
57004
57237
  "save_note",
57005
57238
  "notify",
@@ -57402,6 +57635,157 @@ var init_tool_runtime = __esm(() => {
57402
57635
  ]);
57403
57636
  });
57404
57637
 
57638
+ // packages/core/src/utils/crypto.ts
57639
+ import * as crypto2 from "crypto";
57640
+ function hashString(input) {
57641
+ return crypto2.createHash("sha256").update(input).digest("hex");
57642
+ }
57643
+ function hashObject(obj2) {
57644
+ return hashString(JSON.stringify(obj2));
57645
+ }
57646
+ var init_crypto2 = () => {};
57647
+
57648
+ // packages/core/src/agent/stuck-loop.ts
57649
+ class StuckLoopDetector {
57650
+ log = logger.child("stuck-loop");
57651
+ history = new Map;
57652
+ progressHistory = new Map;
57653
+ maxHistoryPerSession = 50;
57654
+ triggerThreshold = 3;
57655
+ progressThreshold = 3;
57656
+ constructor(_config) {}
57657
+ recordToolCall(sessionId, toolName, args, error4) {
57658
+ let sessionHistory = this.history.get(sessionId);
57659
+ if (!sessionHistory) {
57660
+ sessionHistory = [];
57661
+ this.history.set(sessionId, sessionHistory);
57662
+ }
57663
+ const record2 = {
57664
+ toolName,
57665
+ argsHash: hashObject(args),
57666
+ errorMessage: error4,
57667
+ timestamp: Date.now()
57668
+ };
57669
+ sessionHistory.push(record2);
57670
+ if (sessionHistory.length > this.maxHistoryPerSession) {
57671
+ sessionHistory.shift();
57672
+ }
57673
+ this.log.debug(`Recorded tool call: ${toolName} for session ${sessionId}`);
57674
+ }
57675
+ check(sessionId) {
57676
+ const sessionHistory = this.history.get(sessionId) ?? [];
57677
+ if (sessionHistory.length < this.triggerThreshold) {
57678
+ return { detected: false, toolName: "", count: 0, kind: "loop" };
57679
+ }
57680
+ const recent = sessionHistory.slice(-10);
57681
+ const counts = new Map;
57682
+ for (const record2 of recent) {
57683
+ const key = `${record2.toolName}:${record2.argsHash}`;
57684
+ const existing = counts.get(key);
57685
+ if (existing) {
57686
+ existing.count++;
57687
+ if (record2.errorMessage) {
57688
+ existing.error = record2.errorMessage;
57689
+ }
57690
+ } else {
57691
+ counts.set(key, { count: 1, error: record2.errorMessage });
57692
+ }
57693
+ }
57694
+ for (const [key, data] of counts) {
57695
+ if (data.count >= this.triggerThreshold && data.error) {
57696
+ const toolName = key.split(":")[0] ?? "unknown";
57697
+ this.log.warn(`Stuck loop detected: ${toolName} called ${data.count} times with same args and error`);
57698
+ return {
57699
+ detected: true,
57700
+ toolName,
57701
+ count: data.count,
57702
+ lastError: data.error,
57703
+ kind: "loop"
57704
+ };
57705
+ }
57706
+ }
57707
+ return { detected: false, toolName: "", count: 0, kind: "loop" };
57708
+ }
57709
+ recordProgress(sessionId, progressHash) {
57710
+ let sessionProgress = this.progressHistory.get(sessionId);
57711
+ if (!sessionProgress) {
57712
+ sessionProgress = [];
57713
+ this.progressHistory.set(sessionId, sessionProgress);
57714
+ }
57715
+ sessionProgress.push({ hash: progressHash, timestamp: Date.now() });
57716
+ if (sessionProgress.length > this.maxHistoryPerSession) {
57717
+ sessionProgress.shift();
57718
+ }
57719
+ this.log.debug(`Recorded progress hash for session ${sessionId}: ${progressHash}`);
57720
+ }
57721
+ checkProgress(sessionId, threshold) {
57722
+ const sessionProgress = this.progressHistory.get(sessionId) ?? [];
57723
+ const required2 = threshold ?? this.progressThreshold;
57724
+ if (sessionProgress.length < required2) {
57725
+ return { detected: false, toolName: "", count: 0, kind: "stall" };
57726
+ }
57727
+ const recent = sessionProgress.slice(-required2);
57728
+ const firstHash = recent[0]?.hash;
57729
+ const allSame = recent.every((r) => r.hash === firstHash);
57730
+ if (allSame && firstHash) {
57731
+ this.log.warn(`Stall detected: no progress for ${required2} checks (hash ${firstHash})`);
57732
+ return {
57733
+ detected: true,
57734
+ toolName: "NO_PROGRESS",
57735
+ count: required2,
57736
+ kind: "stall"
57737
+ };
57738
+ }
57739
+ return { detected: false, toolName: "", count: 0, kind: "stall" };
57740
+ }
57741
+ clear(sessionId) {
57742
+ this.history.delete(sessionId);
57743
+ this.progressHistory.delete(sessionId);
57744
+ this.log.debug(`Cleared stuck loop history for session ${sessionId}`);
57745
+ }
57746
+ prune(maxAgeMs = 30 * 60 * 1000) {
57747
+ const now = Date.now();
57748
+ let pruned = 0;
57749
+ for (const [sessionId, history] of this.history) {
57750
+ const filtered = history.filter((r) => now - r.timestamp < maxAgeMs);
57751
+ if (filtered.length === 0) {
57752
+ this.history.delete(sessionId);
57753
+ pruned++;
57754
+ } else if (filtered.length !== history.length) {
57755
+ this.history.set(sessionId, filtered);
57756
+ }
57757
+ }
57758
+ for (const [sessionId, history] of this.progressHistory) {
57759
+ const filtered = history.filter((r) => now - r.timestamp < maxAgeMs);
57760
+ if (filtered.length === 0) {
57761
+ this.progressHistory.delete(sessionId);
57762
+ pruned++;
57763
+ } else if (filtered.length !== history.length) {
57764
+ this.progressHistory.set(sessionId, filtered);
57765
+ }
57766
+ }
57767
+ return pruned;
57768
+ }
57769
+ }
57770
+ function createStuckLoopDetector(config2) {
57771
+ return new StuckLoopDetector(config2);
57772
+ }
57773
+ function getInterventionMessage(state) {
57774
+ if (!state.detected)
57775
+ return "";
57776
+ if (state.kind === "stall") {
57777
+ return `WARNING: Has estado sin avanzar durante ${state.count} ciclos consecutivos. Revisa tu plan, intenta una herramienta diferente o pide aclaraci\xF3n al usuario en lugar de repetir la misma secuencia.`;
57778
+ }
57779
+ if (state.count >= 4) {
57780
+ return `CRITICAL: Has llamado ${state.toolName} ${state.count} veces con los mismos argumentos y sigue fallando con: "${state.lastError}". El usuario ser\xE1 notificado. Debes cambiar completamente de estrategia o pedir ayuda.`;
57781
+ }
57782
+ return `WARNING: Has llamado ${state.toolName} ${state.count} veces con los mismos argumentos y sigue fallando. Debes probar un enfoque diferente en lugar de repetir la misma acci\xF3n.`;
57783
+ }
57784
+ var init_stuck_loop = __esm(() => {
57785
+ init_logger();
57786
+ init_crypto2();
57787
+ });
57788
+
57405
57789
  // packages/core/src/agent/agent-loop.ts
57406
57790
  var exports_agent_loop = {};
57407
57791
  __export(exports_agent_loop, {
@@ -57420,9 +57804,13 @@ async function* runAgent(opts) {
57420
57804
  throw new Error(`Agent not found: ${opts.agentId}`);
57421
57805
  const agentName = agent.name || opts.agentId;
57422
57806
  const maxIterations = agent.max_iterations || 10;
57807
+ const maxWallClockMs = agent.max_wall_clock_ms || DEFAULT_MAX_WALL_CLOCK_MS;
57808
+ const wallClockDeadline = Date.now() + maxWallClockMs;
57809
+ const stuckDetector = createStuckLoopDetector(loadConfig());
57810
+ let stuckState;
57423
57811
  const providerCfg = await resolveProviderConfig(agent.provider_id || "openai", agent.model_id || "gpt-4o-mini");
57424
57812
  const cleanModel = providerCfg.model.replace(new RegExp(`^${providerCfg.provider}\\/`), "");
57425
- log47.info(`[agent-loop] Starting: agent=${agentName} thread=${opts.threadId} provider=${providerCfg.provider}/${cleanModel}`);
57813
+ log48.info(`[agent-loop] Starting: agent=${agentName} thread=${opts.threadId} provider=${providerCfg.provider}/${cleanModel}`);
57426
57814
  emitCanvas("canvas:node_update", {
57427
57815
  nodeId: opts.agentId,
57428
57816
  changes: { status: "thinking" }
@@ -57441,6 +57829,17 @@ async function* runAgent(opts) {
57441
57829
  taskContext: opts.taskContext,
57442
57830
  userId: opts.userId
57443
57831
  });
57832
+ if (opts.extraTools?.length) {
57833
+ const existingNames = new Set(ctx.tools.map((t) => t.function?.name));
57834
+ for (const tool of opts.extraTools) {
57835
+ const name = tool.function?.name || tool.name;
57836
+ if (name && !existingNames.has(name)) {
57837
+ ctx.tools.push(tool);
57838
+ existingNames.add(name);
57839
+ log48.info(`[agent-loop] Force-injected tool into loadout: ${name}`);
57840
+ }
57841
+ }
57842
+ }
57444
57843
  const systemPrompt = opts.systemPromptOverride || ctx.systemPrompt;
57445
57844
  let messages = [
57446
57845
  { role: "system", content: systemPrompt },
@@ -57456,17 +57855,29 @@ async function* runAgent(opts) {
57456
57855
  let lastToolSignature = "";
57457
57856
  let consecutiveRepeat = 0;
57458
57857
  let loopDetected = false;
57858
+ let idleIterations = 0;
57859
+ const PROGRESS_TOOLS = new Set(["browser_type", "browser_click", "browser_navigate"]);
57459
57860
  while (iterations < maxIterations) {
57460
57861
  if (opts.signal?.aborted) {
57461
- log47.info(`[agent-loop] Aborted by signal at iteration ${iterations}`);
57862
+ log48.info(`[agent-loop] Aborted by signal at iteration ${iterations}`);
57462
57863
  finalContent = "Generaci\xF3n detenida.";
57463
57864
  break;
57464
57865
  }
57866
+ if (Date.now() > wallClockDeadline) {
57867
+ log48.warn(`[agent-loop] Wall-clock timeout exceeded (${maxWallClockMs}ms). Breaking.`);
57868
+ finalContent = "La tarea tom\xF3 demasiado tiempo. Te sugiero dividirla en pasos m\xE1s peque\xF1os o darme m\xE1s detalles para continuar.";
57869
+ break;
57870
+ }
57465
57871
  iterations++;
57872
+ let streamedThisCall = false;
57466
57873
  const response = await callLLM({
57467
57874
  ...providerCfg,
57468
57875
  messages: clearOldToolResults(messages),
57469
- tools: ctx.tools.length > 0 ? ctx.tools : undefined
57876
+ tools: ctx.tools.length > 0 ? ctx.tools : undefined,
57877
+ onToken: opts.onToken ? (token) => {
57878
+ streamedThisCall = true;
57879
+ opts.onToken?.(token);
57880
+ } : undefined
57470
57881
  });
57471
57882
  if (response.usage) {
57472
57883
  totalInputTokens += response.usage.input_tokens;
@@ -57475,7 +57886,7 @@ async function* runAgent(opts) {
57475
57886
  const agentMsg = { content: response.content };
57476
57887
  if (response.tool_calls?.length)
57477
57888
  agentMsg.tool_calls = response.tool_calls;
57478
- yield { agent: { messages: [agentMsg] } };
57889
+ yield { agent: { messages: [agentMsg], streamed: streamedThisCall } };
57479
57890
  if (opts.onStep && response.content) {
57480
57891
  await opts.onStep({ type: "text", message: response.content });
57481
57892
  }
@@ -57529,9 +57940,9 @@ async function* runAgent(opts) {
57529
57940
  const toolResultJS = batchResult.result;
57530
57941
  const toolMs = batchResult.durationMs;
57531
57942
  const toolResultLLM = formatToolResult(toolResultJS, cleanModel);
57532
- log47.info(`[agent-loop] Tool ${toolName} completed in ${toolMs}ms`);
57943
+ log48.info(`[agent-loop] Tool ${toolName} completed in ${toolMs}ms`);
57533
57944
  const resultPreview = toolResultLLM.length > 500 ? toolResultLLM.substring(0, 500) + `\u2026 (+${toolResultLLM.length - 500} chars)` : toolResultLLM;
57534
- log47.info(`[agent-loop] Tool result [${toolName}]: ${resultPreview}`);
57945
+ log48.info(`[agent-loop] Tool result [${toolName}]: ${resultPreview}`);
57535
57946
  const textMessage = typeof opts.userMessage === "string" ? opts.userMessage : Array.isArray(opts.userMessage) ? opts.userMessage.filter((p2) => p2.type === "text").map((p2) => p2.text).join(`
57536
57947
  `) : String(opts.userMessage);
57537
57948
  const cleanMessage = textMessage.replace(/^\[Timestamp:.*?\]\n/, "");
@@ -57555,6 +57966,8 @@ async function* runAgent(opts) {
57555
57966
  content: toolResultLLM,
57556
57967
  tool_call_id: tc.id
57557
57968
  });
57969
+ const errorMessage = toolResultLLM.startsWith("[Tool Error]") ? toolResultLLM : undefined;
57970
+ stuckDetector.recordToolCall(opts.threadId, toolName, tc.function.arguments, errorMessage);
57558
57971
  if (toolName === "search_knowledge") {
57559
57972
  try {
57560
57973
  const result = toolResultJS;
@@ -57569,7 +57982,7 @@ async function* runAgent(opts) {
57569
57982
  const altName = found.name.includes(".") ? found.name.replace(/\./g, "_") : found.name.replace(/_/g, ".");
57570
57983
  nativeTool = ctx.allTools.find((t) => t.name === altName);
57571
57984
  if (nativeTool) {
57572
- log47.info(`[agent-loop] Resolved legacy tool name "${found.name}" \u2192 "${nativeTool.name}"`);
57985
+ log48.info(`[agent-loop] Resolved legacy tool name "${found.name}" \u2192 "${nativeTool.name}"`);
57573
57986
  }
57574
57987
  }
57575
57988
  if (nativeTool) {
@@ -57581,17 +57994,17 @@ async function* runAgent(opts) {
57581
57994
  parameters: nativeTool.parameters ?? { type: "object", properties: {} }
57582
57995
  }
57583
57996
  });
57584
- log47.info(`[agent-loop] Injected discovered native tool into loadout: ${nativeTool.name}`);
57997
+ log48.info(`[agent-loop] Injected discovered native tool into loadout: ${nativeTool.name}`);
57585
57998
  currentToolNames.add(found.name);
57586
57999
  injectedTools.push(nativeTool.name);
57587
58000
  } else {
57588
- log47.warn(`[agent-loop] search_knowledge returned tool "${found.name}" but no matching executor found in allTools`);
58001
+ log48.warn(`[agent-loop] search_knowledge returned tool "${found.name}" but no matching executor found in allTools`);
57589
58002
  }
57590
58003
  }
57591
58004
  }
57592
58005
  for (const found of foundMcpTools) {
57593
58006
  const mcpFullName = found.full_name || found.id;
57594
- log47.debug(`[agent-loop] MCP discovery candidate: tool_name="${found.tool_name}", full_name="${found.full_name}", id="${found.id}", resolved="${mcpFullName}"`);
58007
+ log48.debug(`[agent-loop] MCP discovery candidate: tool_name="${found.tool_name}", full_name="${found.full_name}", id="${found.id}", resolved="${mcpFullName}"`);
57595
58008
  if (!currentToolNames.has(mcpFullName)) {
57596
58009
  const mcpTool = ctx.allTools.find((t) => t.name === mcpFullName);
57597
58010
  if (mcpTool) {
@@ -57603,10 +58016,10 @@ async function* runAgent(opts) {
57603
58016
  parameters: mcpTool.parameters ?? { type: "object", properties: {} }
57604
58017
  }
57605
58018
  });
57606
- log47.info(`[agent-loop] Injected discovered MCP tool into loadout: ${mcpTool.name}`);
58019
+ log48.info(`[agent-loop] Injected discovered MCP tool into loadout: ${mcpTool.name}`);
57607
58020
  currentToolNames.add(mcpFullName);
57608
58021
  } else {
57609
- log47.warn(`[agent-loop] MCP tool "${mcpFullName}" not found in allTools (available MCP: ${ctx.allTools.filter((t) => t.name.includes("__")).map((t) => t.name).join(", ")})`);
58022
+ log48.warn(`[agent-loop] MCP tool "${mcpFullName}" not found in allTools (available MCP: ${ctx.allTools.filter((t) => t.name.includes("__")).map((t) => t.name).join(", ")})`);
57610
58023
  }
57611
58024
  }
57612
58025
  }
@@ -57644,16 +58057,16 @@ ${s2.body}`).join(`
57644
58057
 
57645
58058
  --- SKILL INSTRUCTIONS (Auto-loaded) ---
57646
58059
  ${newSkillSection}`;
57647
- log47.info(`[agent-loop] Injected ${newSkills.length} skill(s) for tools: ${newSkills.map((s2) => s2.name).join(", ")}`);
58060
+ log48.info(`[agent-loop] Injected ${newSkills.length} skill(s) for tools: ${newSkills.map((s2) => s2.name).join(", ")}`);
57648
58061
  }
57649
58062
  }
57650
58063
  }
57651
58064
  } catch (skillErr) {
57652
- log47.warn(`[agent-loop] Failed to inject skills for tools: ${skillErr.message}`);
58065
+ log48.warn(`[agent-loop] Failed to inject skills for tools: ${skillErr.message}`);
57653
58066
  }
57654
58067
  }
57655
58068
  } catch (err) {
57656
- log47.warn(`[agent-loop] search_knowledge tool injection failed: ${err.message}`);
58069
+ log48.warn(`[agent-loop] search_knowledge tool injection failed: ${err.message}`);
57657
58070
  }
57658
58071
  try {
57659
58072
  const result = toolResultJS;
@@ -57683,19 +58096,19 @@ ${section}`);
57683
58096
  const lastMsg = messages[messages.length - 1];
57684
58097
  if (lastMsg?.role === "tool") {
57685
58098
  lastMsg.content += extras.join("");
57686
- log47.info(`[agent-loop] Enriched search_knowledge result with ${foundSkills.length} skill(s) and ${foundPlaybook.length} rule(s)`);
58099
+ log48.info(`[agent-loop] Enriched search_knowledge result with ${foundSkills.length} skill(s) and ${foundPlaybook.length} rule(s)`);
57687
58100
  }
57688
58101
  }
57689
58102
  }
57690
58103
  } catch (err) {
57691
- log47.warn(`[agent-loop] search_knowledge enrichment failed: ${err.message}`);
58104
+ log48.warn(`[agent-loop] search_knowledge enrichment failed: ${err.message}`);
57692
58105
  }
57693
58106
  }
57694
58107
  const sig = `${toolName}:${JSON.stringify(tc.function.arguments)}`;
57695
58108
  if (sig === lastToolSignature) {
57696
58109
  consecutiveRepeat++;
57697
58110
  if (consecutiveRepeat >= 2) {
57698
- log47.warn(`[agent-loop] Loop detected: "${toolName}" x${consecutiveRepeat + 1} with same args. Breaking.`);
58111
+ log48.warn(`[agent-loop] Loop detected: "${toolName}" x${consecutiveRepeat + 1} with same args. Breaking.`);
57699
58112
  finalContent = "No pude completar la tarea porque no encontr\xE9 las herramientas necesarias para ello.";
57700
58113
  loopDetected = true;
57701
58114
  }
@@ -57706,13 +58119,52 @@ ${section}`);
57706
58119
  }
57707
58120
  if (loopDetected)
57708
58121
  break;
58122
+ stuckState = stuckDetector.check(opts.threadId);
58123
+ if (stuckState.detected) {
58124
+ const intervention = getInterventionMessage(stuckState);
58125
+ log48.warn(`[agent-loop] ${intervention}`);
58126
+ if (stuckState.count >= 4) {
58127
+ finalContent = intervention;
58128
+ loopDetected = true;
58129
+ emitCanvas("canvas:node_update", {
58130
+ nodeId: opts.agentId,
58131
+ changes: { status: "stuck", currentTool: stuckState.toolName }
58132
+ });
58133
+ break;
58134
+ } else {
58135
+ messages.push({
58136
+ role: "user",
58137
+ content: intervention
58138
+ });
58139
+ }
58140
+ }
58141
+ const hadProgress = toolResults.some((r) => PROGRESS_TOOLS.has(r.toolName) && !String(r.result).startsWith("[Tool Error]"));
58142
+ if (hadProgress) {
58143
+ idleIterations = 0;
58144
+ } else if (toolResults.length > 0) {
58145
+ idleIterations++;
58146
+ }
58147
+ if (idleIterations >= 3 && idleIterations < 5) {
58148
+ const stallMsg = "ADVERTENCIA: Llevas varios pasos sin modificar la p\xE1gina. Si ya completaste el formulario, responde al usuario. Si no, avanza con browser_type/browser_click en lugar de seguir inspeccionando.";
58149
+ log48.warn(`[agent-loop] ${stallMsg}`);
58150
+ messages.push({ role: "user", content: stallMsg });
58151
+ } else if (idleIterations >= 5) {
58152
+ const stallMsg = "No logr\xE9 avanzar en el formulario despu\xE9s de varios intentos. Puede que la p\xE1gina no sea compatible o que falten instrucciones. Te sugiero revisar la URL o darme m\xE1s detalles.";
58153
+ log48.warn(`[agent-loop] Stall break: ${stallMsg}`);
58154
+ finalContent = stallMsg;
58155
+ emitCanvas("canvas:node_update", {
58156
+ nodeId: opts.agentId,
58157
+ changes: { status: "stuck", currentTool: "NO_PROGRESS" }
58158
+ });
58159
+ break;
58160
+ }
57709
58161
  emitCanvas("canvas:node_update", {
57710
58162
  nodeId: opts.agentId,
57711
58163
  changes: { status: "thinking", currentTool: null }
57712
58164
  });
57713
58165
  }
57714
58166
  if (!finalContent) {
57715
- log47.info(`[agent-loop] Max iterations hit with no text response \u2014 requesting synthesis (isolated=${!!opts.isolated})`);
58167
+ log48.info(`[agent-loop] Max iterations hit with no text response \u2014 requesting synthesis (isolated=${!!opts.isolated})`);
57716
58168
  try {
57717
58169
  messages.push({
57718
58170
  role: "user",
@@ -57733,7 +58185,7 @@ ${section}`);
57733
58185
  }
57734
58186
  yield { agent: { messages: [{ content: finalContent }] } };
57735
58187
  } catch (err) {
57736
- log47.warn(`[agent-loop] Synthesis call failed: ${err.message}`);
58188
+ log48.warn(`[agent-loop] Synthesis call failed: ${err.message}`);
57737
58189
  finalContent = "He completado las tareas solicitadas.";
57738
58190
  if (!opts.isolated) {
57739
58191
  addMessage(opts.threadId, "assistant", finalContent);
@@ -57768,7 +58220,7 @@ ${section}`);
57768
58220
  durationMs,
57769
58221
  tokensUsed: totalInputTokens + totalOutputTokens
57770
58222
  });
57771
- log47.info(`[agent-loop] Done: agent=${agentName} iterations=${iterations} ` + `tokens=${totalInputTokens + totalOutputTokens} elapsed=${durationMs}ms`);
58223
+ log48.info(`[agent-loop] Done: agent=${agentName} iterations=${iterations} ` + `tokens=${totalInputTokens + totalOutputTokens} elapsed=${durationMs}ms`);
57772
58224
  }
57773
58225
  async function runAgentIsolated(opts) {
57774
58226
  let lastContent = "";
@@ -57801,16 +58253,16 @@ class AgentLoop {
57801
58253
  channel: config2.configurable?.channel ? (config2.configurable?.channel).split(":")[0] : null,
57802
58254
  channelUserId: config2.configurable?.thread_id
57803
58255
  });
57804
- log47.info(`[AgentLoop.stream] MCP Manager available: ${this.mcpManager !== null}`);
58256
+ log48.info(`[AgentLoop.stream] MCP Manager available: ${this.mcpManager !== null}`);
57805
58257
  if (this.mcpManager) {
57806
58258
  try {
57807
58259
  const servers = this.mcpManager.listServers?.() || [];
57808
- log47.info(`[AgentLoop.stream] MCP servers: ${servers.length} registered`);
58260
+ log48.info(`[AgentLoop.stream] MCP servers: ${servers.length} registered`);
57809
58261
  for (const s2 of servers) {
57810
- log47.info(` - ${s2.name}: ${s2.status} (${s2.tools?.length || 0} tools)`);
58262
+ log48.info(` - ${s2.name}: ${s2.status} (${s2.tools?.length || 0} tools)`);
57811
58263
  }
57812
58264
  } catch (e) {
57813
- log47.warn(`[AgentLoop.stream] Failed to list MCP servers: ${e.message}`);
58265
+ log48.warn(`[AgentLoop.stream] Failed to list MCP servers: ${e.message}`);
57814
58266
  }
57815
58267
  }
57816
58268
  const lastUserMsg = [...input.messages].reverse().find((m2) => m2.role === "user");
@@ -57826,7 +58278,10 @@ class AgentLoop {
57826
58278
  systemPromptOverride,
57827
58279
  mcpManager: this.mcpManager,
57828
58280
  userId,
57829
- signal: config2.signal
58281
+ signal: config2.signal,
58282
+ onToken: config2.onToken,
58283
+ onStep: config2.onStep,
58284
+ extraTools: config2.extraTools
57830
58285
  });
57831
58286
  }
57832
58287
  _resolveCoordinatorId() {
@@ -57841,9 +58296,9 @@ function buildAgentLoop(opts = {}) {
57841
58296
  _agentLoop = new AgentLoop;
57842
58297
  if (opts.mcpManager) {
57843
58298
  _agentLoop.setMCPManager(opts.mcpManager);
57844
- log47.info("[buildAgentLoop] MCP Manager set successfully");
58299
+ log48.info("[buildAgentLoop] MCP Manager set successfully");
57845
58300
  } else {
57846
- log47.warn("[buildAgentLoop] No MCP Manager provided, agent will not have MCP tools");
58301
+ log48.warn("[buildAgentLoop] No MCP Manager provided, agent will not have MCP tools");
57847
58302
  }
57848
58303
  return _agentLoop;
57849
58304
  }
@@ -57851,7 +58306,7 @@ async function rebuildAgentLoop(opts = {}) {
57851
58306
  _agentLoop = null;
57852
58307
  return buildAgentLoop(opts);
57853
58308
  }
57854
- var log47, _agentLoop = null;
58309
+ var log48, DEFAULT_MAX_WALL_CLOCK_MS, _agentLoop = null;
57855
58310
  var init_agent_loop = __esm(() => {
57856
58311
  init_logger();
57857
58312
  init_sqlite();
@@ -57865,11 +58320,13 @@ var init_agent_loop = __esm(() => {
57865
58320
  init_onboarding();
57866
58321
  init_loader();
57867
58322
  init_tool_runtime();
57868
- log47 = logger.child("agent-loop");
58323
+ init_stuck_loop();
58324
+ log48 = logger.child("agent-loop");
58325
+ DEFAULT_MAX_WALL_CLOCK_MS = 5 * 60 * 1000;
57869
58326
  });
57870
58327
 
57871
58328
  // packages/core/src/tools/agents/index.ts
57872
- import crypto2 from "crypto";
58329
+ import crypto3 from "crypto";
57873
58330
  function createTools5() {
57874
58331
  return [
57875
58332
  memoryWriteTool,
@@ -57888,13 +58345,13 @@ function createTools5() {
57888
58345
  busReadTool
57889
58346
  ];
57890
58347
  }
57891
- var log48, memoryWriteTool, memoryReadTool, memoryListTool, memorySearchTool, memoryDeleteTool, agentCreateTool, agentFindTool, agentArchiveTool, taskDelegateTool, taskDelegateCodeTool, taskStatusTool, busPublishTool, busReadTool;
58348
+ var log49, memoryWriteTool, memoryReadTool, memoryListTool, memorySearchTool, memoryDeleteTool, agentCreateTool, agentFindTool, agentArchiveTool, taskDelegateTool, taskDelegateCodeTool, taskStatusTool, busPublishTool, busReadTool;
57892
58349
  var init_agents = __esm(() => {
57893
58350
  init_sqlite();
57894
58351
  init_logger();
57895
58352
  init_agent_bus();
57896
58353
  init_get_available_models();
57897
- log48 = logger.child("agents");
58354
+ log49 = logger.child("agents");
57898
58355
  memoryWriteTool = {
57899
58356
  name: "memory_write",
57900
58357
  description: "Store information in persistent long-term memory. Spanish: guardar memoria, recordar, guardar dato, memoria persistente",
@@ -58089,7 +58546,7 @@ var init_agents = __esm(() => {
58089
58546
  };
58090
58547
  }
58091
58548
  try {
58092
- const agentId = crypto2.randomUUID().replace(/-/g, "").slice(0, 16);
58549
+ const agentId = crypto3.randomUUID().replace(/-/g, "").slice(0, 16);
58093
58550
  db.query(`
58094
58551
  INSERT INTO agents (id, user_id, name, description, system_prompt, tools_json, role, status, parent_id, provider_id, model_id, tone, max_iterations, workspace)
58095
58552
  VALUES (?, ?, ?, ?, ?, ?, 'worker', 'idle', ?, ?, ?, ?, ?, ?)
@@ -58199,7 +58656,7 @@ var init_agents = __esm(() => {
58199
58656
  }
58200
58657
  const taskName = taskDescription.slice(0, 60);
58201
58658
  agentBus.notifyTaskStarted(workerId, worker.name, 0, taskName, "");
58202
- log48.info(`[task_delegate] Delegating to ${worker.name} (${workerId})`);
58659
+ log49.info(`[task_delegate] Delegating to ${worker.name} (${workerId})`);
58203
58660
  try {
58204
58661
  const { runAgentIsolated: runAgentIsolated2 } = await Promise.resolve().then(() => (init_agent_loop(), exports_agent_loop));
58205
58662
  const threadId = `task-${Date.now()}-${workerId}`;
@@ -58685,7 +59142,7 @@ var init_canvas_manager = __esm(() => {
58685
59142
 
58686
59143
  // packages/core/src/canvas/a2ui-tools.ts
58687
59144
  function createA2UISurfaceTool(_config) {
58688
- const log49 = logger.child("a2ui-surface");
59145
+ const log50 = logger.child("a2ui-surface");
58689
59146
  return {
58690
59147
  name: "a2ui_create_surface",
58691
59148
  description: "Create an A2UI v0.9 surface on the user's canvas for rendering rich interactive UIs",
@@ -58737,7 +59194,7 @@ function createA2UISurfaceTool(_config) {
58737
59194
  })();
58738
59195
  if (!canvasManager.isSessionConnected(sessionId)) {
58739
59196
  const connected = canvasManager.getConnectedSessions();
58740
- log49.warn(`No canvas sessions connected. Rendering to ${sessionId} anyway. Available: ${connected.join(", ")}`);
59197
+ log50.warn(`No canvas sessions connected. Rendering to ${sessionId} anyway. Available: ${connected.join(", ")}`);
58741
59198
  }
58742
59199
  await canvasManager.sendA2UIMessage(sessionId, "a2ui:createSurface", {
58743
59200
  surfaceId: params.surfaceId,
@@ -58745,7 +59202,7 @@ function createA2UISurfaceTool(_config) {
58745
59202
  theme: params.theme ?? {},
58746
59203
  sendDataModel: params.sendDataModel ?? false
58747
59204
  });
58748
- log49.info(`Created A2UI surface '${params.surfaceId}' on session ${sessionId}`);
59205
+ log50.info(`Created A2UI surface '${params.surfaceId}' on session ${sessionId}`);
58749
59206
  return JSON.stringify({
58750
59207
  status: "created",
58751
59208
  surfaceId: params.surfaceId,
@@ -58755,7 +59212,7 @@ function createA2UISurfaceTool(_config) {
58755
59212
  };
58756
59213
  }
58757
59214
  function createA2UIUpdateComponentsTool(_config) {
58758
- const log49 = logger.child("a2ui-components");
59215
+ const log50 = logger.child("a2ui-components");
58759
59216
  return {
58760
59217
  name: "a2ui_update_components",
58761
59218
  description: `Send A2UI v0.9 components to an existing surface. Components are a FLAT list with ID references (adjacency list).
@@ -58826,7 +59283,7 @@ Root component: usar id="root" expl\xEDcito.`,
58826
59283
  surfaceId: params.surfaceId,
58827
59284
  components: params.components
58828
59285
  });
58829
- log49.info(`Updated A2UI components on surface '${params.surfaceId}' (${params.components.length} components)`);
59286
+ log50.info(`Updated A2UI components on surface '${params.surfaceId}' (${params.components.length} components)`);
58830
59287
  return JSON.stringify({
58831
59288
  status: "updated",
58832
59289
  surfaceId: params.surfaceId,
@@ -58836,7 +59293,7 @@ Root component: usar id="root" expl\xEDcito.`,
58836
59293
  };
58837
59294
  }
58838
59295
  function createA2UIUpdateDataModelTool(_config) {
58839
- const log49 = logger.child("a2ui-data");
59296
+ const log50 = logger.child("a2ui-data");
58840
59297
  return {
58841
59298
  name: "a2ui_update_data_model",
58842
59299
  description: "Update the data model for an A2UI v0.9 surface. The data model provides dynamic values that components can bind to via paths (e.g. '/user/name').",
@@ -58873,7 +59330,7 @@ function createA2UIUpdateDataModelTool(_config) {
58873
59330
  path: params.path,
58874
59331
  value: params.value
58875
59332
  });
58876
- log49.info(`Updated A2UI data model on surface '${params.surfaceId}' (path: ${params.path ?? "/"})`);
59333
+ log50.info(`Updated A2UI data model on surface '${params.surfaceId}' (path: ${params.path ?? "/"})`);
58877
59334
  return JSON.stringify({
58878
59335
  status: "updated",
58879
59336
  surfaceId: params.surfaceId,
@@ -58883,7 +59340,7 @@ function createA2UIUpdateDataModelTool(_config) {
58883
59340
  };
58884
59341
  }
58885
59342
  function createA2UIDeleteSurfaceTool(_config) {
58886
- const log49 = logger.child("a2ui-delete");
59343
+ const log50 = logger.child("a2ui-delete");
58887
59344
  return {
58888
59345
  name: "a2ui_delete_surface",
58889
59346
  description: "Delete an A2UI v0.9 surface and remove it from the user's canvas",
@@ -58910,7 +59367,7 @@ function createA2UIDeleteSurfaceTool(_config) {
58910
59367
  await canvasManager.sendA2UIMessage(sessionId, "a2ui:deleteSurface", {
58911
59368
  surfaceId: params.surfaceId
58912
59369
  });
58913
- log49.info(`Deleted A2UI surface '${params.surfaceId}'`);
59370
+ log50.info(`Deleted A2UI surface '${params.surfaceId}'`);
58914
59371
  return JSON.stringify({
58915
59372
  status: "deleted",
58916
59373
  surfaceId: params.surfaceId
@@ -58949,13 +59406,13 @@ function createTools6(config2) {
58949
59406
  createA2UIDeleteSurfaceTool(a2uiConfig)
58950
59407
  ];
58951
59408
  }
58952
- var log49, pendingInteractions, canvasRenderTool, canvasAskTool, canvasConfirmTool, canvasShowCardTool, canvasShowProgressTool, canvasShowListTool, canvasClearTool;
59409
+ var log50, pendingInteractions, canvasRenderTool, canvasAskTool, canvasConfirmTool, canvasShowCardTool, canvasShowProgressTool, canvasShowListTool, canvasClearTool;
58953
59410
  var init_canvas = __esm(() => {
58954
59411
  init_emitter();
58955
59412
  init_logger();
58956
59413
  init_canvas_manager();
58957
59414
  init_a2ui_tools();
58958
- log49 = logger.child("canvas");
59415
+ log50 = logger.child("canvas");
58959
59416
  pendingInteractions = new Map;
58960
59417
  canvasRenderTool = {
58961
59418
  name: "canvas_render",
@@ -59271,10 +59728,10 @@ var init_canvas = __esm(() => {
59271
59728
  function createTools7() {
59272
59729
  return [voiceTranscribeTool, voiceSpeakTool];
59273
59730
  }
59274
- var log50, voiceTranscribeTool, voiceSpeakTool;
59731
+ var log51, voiceTranscribeTool, voiceSpeakTool;
59275
59732
  var init_voice = __esm(() => {
59276
59733
  init_logger();
59277
- log50 = logger.child("voice");
59734
+ log51 = logger.child("voice");
59278
59735
  voiceTranscribeTool = {
59279
59736
  name: "voice_transcribe",
59280
59737
  description: "Transcribe audio input to text. Spanish: transcribir audio, voz a texto, reconocimiento de voz",
@@ -59295,7 +59752,7 @@ var init_voice = __esm(() => {
59295
59752
  execute: async (params) => {
59296
59753
  const audio = params.audio;
59297
59754
  const language = params.language ?? "auto";
59298
- log50.info(`Transcribing audio: ${audio.substring(0, 50)}...`);
59755
+ log51.info(`Transcribing audio: ${audio.substring(0, 50)}...`);
59299
59756
  try {
59300
59757
  return {
59301
59758
  ok: true,
@@ -59337,7 +59794,7 @@ var init_voice = __esm(() => {
59337
59794
  const text = params.text;
59338
59795
  const voiceId = params.voice_id ?? "default";
59339
59796
  const language = params.language ?? "es";
59340
- log50.info(`Synthesizing speech: ${text.substring(0, 50)}...`);
59797
+ log51.info(`Synthesizing speech: ${text.substring(0, 50)}...`);
59341
59798
  try {
59342
59799
  return {
59343
59800
  ok: true,
@@ -59374,11 +59831,11 @@ function buildFtsMatch(words) {
59374
59831
  function createTools8() {
59375
59832
  return [searchKnowledgeTool, notifyTool, saveNoteTool, reportProgressTool];
59376
59833
  }
59377
- var log51, ES_EN_DICT, searchKnowledgeTool, notifyTool, saveNoteTool, reportProgressTool;
59834
+ var log52, ES_EN_DICT, searchKnowledgeTool, notifyTool, saveNoteTool, reportProgressTool;
59378
59835
  var init_core3 = __esm(() => {
59379
59836
  init_sqlite();
59380
59837
  init_logger();
59381
- log51 = logger.child("core");
59838
+ log52 = logger.child("core");
59382
59839
  ES_EN_DICT = {
59383
59840
  buscar: ["search", "find", "list", "get", "query"],
59384
59841
  listar: ["list", "get", "fetch", "retrieve"],
@@ -59569,7 +60026,7 @@ var init_core3 = __esm(() => {
59569
60026
  }
59570
60027
  };
59571
60028
  if (!query2) {
59572
- log51.info(`[search_knowledge] Empty query \u2014 returning empty results`);
60029
+ log52.info(`[search_knowledge] Empty query \u2014 returning empty results`);
59573
60030
  return { query: query2, type, tools: [], skills: [], playbook: [], toolsmcp: [] };
59574
60031
  }
59575
60032
  const escapedQuery = query2.replace(/'/g, "''");
@@ -59628,7 +60085,7 @@ var init_core3 = __esm(() => {
59628
60085
  if (englishQuery.length > 0) {
59629
60086
  const enWords = englishQuery.split(/\s+/).filter((w2) => w2.length > 0);
59630
60087
  const enMatch = buildFtsMatch(enWords);
59631
- log51.info(`[search_knowledge] Bilingual fallback: "${normalizedQuery}" \u2192 "${englishQuery}" (first pass: ${totalFirst} results)`);
60088
+ log52.info(`[search_knowledge] Bilingual fallback: "${normalizedQuery}" \u2192 "${englishQuery}" (first pass: ${totalFirst} results)`);
59632
60089
  const existingIds = new Set([
59633
60090
  ...result.tools.map((t) => t.name),
59634
60091
  ...result.skills.map((s2) => s2.id),
@@ -59726,7 +60183,7 @@ var init_core3 = __esm(() => {
59726
60183
  const message = params.message;
59727
60184
  const channel = config2?.configurable?.channel ?? "webchat";
59728
60185
  const userId = config2?.configurable?.user_id ?? "";
59729
- log51.info(`[notify] Sending to ${channel}/${userId}: ${message.substring(0, 80)}`);
60186
+ log52.info(`[notify] Sending to ${channel}/${userId}: ${message.substring(0, 80)}`);
59730
60187
  const result = await sendToUserChannel2(channel, userId, message);
59731
60188
  if (!result.ok)
59732
60189
  throw new Error(`Channel send failed: ${result.error}`);
@@ -59801,7 +60258,7 @@ var init_core3 = __esm(() => {
59801
60258
  const taskId = params.task_id ?? null;
59802
60259
  const channel = config2?.configurable?.channel ?? "webchat";
59803
60260
  const userId = config2?.configurable?.user_id ?? "";
59804
- log51.info(`[report_progress] ${progress}% \u2014 ${message}`);
60261
+ log52.info(`[report_progress] ${progress}% \u2014 ${message}`);
59805
60262
  if (taskId) {
59806
60263
  const db = getDb();
59807
60264
  db.query(`UPDATE tasks SET progress = ?, updated_at = unixepoch() WHERE id = ?`).run(progress, taskId);
@@ -117207,10 +117664,10 @@ var init_pdf2 = __esm(() => {
117207
117664
  // packages/core/src/tools/office/office-leer-pdf.ts
117208
117665
  import * as fs11 from "fs";
117209
117666
  import * as path12 from "path";
117210
- var log52, officeLeerPdfTool;
117667
+ var log53, officeLeerPdfTool;
117211
117668
  var init_office_leer_pdf = __esm(() => {
117212
117669
  init_logger();
117213
- log52 = logger.child("office-leer-pdf");
117670
+ log53 = logger.child("office-leer-pdf");
117214
117671
  officeLeerPdfTool = {
117215
117672
  name: "office_leer_pdf",
117216
117673
  description: "Leer contenido de un archivo PDF y retornar texto plano con metadata. Spanish: leer pdf, abrir pdf, extraer texto de pdf, pdf a texto",
@@ -117236,7 +117693,7 @@ var init_office_leer_pdf = __esm(() => {
117236
117693
  const ruta = params.ruta;
117237
117694
  const paginaInicio = Math.max(1, params.pagina_inicio ?? 1);
117238
117695
  const paginaFin = params.pagina_fin;
117239
- log52.debug(`Leyendo PDF: ${ruta}`);
117696
+ log53.debug(`Leyendo PDF: ${ruta}`);
117240
117697
  try {
117241
117698
  const rutaAbsoluta = path12.resolve(ruta);
117242
117699
  if (!fs11.existsSync(rutaAbsoluta)) {
@@ -117268,7 +117725,7 @@ var init_office_leer_pdf = __esm(() => {
117268
117725
  const textoCompleto = textosPorPagina.map((p2) => p2.texto).join(`
117269
117726
 
117270
117727
  `);
117271
- log52.info(`PDF le\xEDdo: ${totalPaginas} p\xE1ginas, ${textoCompleto.length} caracteres`);
117728
+ log53.info(`PDF le\xEDdo: ${totalPaginas} p\xE1ginas, ${textoCompleto.length} caracteres`);
117272
117729
  return {
117273
117730
  ok: true,
117274
117731
  ruta: rutaAbsoluta,
@@ -117279,7 +117736,7 @@ var init_office_leer_pdf = __esm(() => {
117279
117736
  paginas: textosPorPagina
117280
117737
  };
117281
117738
  } catch (error4) {
117282
- log52.error(`Error leyendo PDF: ${error4.message}`);
117739
+ log53.error(`Error leyendo PDF: ${error4.message}`);
117283
117740
  return {
117284
117741
  ok: false,
117285
117742
  error: `No se pudo leer el PDF: ${error4.message}`
@@ -138038,10 +138495,10 @@ var init_es2 = __esm(() => {
138038
138495
  // packages/core/src/tools/office/office-escribir-pdf.ts
138039
138496
  import * as path13 from "path";
138040
138497
  import * as fs12 from "fs";
138041
- var log53, officeEscribirPdfTool;
138498
+ var log54, officeEscribirPdfTool;
138042
138499
  var init_office_escribir_pdf = __esm(() => {
138043
138500
  init_logger();
138044
- log53 = logger.child("office-escribir-pdf");
138501
+ log54 = logger.child("office-escribir-pdf");
138045
138502
  officeEscribirPdfTool = {
138046
138503
  name: "office_escribir_pdf",
138047
138504
  description: "Generar un archivo PDF desde texto con configuraci\xF3n de m\xE1rgenes y tama\xF1o de p\xE1gina. Spanish: crear pdf, generar pdf, escribir pdf, exportar a pdf",
@@ -138083,7 +138540,7 @@ var init_office_escribir_pdf = __esm(() => {
138083
138540
  const tama_oPagina = params.tama\u{f1}o_pagina ?? "A4";
138084
138541
  const margen = params.margen ?? 50;
138085
138542
  const tama_oFuente = params.tama\u{f1}o_fuente ?? 12;
138086
- log53.debug(`Generando PDF: ${ruta}`);
138543
+ log54.debug(`Generando PDF: ${ruta}`);
138087
138544
  try {
138088
138545
  const { PDFDocument: PDFDocument2, StandardFonts: StandardFonts3, rgb: rgb2, PageSizes: PageSizes2 } = await Promise.resolve().then(() => (init_es2(), exports_es));
138089
138546
  const pdfDoc = await PDFDocument2.create();
@@ -138157,7 +138614,7 @@ var init_office_escribir_pdf = __esm(() => {
138157
138614
  }
138158
138615
  const pdfBytes = await pdfDoc.save();
138159
138616
  fs12.writeFileSync(rutaAbsoluta, pdfBytes);
138160
- log53.info(`PDF generado: ${rutaAbsoluta} (${pdfDoc.getPageCount()} p\xE1ginas)`);
138617
+ log54.info(`PDF generado: ${rutaAbsoluta} (${pdfDoc.getPageCount()} p\xE1ginas)`);
138161
138618
  return {
138162
138619
  ok: true,
138163
138620
  ruta: rutaAbsoluta,
@@ -138165,7 +138622,7 @@ var init_office_escribir_pdf = __esm(() => {
138165
138622
  bytesEscritos: pdfBytes.length
138166
138623
  };
138167
138624
  } catch (error5) {
138168
- log53.error(`Error generando PDF: ${error5.message}`);
138625
+ log54.error(`Error generando PDF: ${error5.message}`);
138169
138626
  return {
138170
138627
  ok: false,
138171
138628
  error: `No se pudo generar el PDF: ${error5.message}`
@@ -162040,10 +162497,10 @@ var require_lib6 = __commonJS((exports) => {
162040
162497
  // packages/core/src/tools/office/office-leer-docx.ts
162041
162498
  import * as fs13 from "fs";
162042
162499
  import * as path14 from "path";
162043
- var log54, officeLeerDocxTool;
162500
+ var log55, officeLeerDocxTool;
162044
162501
  var init_office_leer_docx = __esm(() => {
162045
162502
  init_logger();
162046
- log54 = logger.child("office-leer-docx");
162503
+ log55 = logger.child("office-leer-docx");
162047
162504
  officeLeerDocxTool = {
162048
162505
  name: "office_leer_docx",
162049
162506
  description: "Leer un archivo Word (.docx) y retornar el contenido de texto preservando p\xE1rrafos y tablas. Spanish: leer word, abrir docx, extraer texto de word, contenido word",
@@ -162064,7 +162521,7 @@ var init_office_leer_docx = __esm(() => {
162064
162521
  execute: async (params) => {
162065
162522
  const ruta = params.ruta;
162066
162523
  const incluirTablas = params.incluir_tablas ?? true;
162067
- log54.debug(`Leyendo DOCX: ${ruta}`);
162524
+ log55.debug(`Leyendo DOCX: ${ruta}`);
162068
162525
  try {
162069
162526
  const rutaAbsoluta = path14.resolve(ruta);
162070
162527
  if (!fs13.existsSync(rutaAbsoluta)) {
@@ -162089,7 +162546,7 @@ ${textoCeldas.join(" | ")}`;
162089
162546
  }
162090
162547
  }
162091
162548
  const advertencias = resultadoTexto.messages.filter((m2) => m2.type === "warning").map((m2) => m2.message);
162092
- log54.info(`DOCX le\xEDdo: ${resultadoTexto.value.length} caracteres`);
162549
+ log55.info(`DOCX le\xEDdo: ${resultadoTexto.value.length} caracteres`);
162093
162550
  return {
162094
162551
  ok: true,
162095
162552
  ruta: rutaAbsoluta,
@@ -162098,7 +162555,7 @@ ${textoCeldas.join(" | ")}`;
162098
162555
  advertencias: advertencias.length > 0 ? advertencias : undefined
162099
162556
  };
162100
162557
  } catch (error5) {
162101
- log54.error(`Error leyendo DOCX: ${error5.message}`);
162558
+ log55.error(`Error leyendo DOCX: ${error5.message}`);
162102
162559
  return {
162103
162560
  ok: false,
162104
162561
  error: `No se pudo leer el archivo DOCX: ${error5.message}`
@@ -183937,10 +184394,10 @@ var init_dist3 = __esm(() => {
183937
184394
  // packages/core/src/tools/office/office-escribir-docx.ts
183938
184395
  import * as path15 from "path";
183939
184396
  import * as fs14 from "fs";
183940
- var log55, officeEscribirDocxTool;
184397
+ var log56, officeEscribirDocxTool;
183941
184398
  var init_office_escribir_docx = __esm(() => {
183942
184399
  init_logger();
183943
- log55 = logger.child("office-escribir-docx");
184400
+ log56 = logger.child("office-escribir-docx");
183944
184401
  officeEscribirDocxTool = {
183945
184402
  name: "office_escribir_docx",
183946
184403
  description: "Generar un archivo Word (.docx) con p\xE1rrafos, t\xEDtulos y tablas. Spanish: crear word, generar docx, escribir documento word, exportar a docx",
@@ -183987,7 +184444,7 @@ var init_office_escribir_docx = __esm(() => {
183987
184444
  const titulo = params.titulo;
183988
184445
  const parrafosInput = params.parrafos ?? [];
183989
184446
  const tablasInput = params.tablas ?? [];
183990
- log55.debug(`Generando DOCX: ${ruta}`);
184447
+ log56.debug(`Generando DOCX: ${ruta}`);
183991
184448
  try {
183992
184449
  const {
183993
184450
  Document: Document2,
@@ -184067,7 +184524,7 @@ var init_office_escribir_docx = __esm(() => {
184067
184524
  }
184068
184525
  const buffer2 = await Packer2.toBuffer(doc2);
184069
184526
  fs14.writeFileSync(rutaAbsoluta, buffer2);
184070
- log55.info(`DOCX generado: ${rutaAbsoluta} (${buffer2.length} bytes)`);
184527
+ log56.info(`DOCX generado: ${rutaAbsoluta} (${buffer2.length} bytes)`);
184071
184528
  return {
184072
184529
  ok: true,
184073
184530
  ruta: rutaAbsoluta,
@@ -184076,7 +184533,7 @@ var init_office_escribir_docx = __esm(() => {
184076
184533
  tablas: tablasInput.length
184077
184534
  };
184078
184535
  } catch (error5) {
184079
- log55.error(`Error generando DOCX: ${error5.message}`);
184536
+ log56.error(`Error generando DOCX: ${error5.message}`);
184080
184537
  return {
184081
184538
  ok: false,
184082
184539
  error: `No se pudo generar el archivo DOCX: ${error5.message}`
@@ -211988,10 +212445,10 @@ var init_xlsx = __esm(() => {
211988
212445
  // packages/core/src/tools/office/office-leer-xlsx.ts
211989
212446
  import * as fs15 from "fs";
211990
212447
  import * as path16 from "path";
211991
- var log56, officeLeerXlsxTool;
212448
+ var log57, officeLeerXlsxTool;
211992
212449
  var init_office_leer_xlsx = __esm(() => {
211993
212450
  init_logger();
211994
- log56 = logger.child("office-leer-xlsx");
212451
+ log57 = logger.child("office-leer-xlsx");
211995
212452
  officeLeerXlsxTool = {
211996
212453
  name: "office_leer_xlsx",
211997
212454
  description: "Leer un archivo Excel (.xlsx) y retornar las hojas con sus datos como objetos JSON. Spanish: leer excel, abrir xlsx, extraer datos de excel, hojas excel",
@@ -212022,7 +212479,7 @@ var init_office_leer_xlsx = __esm(() => {
212022
212479
  const hojaFiltro = params.hoja;
212023
212480
  const incluirEncabezados = params.incluir_encabezados ?? true;
212024
212481
  const rango = params.rango;
212025
- log56.debug(`Leyendo XLSX: ${ruta}`);
212482
+ log57.debug(`Leyendo XLSX: ${ruta}`);
212026
212483
  try {
212027
212484
  const rutaAbsoluta = path16.resolve(ruta);
212028
212485
  if (!fs15.existsSync(rutaAbsoluta)) {
@@ -212036,7 +212493,7 @@ var init_office_leer_xlsx = __esm(() => {
212036
212493
  for (const nombreHoja of nombresHojas) {
212037
212494
  const hoja = workbook.Sheets[nombreHoja];
212038
212495
  if (!hoja) {
212039
- log56.warn(`Hoja '${nombreHoja}' no encontrada en el archivo`);
212496
+ log57.warn(`Hoja '${nombreHoja}' no encontrada en el archivo`);
212040
212497
  continue;
212041
212498
  }
212042
212499
  const opciones = {
@@ -212060,7 +212517,7 @@ var init_office_leer_xlsx = __esm(() => {
212060
212517
  }
212061
212518
  }
212062
212519
  const totalFilas = Object.values(hojas).reduce((acc, filas) => acc + filas.length, 0);
212063
- log56.info(`XLSX le\xEDdo: ${nombresHojas.length} hojas, ${totalFilas} filas totales`);
212520
+ log57.info(`XLSX le\xEDdo: ${nombresHojas.length} hojas, ${totalFilas} filas totales`);
212064
212521
  return {
212065
212522
  ok: true,
212066
212523
  ruta: rutaAbsoluta,
@@ -212069,7 +212526,7 @@ var init_office_leer_xlsx = __esm(() => {
212069
212526
  totalFilas
212070
212527
  };
212071
212528
  } catch (error5) {
212072
- log56.error(`Error leyendo XLSX: ${error5.message}`);
212529
+ log57.error(`Error leyendo XLSX: ${error5.message}`);
212073
212530
  return {
212074
212531
  ok: false,
212075
212532
  error: `No se pudo leer el archivo Excel: ${error5.message}`
@@ -212082,10 +212539,10 @@ var init_office_leer_xlsx = __esm(() => {
212082
212539
  // packages/core/src/tools/office/office-escribir-xlsx.ts
212083
212540
  import * as path17 from "path";
212084
212541
  import * as fs16 from "fs";
212085
- var log57, officeEscribirXlsxTool;
212542
+ var log58, officeEscribirXlsxTool;
212086
212543
  var init_office_escribir_xlsx = __esm(() => {
212087
212544
  init_logger();
212088
- log57 = logger.child("office-escribir-xlsx");
212545
+ log58 = logger.child("office-escribir-xlsx");
212089
212546
  officeEscribirXlsxTool = {
212090
212547
  name: "office_escribir_xlsx",
212091
212548
  description: "Generar un archivo Excel (.xlsx) desde un objeto JSON con hojas, filas y columnas. Spanish: crear excel, generar xlsx, escribir excel, exportar a xlsx",
@@ -212114,7 +212571,7 @@ var init_office_escribir_xlsx = __esm(() => {
212114
212571
  execute: async (params) => {
212115
212572
  const ruta = params.ruta;
212116
212573
  const hojasInput = params.hojas;
212117
- log57.debug(`Generando XLSX: ${ruta}`);
212574
+ log58.debug(`Generando XLSX: ${ruta}`);
212118
212575
  try {
212119
212576
  const XLSX2 = await Promise.resolve().then(() => (init_xlsx(), exports_xlsx));
212120
212577
  const workbook = XLSX2.utils.book_new();
@@ -212135,7 +212592,7 @@ var init_office_escribir_xlsx = __esm(() => {
212135
212592
  const buffer2 = XLSX2.write(workbook, { type: "buffer", bookType: "xlsx" });
212136
212593
  fs16.writeFileSync(rutaAbsoluta, buffer2);
212137
212594
  const totalFilas = hojasInput.reduce((acc, h) => acc + h.datos.length, 0);
212138
- log57.info(`XLSX generado: ${rutaAbsoluta} (${hojasInput.length} hojas, ${totalFilas} filas)`);
212595
+ log58.info(`XLSX generado: ${rutaAbsoluta} (${hojasInput.length} hojas, ${totalFilas} filas)`);
212139
212596
  return {
212140
212597
  ok: true,
212141
212598
  ruta: rutaAbsoluta,
@@ -212145,7 +212602,7 @@ var init_office_escribir_xlsx = __esm(() => {
212145
212602
  bytesEscritos: buffer2.length
212146
212603
  };
212147
212604
  } catch (error5) {
212148
- log57.error(`Error generando XLSX: ${error5.message}`);
212605
+ log58.error(`Error generando XLSX: ${error5.message}`);
212149
212606
  return {
212150
212607
  ok: false,
212151
212608
  error: `No se pudo generar el archivo Excel: ${error5.message}`
@@ -212158,10 +212615,10 @@ var init_office_escribir_xlsx = __esm(() => {
212158
212615
  // packages/core/src/tools/office/office-leer-pptx.ts
212159
212616
  import * as fs17 from "fs";
212160
212617
  import * as path18 from "path";
212161
- var log58, officeLeerPptxTool;
212618
+ var log59, officeLeerPptxTool;
212162
212619
  var init_office_leer_pptx = __esm(() => {
212163
212620
  init_logger();
212164
- log58 = logger.child("office-leer-pptx");
212621
+ log59 = logger.child("office-leer-pptx");
212165
212622
  officeLeerPptxTool = {
212166
212623
  name: "office_leer_pptx",
212167
212624
  description: "Leer un archivo PowerPoint (.pptx) y retornar el texto de cada diapositiva como array estructurado. Spanish: leer powerpoint, abrir pptx, extraer texto de presentacion, contenido slides",
@@ -212182,7 +212639,7 @@ var init_office_leer_pptx = __esm(() => {
212182
212639
  execute: async (params) => {
212183
212640
  const ruta = params.ruta;
212184
212641
  const soloSlide = params.solo_diapositiva;
212185
- log58.debug(`Leyendo PPTX: ${ruta}`);
212642
+ log59.debug(`Leyendo PPTX: ${ruta}`);
212186
212643
  try {
212187
212644
  const rutaAbsoluta = path18.resolve(ruta);
212188
212645
  if (!fs17.existsSync(rutaAbsoluta)) {
@@ -212229,7 +212686,7 @@ var init_office_leer_pptx = __esm(() => {
212229
212686
  fragmentos
212230
212687
  });
212231
212688
  }
212232
- log58.info(`PPTX le\xEDdo: ${archivosSlides.length} slides totales, ${diapositivas.length} le\xEDdas`);
212689
+ log59.info(`PPTX le\xEDdo: ${archivosSlides.length} slides totales, ${diapositivas.length} le\xEDdas`);
212233
212690
  return {
212234
212691
  ok: true,
212235
212692
  ruta: rutaAbsoluta,
@@ -212237,7 +212694,7 @@ var init_office_leer_pptx = __esm(() => {
212237
212694
  diapositivas
212238
212695
  };
212239
212696
  } catch (error5) {
212240
- log58.error(`Error leyendo PPTX: ${error5.message}`);
212697
+ log59.error(`Error leyendo PPTX: ${error5.message}`);
212241
212698
  return {
212242
212699
  ok: false,
212243
212700
  error: `No se pudo leer el archivo PowerPoint: ${error5.message}`
@@ -217466,10 +217923,10 @@ var init_pptxgen_es = __esm(() => {
217466
217923
  // packages/core/src/tools/office/office-escribir-pptx.ts
217467
217924
  import * as path19 from "path";
217468
217925
  import * as fs18 from "fs";
217469
- var log59, officeEscribirPptxTool;
217926
+ var log60, officeEscribirPptxTool;
217470
217927
  var init_office_escribir_pptx = __esm(() => {
217471
217928
  init_logger();
217472
- log59 = logger.child("office-escribir-pptx");
217929
+ log60 = logger.child("office-escribir-pptx");
217473
217930
  officeEscribirPptxTool = {
217474
217931
  name: "office_escribir_pptx",
217475
217932
  description: "Generar un archivo PowerPoint (.pptx) desde un array de diapositivas con t\xEDtulo y contenido. Spanish: crear powerpoint, generar pptx, escribir presentacion, exportar a pptx",
@@ -217504,7 +217961,7 @@ var init_office_escribir_pptx = __esm(() => {
217504
217961
  const ruta = params.ruta;
217505
217962
  const tituloPresentacion = params.titulo_presentacion;
217506
217963
  const diapositivasInput = params.diapositivas;
217507
- log59.debug(`Generando PPTX: ${ruta}`);
217964
+ log60.debug(`Generando PPTX: ${ruta}`);
217508
217965
  try {
217509
217966
  const pptxgen = (await Promise.resolve().then(() => (init_pptxgen_es(), exports_pptxgen_es))).default;
217510
217967
  const pres = new pptxgen;
@@ -217578,7 +218035,7 @@ var init_office_escribir_pptx = __esm(() => {
217578
218035
  }
217579
218036
  await pres.writeFile({ fileName: rutaAbsoluta });
217580
218037
  const stats = fs18.statSync(rutaAbsoluta);
217581
- log59.info(`PPTX generado: ${rutaAbsoluta} (${diapositivasInput.length} diapositivas)`);
218038
+ log60.info(`PPTX generado: ${rutaAbsoluta} (${diapositivasInput.length} diapositivas)`);
217582
218039
  return {
217583
218040
  ok: true,
217584
218041
  ruta: rutaAbsoluta,
@@ -217586,7 +218043,7 @@ var init_office_escribir_pptx = __esm(() => {
217586
218043
  bytesEscritos: stats.size
217587
218044
  };
217588
218045
  } catch (error5) {
217589
- log59.error(`Error generando PPTX: ${error5.message}`);
218046
+ log60.error(`Error generando PPTX: ${error5.message}`);
217590
218047
  return {
217591
218048
  ok: false,
217592
218049
  error: `No se pudo generar el archivo PowerPoint: ${error5.message}`
@@ -217675,7 +218132,7 @@ class VoiceService {
217675
218132
  } else if (isOpenAi) {
217676
218133
  return this.transcribeWithOpenAIWhisper(audio);
217677
218134
  }
217678
- log60.warn(`Unknown STT provider ${modelId}, defaulting to Groq Whisper`);
218135
+ log61.warn(`Unknown STT provider ${modelId}, defaulting to Groq Whisper`);
217679
218136
  return this.transcribeWithGroq(audio, "whisper-large-v3-turbo");
217680
218137
  }
217681
218138
  async getProviderApiKey(providerId) {
@@ -217777,7 +218234,7 @@ class VoiceService {
217777
218234
  } else if (isQwen) {
217778
218235
  return this.speakWithQwen(text2, modelId, voiceId);
217779
218236
  }
217780
- log60.warn(`Unknown TTS provider ${modelId}, defaulting to ElevenLabs Flash`);
218237
+ log61.warn(`Unknown TTS provider ${modelId}, defaulting to ElevenLabs Flash`);
217781
218238
  return this.speakWithElevenLabs(text2, "eleven_flash_v2_5", voiceId);
217782
218239
  }
217783
218240
  async speakWithPiper(text2, voiceId) {
@@ -218117,12 +218574,12 @@ class VoiceService {
218117
218574
  throw new Error("WebChat audio missing base64 or buffer");
218118
218575
  }
218119
218576
  }
218120
- var log60, voiceService;
218577
+ var log61, voiceService;
218121
218578
  var init_voice2 = __esm(() => {
218122
218579
  init_sqlite();
218123
218580
  init_crypto();
218124
218581
  init_logger();
218125
- log60 = logger.child("voice");
218582
+ log61 = logger.child("voice");
218126
218583
  voiceService = VoiceService.getInstance();
218127
218584
  });
218128
218585
 
@@ -218135,12 +218592,12 @@ function createTools10() {
218135
218592
  meetingReportTool
218136
218593
  ];
218137
218594
  }
218138
- var log61, meetingStartTool, meetingAddSegmentTool, meetingStopTool, meetingReportTool;
218595
+ var log62, meetingStartTool, meetingAddSegmentTool, meetingStopTool, meetingReportTool;
218139
218596
  var init_meeting = __esm(() => {
218140
218597
  init_sqlite();
218141
218598
  init_voice2();
218142
218599
  init_logger();
218143
- log61 = logger.child("meeting");
218600
+ log62 = logger.child("meeting");
218144
218601
  meetingStartTool = {
218145
218602
  name: "meeting_start",
218146
218603
  description: "Inicia una sesi\xF3n de transcripci\xF3n de reuni\xF3n en tiempo real. | Start a real-time meeting transcription session.",
@@ -218166,7 +218623,7 @@ var init_meeting = __esm(() => {
218166
218623
  const result = db.query(`INSERT INTO meeting_sessions (title, stt_model)
218167
218624
  VALUES (?, ?)
218168
218625
  RETURNING id, title, status, stt_model, started_at`).get(title, sttModel);
218169
- log61.info(`Meeting session started: ${result.id} \u2014 "${title}"`);
218626
+ log62.info(`Meeting session started: ${result.id} \u2014 "${title}"`);
218170
218627
  return {
218171
218628
  ok: true,
218172
218629
  session_id: result.id,
@@ -218178,7 +218635,7 @@ T\xEDtulo: "${title}"
218178
218635
  Modelo STT: ${sttModel}`
218179
218636
  };
218180
218637
  } catch (error5) {
218181
- log61.error(`meeting_start error: ${error5.message}`);
218638
+ log62.error(`meeting_start error: ${error5.message}`);
218182
218639
  return { ok: false, error: `Error al iniciar la sesi\xF3n: ${error5.message}` };
218183
218640
  }
218184
218641
  }
@@ -218243,7 +218700,7 @@ Modelo STT: ${sttModel}`
218243
218700
  const seq = seqResult.next_seq;
218244
218701
  db.query(`INSERT INTO meeting_segments (session_id, seq, speaker, text, duration_ms)
218245
218702
  VALUES (?, ?, ?, ?, NULL)`).run(sessionId, seq, speaker, transcription);
218246
- log61.info(`Segment ${seq} added to session ${sessionId}: "${transcription.substring(0, 60)}..."`);
218703
+ log62.info(`Segment ${seq} added to session ${sessionId}: "${transcription.substring(0, 60)}..."`);
218247
218704
  return {
218248
218705
  ok: true,
218249
218706
  seq,
@@ -218252,7 +218709,7 @@ Modelo STT: ${sttModel}`
218252
218709
  message: speaker ? `[${speaker}]: ${transcription}` : transcription
218253
218710
  };
218254
218711
  } catch (error5) {
218255
- log61.error(`meeting_add_segment error: ${error5.message}`);
218712
+ log62.error(`meeting_add_segment error: ${error5.message}`);
218256
218713
  return {
218257
218714
  ok: false,
218258
218715
  error: `Error al agregar segmento: ${error5.message}`
@@ -218290,7 +218747,7 @@ Modelo STT: ${sttModel}`
218290
218747
  }
218291
218748
  db.query(`UPDATE meeting_sessions SET status = 'stopped', stopped_at = unixepoch() WHERE id = ?`).run(sessionId);
218292
218749
  const countResult = db.query(`SELECT COUNT(*) as count FROM meeting_segments WHERE session_id = ?`).get(sessionId);
218293
- log61.info(`Meeting session stopped: ${sessionId} \u2014 ${countResult.count} segments`);
218750
+ log62.info(`Meeting session stopped: ${sessionId} \u2014 ${countResult.count} segments`);
218294
218751
  return {
218295
218752
  ok: true,
218296
218753
  session_id: sessionId,
@@ -218302,7 +218759,7 @@ ${countResult.count} segmentos transcritos.
218302
218759
  Puedes pedir el reporte con: "Genera el reporte de la reuni\xF3n ${sessionId}"`
218303
218760
  };
218304
218761
  } catch (error5) {
218305
- log61.error(`meeting_stop error: ${error5.message}`);
218762
+ log62.error(`meeting_stop error: ${error5.message}`);
218306
218763
  return { ok: false, error: `Error al detener la sesi\xF3n: ${error5.message}` };
218307
218764
  }
218308
218765
  }
@@ -218378,7 +218835,7 @@ Puedes pedir el reporte con: "Genera el reporte de la reuni\xF3n ${sessionId}"`
218378
218835
  Luego llama a office_escribir_docx para guardar el reporte como documento Word.`
218379
218836
  };
218380
218837
  } catch (error5) {
218381
- log61.error(`meeting_report error: ${error5.message}`);
218838
+ log62.error(`meeting_report error: ${error5.message}`);
218382
218839
  return {
218383
218840
  ok: false,
218384
218841
  error: `Error al obtener el reporte: ${error5.message}`
@@ -218389,10 +218846,10 @@ Luego llama a office_escribir_docx para guardar el reporte como documento Word.`
218389
218846
  });
218390
218847
 
218391
218848
  // packages/core/src/tools/api/api-request.ts
218392
- var log62, ALLOWED_METHODS, apiRequestTool;
218849
+ var log63, ALLOWED_METHODS, apiRequestTool;
218393
218850
  var init_api_request = __esm(() => {
218394
218851
  init_logger();
218395
- log62 = logger.child("api-request");
218852
+ log63 = logger.child("api-request");
218396
218853
  ALLOWED_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"];
218397
218854
  apiRequestTool = {
218398
218855
  name: "api_request",
@@ -218458,7 +218915,7 @@ var init_api_request = __esm(() => {
218458
218915
  }
218459
218916
  url = urlObj.toString();
218460
218917
  }
218461
- log62.info(`[api_request] ${method} ${url}`);
218918
+ log63.info(`[api_request] ${method} ${url}`);
218462
218919
  const fetchOptions = {
218463
218920
  method,
218464
218921
  headers: {
@@ -218504,7 +218961,7 @@ var init_api_request = __esm(() => {
218504
218961
  response.headers.forEach((value, key) => {
218505
218962
  responseHeaders[key] = value;
218506
218963
  });
218507
- log62.info(`[api_request] ${method} ${url} \u2192 ${response.status} ${response.statusText}`);
218964
+ log63.info(`[api_request] ${method} ${url} \u2192 ${response.status} ${response.statusText}`);
218508
218965
  return {
218509
218966
  ok: response.ok,
218510
218967
  status: response.status,
@@ -218516,7 +218973,7 @@ var init_api_request = __esm(() => {
218516
218973
  };
218517
218974
  } catch (error5) {
218518
218975
  const msg = error5.message;
218519
- log62.error(`[api_request] ${method} ${url} failed: ${msg}`);
218976
+ log63.error(`[api_request] ${method} ${url} failed: ${msg}`);
218520
218977
  return {
218521
218978
  ok: false,
218522
218979
  error: `HTTP request failed: ${msg}`,