@besales/mcp 0.48.0 → 1.0.0-beta.2

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 (587) hide show
  1. package/README.md +109 -164
  2. package/README.onprem.ru.md +35 -0
  3. package/bin/besales-mcp-http.js +9 -0
  4. package/bin/besales-onprem.mjs +19 -0
  5. package/dist/auth/connection-store.d.ts +3 -1
  6. package/dist/auth/connection-store.js +9 -3
  7. package/dist/auth/connection-store.js.map +1 -1
  8. package/dist/auth/oauth-client.d.ts +20 -27
  9. package/dist/auth/oauth-client.js +31 -23
  10. package/dist/auth/oauth-client.js.map +1 -1
  11. package/dist/auth/session-workspace.d.ts +1 -0
  12. package/dist/auth/session-workspace.js +10 -1
  13. package/dist/auth/session-workspace.js.map +1 -1
  14. package/dist/auth/token-storage.js +4 -1
  15. package/dist/auth/token-storage.js.map +1 -1
  16. package/dist/cli.d.ts +1 -0
  17. package/dist/cli.js +80 -19
  18. package/dist/cli.js.map +1 -1
  19. package/dist/constants/crm-catalog.d.ts +2 -0
  20. package/dist/constants/crm-catalog.js +3 -0
  21. package/dist/constants/crm-catalog.js.map +1 -0
  22. package/dist/http/api-client.d.ts +52 -7
  23. package/dist/http/api-client.js +131 -66
  24. package/dist/http/api-client.js.map +1 -1
  25. package/dist/http/feedback-document-error.d.ts +26 -0
  26. package/dist/http/feedback-document-error.js +22 -0
  27. package/dist/http/feedback-document-error.js.map +1 -0
  28. package/dist/http-server.d.ts +15 -0
  29. package/dist/http-server.js +378 -0
  30. package/dist/http-server.js.map +1 -0
  31. package/dist/instructions/server-instructions.d.ts +1 -1
  32. package/dist/instructions/server-instructions.js +6 -3
  33. package/dist/instructions/server-instructions.js.map +1 -1
  34. package/dist/network/constants.d.ts +25 -0
  35. package/dist/network/constants.js +26 -0
  36. package/dist/network/constants.js.map +1 -0
  37. package/dist/network/failed-verifications.d.ts +10 -0
  38. package/dist/network/failed-verifications.js +37 -0
  39. package/dist/network/failed-verifications.js.map +1 -0
  40. package/dist/network/http-test-fixture.d.ts +3 -0
  41. package/dist/network/http-test-fixture.js +86 -0
  42. package/dist/network/http-test-fixture.js.map +1 -0
  43. package/dist/network/known-keys.d.ts +10 -0
  44. package/dist/network/known-keys.js +38 -0
  45. package/dist/network/known-keys.js.map +1 -0
  46. package/dist/network/memory-credentials.d.ts +11 -0
  47. package/dist/network/memory-credentials.js +24 -0
  48. package/dist/network/memory-credentials.js.map +1 -0
  49. package/dist/network/rate-limit.d.ts +23 -0
  50. package/dist/network/rate-limit.js +62 -0
  51. package/dist/network/rate-limit.js.map +1 -0
  52. package/dist/network/rejected-keys.d.ts +9 -0
  53. package/dist/network/rejected-keys.js +39 -0
  54. package/dist/network/rejected-keys.js.map +1 -0
  55. package/dist/network/request-work.d.ts +8 -0
  56. package/dist/network/request-work.js +20 -0
  57. package/dist/network/request-work.js.map +1 -0
  58. package/dist/network/successful-keys.d.ts +17 -0
  59. package/dist/network/successful-keys.js +47 -0
  60. package/dist/network/successful-keys.js.map +1 -0
  61. package/dist/resources/concepts/external-execution.md +3 -1
  62. package/dist/resources/concepts/feedback-sheets.md +21 -12
  63. package/dist/resources/concepts/icp.md +8 -1
  64. package/dist/resources/concepts/sandbox.md +15 -6
  65. package/dist/resources/concepts/triggers.md +8 -0
  66. package/dist/resources/concepts/workbook-classification.md +104 -50
  67. package/dist/resources/docs/agent-behavior.md +51 -382
  68. package/dist/resources/docs/campaigns.md +9 -16
  69. package/dist/resources/docs/crm-integration.md +39 -523
  70. package/dist/resources/docs/files-and-uploads.md +23 -286
  71. package/dist/resources/docs/follow-up.md +47 -12
  72. package/dist/resources/docs/knowledge-base.md +52 -521
  73. package/dist/resources/docs/pipeline-builder.md +26 -216
  74. package/dist/resources/docs/pipeline-settings-deep.md +27 -220
  75. package/dist/resources/docs/platforms.md +106 -519
  76. package/dist/resources/docs/prompt-anatomy.md +39 -285
  77. package/dist/resources/docs/routing.md +8 -16
  78. package/dist/resources/docs/trigger-actions.md +40 -24
  79. package/dist/resources/docs/variables.md +8 -12
  80. package/dist/resources/operator-edit.contract.d.ts +7 -0
  81. package/dist/resources/operator-edit.contract.js +8 -0
  82. package/dist/resources/operator-edit.contract.js.map +1 -0
  83. package/dist/resources/registry.js +20 -4
  84. package/dist/resources/registry.js.map +1 -1
  85. package/dist/resources/workflows/audit-dialogues.md +23 -12
  86. package/dist/resources/workflows/compare-models.md +6 -6
  87. package/dist/resources/workflows/connect-crm-from-scratch.md +15 -12
  88. package/dist/resources/workflows/connect-datasource-from-scratch.md +5 -4
  89. package/dist/resources/workflows/extract-from-document.md +8 -6
  90. package/dist/resources/workflows/operator-edit.md +15 -0
  91. package/dist/resources/workflows/platform-setup-from-scratch.md +59 -70
  92. package/dist/resources/workflows/production-readiness-check.md +25 -15
  93. package/dist/schemas/mcp-tools.json +9902 -4734
  94. package/dist/schemas/voice-actions-api.contract.json +248 -0
  95. package/dist/shared/constants/broadcast-reason.constants.d.ts +2 -0
  96. package/dist/shared/constants/broadcast-reason.constants.js +47 -0
  97. package/dist/shared/constants/broadcast-reason.constants.js.map +1 -0
  98. package/dist/shared/constants/crm-stage-pool.constants.d.ts +2 -0
  99. package/dist/shared/constants/crm-stage-pool.constants.js +3 -0
  100. package/dist/shared/constants/crm-stage-pool.constants.js.map +1 -0
  101. package/dist/shared/constants/followup-note.constants.d.ts +3 -0
  102. package/dist/shared/constants/followup-note.constants.js +4 -0
  103. package/dist/shared/constants/followup-note.constants.js.map +1 -0
  104. package/dist/shared/constants/followup-session.constants.d.ts +2 -0
  105. package/dist/shared/constants/followup-session.constants.js +3 -0
  106. package/dist/shared/constants/followup-session.constants.js.map +1 -0
  107. package/dist/shared/constants/funnel-analytics.constants.d.ts +2 -0
  108. package/dist/shared/constants/funnel-analytics.constants.js +3 -0
  109. package/dist/shared/constants/funnel-analytics.constants.js.map +1 -0
  110. package/dist/shared/constants/message-filter.constants.d.ts +7 -0
  111. package/dist/shared/constants/message-filter.constants.js +8 -0
  112. package/dist/shared/constants/message-filter.constants.js.map +1 -0
  113. package/dist/shared/utils/trigger-repeat-mapping.d.ts +72 -0
  114. package/dist/shared/utils/trigger-repeat-mapping.js +53 -0
  115. package/dist/shared/utils/trigger-repeat-mapping.js.map +1 -0
  116. package/dist/skills/besales-dialogue-audit/SKILL.md +31 -20
  117. package/dist/tasks/task-state-store.js +5 -0
  118. package/dist/tasks/task-state-store.js.map +1 -1
  119. package/dist/tools/annotations.js +4 -3
  120. package/dist/tools/annotations.js.map +1 -1
  121. package/dist/tools/definitions/agent-design.d.ts +78 -21
  122. package/dist/tools/definitions/agent-design.js +246 -90
  123. package/dist/tools/definitions/agent-design.js.map +1 -1
  124. package/dist/tools/definitions/agent-model-notice.d.ts +5 -0
  125. package/dist/tools/definitions/agent-model-notice.js +31 -0
  126. package/dist/tools/definitions/agent-model-notice.js.map +1 -0
  127. package/dist/tools/definitions/agent-models.d.ts +5 -0
  128. package/dist/tools/definitions/agent-models.js +26 -0
  129. package/dist/tools/definitions/agent-models.js.map +1 -0
  130. package/dist/tools/definitions/agent-settings.d.ts +85 -0
  131. package/dist/tools/definitions/agent-settings.js +187 -0
  132. package/dist/tools/definitions/agent-settings.js.map +1 -0
  133. package/dist/tools/definitions/ai-costs.d.ts +12 -0
  134. package/dist/tools/definitions/ai-costs.js +142 -0
  135. package/dist/tools/definitions/ai-costs.js.map +1 -0
  136. package/dist/tools/definitions/api-tool-request.d.ts +15 -0
  137. package/dist/tools/definitions/api-tool-request.js +2 -0
  138. package/dist/tools/definitions/api-tool-request.js.map +1 -0
  139. package/dist/tools/definitions/behavior-shipped-form.d.ts +182 -0
  140. package/dist/tools/definitions/behavior-shipped-form.js +185 -0
  141. package/dist/tools/definitions/behavior-shipped-form.js.map +1 -0
  142. package/dist/tools/definitions/broadcast-alerts.d.ts +6 -0
  143. package/dist/tools/definitions/broadcast-alerts.js +72 -0
  144. package/dist/tools/definitions/broadcast-alerts.js.map +1 -0
  145. package/dist/tools/definitions/broadcast-analytics.d.ts +102 -18
  146. package/dist/tools/definitions/broadcast-analytics.js +732 -431
  147. package/dist/tools/definitions/broadcast-analytics.js.map +1 -1
  148. package/dist/tools/definitions/broadcast-scheduler.d.ts +10 -13
  149. package/dist/tools/definitions/broadcast-scheduler.js +196 -154
  150. package/dist/tools/definitions/broadcast-scheduler.js.map +1 -1
  151. package/dist/tools/definitions/call-operator-task.schema.d.ts +11 -0
  152. package/dist/tools/definitions/call-operator-task.schema.js +30 -0
  153. package/dist/tools/definitions/call-operator-task.schema.js.map +1 -0
  154. package/dist/tools/definitions/contacts.d.ts +3 -0
  155. package/dist/tools/definitions/contacts.js +57 -31
  156. package/dist/tools/definitions/contacts.js.map +1 -1
  157. package/dist/tools/definitions/crm-platform.d.ts +28 -41
  158. package/dist/tools/definitions/crm-platform.js +235 -368
  159. package/dist/tools/definitions/crm-platform.js.map +1 -1
  160. package/dist/tools/definitions/crm-stage-pool.messages.d.ts +39 -0
  161. package/dist/tools/definitions/crm-stage-pool.messages.js +43 -0
  162. package/dist/tools/definitions/crm-stage-pool.messages.js.map +1 -0
  163. package/dist/tools/definitions/crm-stage-pool.schema.d.ts +64 -0
  164. package/dist/tools/definitions/crm-stage-pool.schema.js +109 -0
  165. package/dist/tools/definitions/crm-stage-pool.schema.js.map +1 -0
  166. package/dist/tools/definitions/custom-reports.d.ts +12 -0
  167. package/dist/tools/definitions/custom-reports.js +68 -0
  168. package/dist/tools/definitions/custom-reports.js.map +1 -0
  169. package/dist/tools/definitions/datasource.d.ts +2 -1
  170. package/dist/tools/definitions/datasource.js +28 -13
  171. package/dist/tools/definitions/datasource.js.map +1 -1
  172. package/dist/tools/definitions/dialog-review-findings-response.d.ts +14 -0
  173. package/dist/tools/definitions/dialog-review-findings-response.js +23 -0
  174. package/dist/tools/definitions/dialog-review-findings-response.js.map +1 -0
  175. package/dist/tools/definitions/dialog-review-safe-response.d.ts +5 -0
  176. package/dist/tools/definitions/dialog-review-safe-response.js +152 -0
  177. package/dist/tools/definitions/dialog-review-safe-response.js.map +1 -0
  178. package/dist/tools/definitions/dialog-review.d.ts +49 -0
  179. package/dist/tools/definitions/dialog-review.js +383 -0
  180. package/dist/tools/definitions/dialog-review.js.map +1 -0
  181. package/dist/tools/definitions/dialogue-analysis.d.ts +46 -0
  182. package/dist/tools/definitions/dialogue-analysis.js +170 -0
  183. package/dist/tools/definitions/dialogue-analysis.js.map +1 -0
  184. package/dist/tools/definitions/dialogue-audit-agent-scope.d.ts +7 -0
  185. package/dist/tools/definitions/dialogue-audit-agent-scope.js +41 -0
  186. package/dist/tools/definitions/dialogue-audit-agent-scope.js.map +1 -0
  187. package/dist/tools/definitions/dialogue-audit-alias.d.ts +67 -0
  188. package/dist/tools/definitions/dialogue-audit-alias.js +559 -0
  189. package/dist/tools/definitions/dialogue-audit-alias.js.map +1 -0
  190. package/dist/tools/definitions/dialogue-export.d.ts +7 -1
  191. package/dist/tools/definitions/dialogue-export.js +89 -32
  192. package/dist/tools/definitions/dialogue-export.js.map +1 -1
  193. package/dist/tools/definitions/dialogue-followup-state.d.ts +9 -0
  194. package/dist/tools/definitions/dialogue-followup-state.js +69 -0
  195. package/dist/tools/definitions/dialogue-followup-state.js.map +1 -0
  196. package/dist/tools/definitions/edit-version-transport.test-fixtures.d.ts +13 -0
  197. package/dist/tools/definitions/edit-version-transport.test-fixtures.js +292 -0
  198. package/dist/tools/definitions/edit-version-transport.test-fixtures.js.map +1 -0
  199. package/dist/tools/definitions/edit-version.d.ts +5 -0
  200. package/dist/tools/definitions/edit-version.js +20 -0
  201. package/dist/tools/definitions/edit-version.js.map +1 -0
  202. package/dist/tools/definitions/external-api-channels.js +17 -15
  203. package/dist/tools/definitions/external-api-channels.js.map +1 -1
  204. package/dist/tools/definitions/feedback-document-access.d.ts +16 -0
  205. package/dist/tools/definitions/feedback-document-access.js +63 -0
  206. package/dist/tools/definitions/feedback-document-access.js.map +1 -0
  207. package/dist/tools/definitions/fixtures/shipped-setup-status.d.ts +3 -0
  208. package/dist/tools/definitions/fixtures/shipped-setup-status.js +9 -0
  209. package/dist/tools/definitions/fixtures/shipped-setup-status.js.map +1 -0
  210. package/dist/tools/definitions/follow-up-config.d.ts +79 -0
  211. package/dist/tools/definitions/follow-up-config.js +258 -0
  212. package/dist/tools/definitions/follow-up-config.js.map +1 -0
  213. package/dist/tools/definitions/follow-up-funnel-test.d.ts +4 -3
  214. package/dist/tools/definitions/follow-up-funnel-test.js +65 -52
  215. package/dist/tools/definitions/follow-up-funnel-test.js.map +1 -1
  216. package/dist/tools/definitions/follow-up-promotion-instructions.d.ts +2 -0
  217. package/dist/tools/definitions/follow-up-promotion-instructions.js +7 -0
  218. package/dist/tools/definitions/follow-up-promotion-instructions.js.map +1 -0
  219. package/dist/tools/definitions/follow-up-setup.d.ts +4 -28
  220. package/dist/tools/definitions/follow-up-setup.js +20 -87
  221. package/dist/tools/definitions/follow-up-setup.js.map +1 -1
  222. package/dist/tools/definitions/follow-up.d.ts +20 -122
  223. package/dist/tools/definitions/follow-up.js +200 -357
  224. package/dist/tools/definitions/follow-up.js.map +1 -1
  225. package/dist/tools/definitions/followup-getcourse-compat.d.ts +29 -0
  226. package/dist/tools/definitions/followup-getcourse-compat.js +62 -0
  227. package/dist/tools/definitions/followup-getcourse-compat.js.map +1 -0
  228. package/dist/tools/definitions/followup-sequence-config.schema.d.ts +10 -0
  229. package/dist/tools/definitions/followup-sequence-config.schema.js +14 -0
  230. package/dist/tools/definitions/followup-sequence-config.schema.js.map +1 -0
  231. package/dist/tools/definitions/funnel-analytics.d.ts +18 -0
  232. package/dist/tools/definitions/funnel-analytics.js +150 -0
  233. package/dist/tools/definitions/funnel-analytics.js.map +1 -0
  234. package/dist/tools/definitions/getcourse-anchor-refresh.d.ts +5 -9
  235. package/dist/tools/definitions/getcourse-anchor-refresh.js +26 -31
  236. package/dist/tools/definitions/getcourse-anchor-refresh.js.map +1 -1
  237. package/dist/tools/definitions/getcourse-cold-outbound-settings.d.ts +46 -0
  238. package/dist/tools/definitions/getcourse-cold-outbound-settings.js +37 -0
  239. package/dist/tools/definitions/getcourse-cold-outbound-settings.js.map +1 -0
  240. package/dist/tools/definitions/getcourse-cold-welcome.d.ts +14 -29
  241. package/dist/tools/definitions/getcourse-cold-welcome.js +180 -254
  242. package/dist/tools/definitions/getcourse-cold-welcome.js.map +1 -1
  243. package/dist/tools/definitions/getcourse-wave-welcome.messages.d.ts +10 -0
  244. package/dist/tools/definitions/getcourse-wave-welcome.messages.js +17 -0
  245. package/dist/tools/definitions/getcourse-wave-welcome.messages.js.map +1 -0
  246. package/dist/tools/definitions/help.js.map +1 -1
  247. package/dist/tools/definitions/icp-import-source.d.ts +75 -0
  248. package/dist/tools/definitions/icp-import-source.js +88 -0
  249. package/dist/tools/definitions/icp-import-source.js.map +1 -0
  250. package/dist/tools/definitions/inbound-analytics.d.ts +13 -0
  251. package/dist/tools/definitions/inbound-analytics.js +55 -0
  252. package/dist/tools/definitions/inbound-analytics.js.map +1 -0
  253. package/dist/tools/definitions/instagram-comment.templates.d.ts +19 -0
  254. package/dist/tools/definitions/instagram-comment.templates.js +34 -0
  255. package/dist/tools/definitions/instagram-comment.templates.js.map +1 -0
  256. package/dist/tools/definitions/instagram-settings-compat.d.ts +33 -0
  257. package/dist/tools/definitions/instagram-settings-compat.js +7 -0
  258. package/dist/tools/definitions/instagram-settings-compat.js.map +1 -0
  259. package/dist/tools/definitions/knowledge-chunking.d.ts +42 -0
  260. package/dist/tools/definitions/knowledge-chunking.js +83 -0
  261. package/dist/tools/definitions/knowledge-chunking.js.map +1 -0
  262. package/dist/tools/definitions/knowledge-space-search-fields.d.ts +12 -0
  263. package/dist/tools/definitions/knowledge-space-search-fields.js +30 -0
  264. package/dist/tools/definitions/knowledge-space-search-fields.js.map +1 -0
  265. package/dist/tools/definitions/knowledge.d.ts +24 -14
  266. package/dist/tools/definitions/knowledge.js +342 -233
  267. package/dist/tools/definitions/knowledge.js.map +1 -1
  268. package/dist/tools/definitions/legacy-trigger-repeat.d.ts +17 -0
  269. package/dist/tools/definitions/legacy-trigger-repeat.js +53 -0
  270. package/dist/tools/definitions/legacy-trigger-repeat.js.map +1 -0
  271. package/dist/tools/definitions/link-tracking.d.ts +8 -0
  272. package/dist/tools/definitions/link-tracking.js +141 -38
  273. package/dist/tools/definitions/link-tracking.js.map +1 -1
  274. package/dist/tools/definitions/mailing-variant-content.d.ts +75 -0
  275. package/dist/tools/definitions/mailing-variant-content.js +73 -0
  276. package/dist/tools/definitions/mailing-variant-content.js.map +1 -0
  277. package/dist/tools/definitions/model-comparison.d.ts +1 -0
  278. package/dist/tools/definitions/model-comparison.js +4 -5
  279. package/dist/tools/definitions/model-comparison.js.map +1 -1
  280. package/dist/tools/definitions/money-currency.d.ts +5 -0
  281. package/dist/tools/definitions/money-currency.js +10 -0
  282. package/dist/tools/definitions/money-currency.js.map +1 -0
  283. package/dist/tools/definitions/operator-workflow.d.ts +5 -5
  284. package/dist/tools/definitions/operator-workflow.js +80 -27
  285. package/dist/tools/definitions/operator-workflow.js.map +1 -1
  286. package/dist/tools/definitions/platform-funnel-analytics.d.ts +42 -0
  287. package/dist/tools/definitions/platform-funnel-analytics.js +72 -0
  288. package/dist/tools/definitions/platform-funnel-analytics.js.map +1 -0
  289. package/dist/tools/definitions/platform-getcourse-wave-field-bindings.d.ts +42 -0
  290. package/dist/tools/definitions/platform-getcourse-wave-field-bindings.js +51 -0
  291. package/dist/tools/definitions/platform-getcourse-wave-field-bindings.js.map +1 -0
  292. package/dist/tools/definitions/platform-settings-limits.d.ts +5 -0
  293. package/dist/tools/definitions/platform-settings-limits.js +6 -0
  294. package/dist/tools/definitions/platform-settings-limits.js.map +1 -0
  295. package/dist/tools/definitions/platform-settings-shipped-form.d.ts +37 -0
  296. package/dist/tools/definitions/platform-settings-shipped-form.js +310 -0
  297. package/dist/tools/definitions/platform-settings-shipped-form.js.map +1 -0
  298. package/dist/tools/definitions/platform-settings-update.d.ts +300 -0
  299. package/dist/tools/definitions/platform-settings-update.js +134 -0
  300. package/dist/tools/definitions/platform-settings-update.js.map +1 -0
  301. package/dist/tools/definitions/{getcourse-wave.d.ts → platform-setup-wave.d.ts} +75 -6
  302. package/dist/tools/definitions/platform-setup-wave.js +1079 -0
  303. package/dist/tools/definitions/platform-setup-wave.js.map +1 -0
  304. package/dist/tools/definitions/platform-setup.d.ts +686 -224
  305. package/dist/tools/definitions/platform-setup.js +313 -752
  306. package/dist/tools/definitions/platform-setup.js.map +1 -1
  307. package/dist/tools/definitions/platform-widget-page-rules.schema.d.ts +10 -0
  308. package/dist/tools/definitions/platform-widget-page-rules.schema.js +7 -0
  309. package/dist/tools/definitions/platform-widget-page-rules.schema.js.map +1 -0
  310. package/dist/tools/definitions/prompt-authoring.constants.d.ts +2 -0
  311. package/dist/tools/definitions/prompt-authoring.constants.js +3 -0
  312. package/dist/tools/definitions/prompt-authoring.constants.js.map +1 -0
  313. package/dist/tools/definitions/prompt-batch-controls.d.ts +5 -0
  314. package/dist/tools/definitions/prompt-batch-controls.js +40 -0
  315. package/dist/tools/definitions/prompt-batch-controls.js.map +1 -0
  316. package/dist/tools/definitions/prompt-draft-authoring.d.ts +5 -0
  317. package/dist/tools/definitions/prompt-draft-authoring.js +24 -0
  318. package/dist/tools/definitions/prompt-draft-authoring.js.map +1 -0
  319. package/dist/tools/definitions/prompt-text-projection.d.ts +11 -0
  320. package/dist/tools/definitions/prompt-text-projection.js +62 -0
  321. package/dist/tools/definitions/prompt-text-projection.js.map +1 -0
  322. package/dist/tools/definitions/reviewer-paid.d.ts +19 -0
  323. package/dist/tools/definitions/reviewer-paid.js +115 -0
  324. package/dist/tools/definitions/reviewer-paid.js.map +1 -0
  325. package/dist/tools/definitions/routing-condition-projection.d.ts +31 -0
  326. package/dist/tools/definitions/routing-condition-projection.js +97 -0
  327. package/dist/tools/definitions/routing-condition-projection.js.map +1 -0
  328. package/dist/tools/definitions/schedule-selection-hints.d.ts +3 -0
  329. package/dist/tools/definitions/schedule-selection-hints.js +42 -0
  330. package/dist/tools/definitions/schedule-selection-hints.js.map +1 -0
  331. package/dist/tools/definitions/{scheduled-tasks.d.ts → scheduled-task-alias.d.ts} +12 -10
  332. package/dist/tools/definitions/scheduled-task-alias.js +207 -0
  333. package/dist/tools/definitions/scheduled-task-alias.js.map +1 -0
  334. package/dist/tools/definitions/session.js +3 -3
  335. package/dist/tools/definitions/session.js.map +1 -1
  336. package/dist/tools/definitions/setup-init-operation.schema.d.ts +2 -0
  337. package/dist/tools/definitions/setup-init-operation.schema.js +6 -0
  338. package/dist/tools/definitions/setup-init-operation.schema.js.map +1 -0
  339. package/dist/tools/definitions/shared-input.helpers.d.ts +51 -0
  340. package/dist/tools/definitions/shared-input.helpers.js +323 -0
  341. package/dist/tools/definitions/shared-input.helpers.js.map +1 -0
  342. package/dist/tools/definitions/shared.d.ts +396 -307
  343. package/dist/tools/definitions/shared.js +430 -652
  344. package/dist/tools/definitions/shared.js.map +1 -1
  345. package/dist/tools/definitions/shipped-output-names.d.ts +19 -0
  346. package/dist/tools/definitions/shipped-output-names.js +123 -0
  347. package/dist/tools/definitions/shipped-output-names.js.map +1 -0
  348. package/dist/tools/definitions/task-state.d.ts +5 -5
  349. package/dist/tools/definitions/task-state.js +2 -1
  350. package/dist/tools/definitions/task-state.js.map +1 -1
  351. package/dist/tools/definitions/telegram-personal-capacity.d.ts +4 -0
  352. package/dist/tools/definitions/telegram-personal-capacity.js +18 -0
  353. package/dist/tools/definitions/telegram-personal-capacity.js.map +1 -0
  354. package/dist/tools/definitions/telegram-pool-policy.d.ts +8 -0
  355. package/dist/tools/definitions/telegram-pool-policy.js +56 -0
  356. package/dist/tools/definitions/telegram-pool-policy.js.map +1 -0
  357. package/dist/tools/definitions/touch-history-alias.d.ts +4 -0
  358. package/dist/tools/definitions/touch-history-alias.js +99 -0
  359. package/dist/tools/definitions/touch-history-alias.js.map +1 -0
  360. package/dist/tools/definitions/trigger-action-item.schema.d.ts +254 -0
  361. package/dist/tools/definitions/trigger-action-item.schema.js +121 -0
  362. package/dist/tools/definitions/trigger-action-item.schema.js.map +1 -0
  363. package/dist/tools/definitions/trigger-argument.schema.d.ts +14 -0
  364. package/dist/tools/definitions/trigger-argument.schema.js +23 -0
  365. package/dist/tools/definitions/trigger-argument.schema.js.map +1 -0
  366. package/dist/tools/definitions/trigger-claim-alias.d.ts +10 -0
  367. package/dist/tools/definitions/trigger-claim-alias.js +90 -0
  368. package/dist/tools/definitions/trigger-claim-alias.js.map +1 -0
  369. package/dist/tools/definitions/trigger-echo-projection.d.ts +1 -0
  370. package/dist/tools/definitions/trigger-echo-projection.js +41 -0
  371. package/dist/tools/definitions/trigger-echo-projection.js.map +1 -0
  372. package/dist/tools/definitions/trigger-upsert.tool.d.ts +29 -0
  373. package/dist/tools/definitions/trigger-upsert.tool.js +122 -0
  374. package/dist/tools/definitions/trigger-upsert.tool.js.map +1 -0
  375. package/dist/tools/definitions/v15-port-descriptions.d.ts +11 -0
  376. package/dist/tools/definitions/v15-port-descriptions.js +30 -0
  377. package/dist/tools/definitions/v15-port-descriptions.js.map +1 -0
  378. package/dist/tools/definitions/variables.d.ts +44 -0
  379. package/dist/tools/definitions/variables.js +310 -0
  380. package/dist/tools/definitions/variables.js.map +1 -0
  381. package/dist/tools/definitions/voice-action-input.d.ts +9 -0
  382. package/dist/tools/definitions/voice-action-input.js +141 -0
  383. package/dist/tools/definitions/voice-action-input.js.map +1 -0
  384. package/dist/tools/definitions/widget-customization-compat.d.ts +51 -0
  385. package/dist/tools/definitions/widget-customization-compat.js +23 -0
  386. package/dist/tools/definitions/widget-customization-compat.js.map +1 -0
  387. package/dist/tools/definitions.d.ts +1089 -636
  388. package/dist/tools/definitions.js +57 -27
  389. package/dist/tools/definitions.js.map +1 -1
  390. package/dist/tools/description-localization.js +3 -2
  391. package/dist/tools/description-localization.js.map +1 -1
  392. package/dist/tools/follow-up-request.d.ts +19 -0
  393. package/dist/tools/follow-up-request.js +81 -0
  394. package/dist/tools/follow-up-request.js.map +1 -0
  395. package/dist/tools/followup-revision.d.ts +4 -0
  396. package/dist/tools/followup-revision.js +29 -0
  397. package/dist/tools/followup-revision.js.map +1 -0
  398. package/dist/tools/incomplete-list.js +4 -0
  399. package/dist/tools/incomplete-list.js.map +1 -1
  400. package/dist/tools/inventory.js +47 -11
  401. package/dist/tools/inventory.js.map +1 -1
  402. package/dist/tools/operation-recovery.d.ts +4 -0
  403. package/dist/tools/operation-recovery.js +33 -0
  404. package/dist/tools/operation-recovery.js.map +1 -0
  405. package/dist/tools/registry-mapping-primary.cases.d.ts +2 -0
  406. package/dist/tools/registry-mapping-primary.cases.js +753 -0
  407. package/dist/tools/registry-mapping-primary.cases.js.map +1 -0
  408. package/dist/tools/registry-mapping-secondary.cases.d.ts +2 -0
  409. package/dist/tools/registry-mapping-secondary.cases.js +626 -0
  410. package/dist/tools/registry-mapping-secondary.cases.js.map +1 -0
  411. package/dist/tools/registry-mapping.cases.d.ts +8 -0
  412. package/dist/tools/registry-mapping.cases.js +13 -0
  413. package/dist/tools/registry-mapping.cases.js.map +1 -0
  414. package/dist/tools/registry-test-fixtures.d.ts +50 -0
  415. package/dist/tools/registry-test-fixtures.js +120 -0
  416. package/dist/tools/registry-test-fixtures.js.map +1 -0
  417. package/dist/tools/registry.d.ts +2 -0
  418. package/dist/tools/registry.js +82 -52
  419. package/dist/tools/registry.js.map +1 -1
  420. package/dist/tools/result.d.ts +1 -0
  421. package/dist/tools/result.js +90 -22
  422. package/dist/tools/result.js.map +1 -1
  423. package/dist/tools/toolsets.d.ts +16 -0
  424. package/dist/tools/toolsets.js +25 -1
  425. package/dist/tools/toolsets.js.map +1 -1
  426. package/dist/types/api-contract.gen.d.ts +105875 -22205
  427. package/dist/utils/credential-signatures.d.ts +3 -0
  428. package/dist/utils/credential-signatures.js +10 -0
  429. package/dist/utils/credential-signatures.js.map +1 -0
  430. package/dist/utils/data-source-column-name.d.ts +10 -0
  431. package/dist/utils/data-source-column-name.js +36 -0
  432. package/dist/utils/data-source-column-name.js.map +1 -0
  433. package/dist/utils/logger.d.ts +1 -0
  434. package/dist/utils/logger.js +32 -8
  435. package/dist/utils/logger.js.map +1 -1
  436. package/dist/utils/secret-read-boundary.d.ts +2 -0
  437. package/dist/utils/secret-read-boundary.js +88 -0
  438. package/dist/utils/secret-read-boundary.js.map +1 -0
  439. package/dist/utils/setup-secrets.d.ts +4 -0
  440. package/dist/utils/setup-secrets.js +40 -0
  441. package/dist/utils/setup-secrets.js.map +1 -0
  442. package/docs/agent-models.md +9 -0
  443. package/docs/agent-usage-guide.full.ru.md +1 -4
  444. package/docs/analytics-contract.md +67 -0
  445. package/docs/async-operation-lifecycle.md +10 -3
  446. package/docs/connect.ru.md +144 -4
  447. package/docs/contact-company-profile.md +17 -0
  448. package/docs/contact-recommendations.md +7 -0
  449. package/docs/crm-stage-pool.md +73 -0
  450. package/docs/customer-data.md +61 -0
  451. package/docs/edit-versions.md +36 -0
  452. package/docs/failure-semantics.md +17 -9
  453. package/docs/help-navigation.md +15 -42
  454. package/docs/host-compatibility-matrix.md +72 -93
  455. package/docs/host-setup.md +33 -35
  456. package/docs/invariants/public-api-and-contracts.md +16 -0
  457. package/docs/legacy-action-settings.md +21 -0
  458. package/docs/main-transfer-dependencies.md +38 -0
  459. package/docs/mcp2-parity.md +50 -0
  460. package/docs/modules/analytics.md +79 -0
  461. package/docs/modules/besales-mcp.md +137 -0
  462. package/docs/modules/dialog-review-report.md +38 -0
  463. package/docs/modules/dialogue-followup-adapters.md +39 -0
  464. package/docs/modules/message-reactions.md +17 -0
  465. package/docs/modules/network-mode.md +284 -0
  466. package/docs/modules/prompt-batch-and-dialogue-controls.md +69 -0
  467. package/docs/pii-policy.md +21 -16
  468. package/docs/response-size-budget.md +197 -7
  469. package/docs/secret-read-boundary.md +102 -0
  470. package/docs/task-state.md +7 -2
  471. package/docs/telegram-pool-policy.md +19 -0
  472. package/docs/tool-effects.md +15 -9
  473. package/docs/tool-surface.md +205 -4
  474. package/docs/voice-actions-and-inbox.md +95 -0
  475. package/docs/wazzup-instagram-comments.md +26 -0
  476. package/package.json +17 -10
  477. package/scripts/api-source-loader.spec.mjs +40 -0
  478. package/scripts/audit-bridge-controls.mjs +129 -0
  479. package/scripts/audit-revert-mutants.mjs +107 -0
  480. package/scripts/bridge-api-input.spec.mjs +98 -0
  481. package/scripts/bridge-controls-mutants.mjs +130 -0
  482. package/scripts/brx3-shipped-refusals.spec.mjs +149 -0
  483. package/scripts/brx4-ledger-payload.spec.mjs +127 -0
  484. package/scripts/build-onprem.mjs +108 -0
  485. package/scripts/connect-clients.sh +141 -0
  486. package/scripts/connect-scopes.mjs +166 -0
  487. package/scripts/connect-scopes.spec.mjs +83 -0
  488. package/scripts/emit-personal-link-carrier.mjs +31 -0
  489. package/scripts/emit-setup-init-schemas.mjs +24 -0
  490. package/scripts/emit-tool-routes.mjs +878 -0
  491. package/scripts/emit-tool-routes.spec.mjs +300 -0
  492. package/scripts/followup-registry.spec.mjs +107 -0
  493. package/scripts/generate-crm-rotation-contract.mjs +98 -0
  494. package/scripts/generate-followup-session-contract.mjs +16 -0
  495. package/scripts/icp-import-verification/mutate.cjs +70 -0
  496. package/scripts/import-secret-read-contract.mjs +53 -0
  497. package/scripts/install-claude-desktop.js +1 -1
  498. package/scripts/lag-decisions.mjs +37 -0
  499. package/scripts/lag-decisions.spec.mjs +87 -0
  500. package/scripts/lag-open-task-owners.mjs +46 -0
  501. package/scripts/lag-open-task-owners.spec.mjs +78 -0
  502. package/scripts/lag-payload.mjs +10 -0
  503. package/scripts/legacy-action-lag.spec.mjs +22 -0
  504. package/scripts/legacy-field-refusal.shipped.spec.mjs +99 -0
  505. package/scripts/mcpcompat-handler.mjs +34 -0
  506. package/scripts/mcpcompat-loader.mjs +36 -0
  507. package/scripts/mcpcompat-typescript.mjs +3 -0
  508. package/scripts/platform-settings-shipped-parity.spec.mjs +89 -0
  509. package/scripts/prbr-round1-recheck.spec.mjs +605 -0
  510. package/scripts/prbr-shipped-compatibility.spec.mjs +276 -0
  511. package/scripts/publish-mcp-registry.mjs +98 -0
  512. package/scripts/publish-mcp-registry.spec.mjs +68 -0
  513. package/scripts/record-scheduled-task-call.mjs +26 -0
  514. package/scripts/refusal-probe.mjs +17 -0
  515. package/scripts/refusal-probe.spec.mjs +29 -0
  516. package/scripts/registry-diff.mjs +502 -0
  517. package/scripts/registry-diff.spec.mjs +787 -0
  518. package/scripts/request-query.mjs +43 -0
  519. package/scripts/request-query.spec.mjs +82 -0
  520. package/scripts/route-lag.mjs +23 -0
  521. package/scripts/route-lag.spec.mjs +30 -0
  522. package/scripts/sample-args.mjs +174 -0
  523. package/scripts/sample-args.spec.mjs +160 -0
  524. package/scripts/shipped-definitions.mjs +197 -0
  525. package/scripts/shipped-definitions.spec.mjs +57 -0
  526. package/scripts/shipped-inputs.spec.mjs +136 -0
  527. package/scripts/shipped-recordings.spec.mjs +19 -0
  528. package/scripts/shipped-ref.d.mts +5 -0
  529. package/scripts/shipped-ref.mjs +20 -0
  530. package/scripts/shipped-ref.spec.mjs +59 -0
  531. package/scripts/shipped-registry.mjs +107 -0
  532. package/scripts/shipped-sample-candidates.mjs +69 -0
  533. package/scripts/shipped-sample-candidates.spec.mjs +117 -0
  534. package/scripts/shipped-sample.mjs +868 -0
  535. package/scripts/shipped-sample.spec.mjs +451 -0
  536. package/scripts/sync-agent-model-schemas.mjs +72 -0
  537. package/scripts/sync-api-contracts.mjs +85 -0
  538. package/scripts/sync-api-contracts.spec.mjs +144 -0
  539. package/scripts/sync-contract-ledger-schemas.mjs +161 -0
  540. package/scripts/sync-crm-stage-pool-schema.mjs +85 -0
  541. package/scripts/sync-prompt-draft-schema.mjs +92 -0
  542. package/scripts/sync-route-map.mjs +94 -0
  543. package/scripts/sync-schema-descriptions.mjs +25 -0
  544. package/scripts/sync-tool-inventory.mjs +27 -0
  545. package/scripts/sync-trigger-argument-schema.mjs +121 -0
  546. package/scripts/sync-trigger-repeat-mapping.mjs +12 -0
  547. package/scripts/sync-voice-actions-contract.mjs +67 -0
  548. package/scripts/sync-voice-actions-tools.mjs +97 -0
  549. package/scripts/sync-wave-id-schemas.mjs +55 -0
  550. package/scripts/tool-input-schemas.mjs +46 -0
  551. package/scripts/tool-input-schemas.spec.mjs +50 -0
  552. package/scripts/verify-followup-adapters.mjs +235 -0
  553. package/scripts/verify-secret-read-import.mjs +84 -0
  554. package/scripts/verify-secret-read-mutants.mjs +143 -0
  555. package/dist/tools/definitions/analytics.d.ts +0 -40
  556. package/dist/tools/definitions/analytics.js +0 -233
  557. package/dist/tools/definitions/analytics.js.map +0 -1
  558. package/dist/tools/definitions/broadcast-mailing-variants.d.ts +0 -41
  559. package/dist/tools/definitions/broadcast-mailing-variants.js +0 -194
  560. package/dist/tools/definitions/broadcast-mailing-variants.js.map +0 -1
  561. package/dist/tools/definitions/dialogue-audit.d.ts +0 -38
  562. package/dist/tools/definitions/dialogue-audit.js +0 -292
  563. package/dist/tools/definitions/dialogue-audit.js.map +0 -1
  564. package/dist/tools/definitions/getcourse-wave.js +0 -519
  565. package/dist/tools/definitions/getcourse-wave.js.map +0 -1
  566. package/dist/tools/definitions/operational-overview.d.ts +0 -3
  567. package/dist/tools/definitions/operational-overview.js +0 -23
  568. package/dist/tools/definitions/operational-overview.js.map +0 -1
  569. package/dist/tools/definitions/scheduled-tasks.js +0 -173
  570. package/dist/tools/definitions/scheduled-tasks.js.map +0 -1
  571. package/dist/tools/definitions/trigger-contact-claims.d.ts +0 -7
  572. package/dist/tools/definitions/trigger-contact-claims.js +0 -60
  573. package/dist/tools/definitions/trigger-contact-claims.js.map +0 -1
  574. package/dist/tools/registry-mapping-cases-core.d.ts +0 -38
  575. package/dist/tools/registry-mapping-cases-core.js +0 -963
  576. package/dist/tools/registry-mapping-cases-core.js.map +0 -1
  577. package/dist/tools/registry-mapping-cases-platform.d.ts +0 -2
  578. package/dist/tools/registry-mapping-cases-platform.js +0 -1052
  579. package/dist/tools/registry-mapping-cases-platform.js.map +0 -1
  580. package/dist/tools/trigger-action-config.d.ts +0 -49
  581. package/dist/tools/trigger-action-config.js +0 -171
  582. package/dist/tools/trigger-action-config.js.map +0 -1
  583. package/docs/evals/model-behavior-scorecard.md +0 -80
  584. package/docs/operation-coverage.md +0 -114
  585. package/scripts/mock-credentials.js +0 -77
  586. package/scripts/model-eval-server.js +0 -213
  587. package/scripts/run-model-eval.js +0 -447
@@ -1,405 +1,248 @@
1
1
  import { z } from 'zod';
2
- import { buildListQuery, defineTool, uuidSchema, withInstructions, } from './shared.js';
2
+ import { crmStagePoolMessage } from './crm-stage-pool.messages.js';
3
+ import { assertCompleteList } from '../incomplete-list.js';
4
+ import { FOLLOWUP_SEQUENCES_MAX_PAGE_SIZE, buildListQuery, defineTool, uuidSchema, withInstructions, } from './shared.js';
3
5
  /**
4
- * Схема конфига реактивационной цепочки.
6
+ * Календарная дата разреза. Время суток здесь бессмысленно: сутки считаются в поясе канала.
5
7
  *
6
- * ⚠️ Ключи ВНУТРИ `config` — camelCase, в отличие от snake_case параметров тулов: `config`
7
- * уходит в тело запроса БЕЗ преобразования, а рантайм читает `anchorMode`/`anchorVariable`/
8
- * `slotGroup`. Назвать их в snake_case значило бы сохранить конфиг, который рантайм не
9
- * прочитает: календарный шаг молча стал бы обычным offset-шагом.
8
+ * Проверяется не только форма, но и СУЩЕСТВОВАНИЕ дня: `2026-02-31` форму проходит, а приведение
9
+ * к дате на стороне базы роняет весь запрос. Отказ здесь понятнее отказа оттуда.
10
+ */
11
+ const calendarDateSchema = z
12
+ .string()
13
+ .regex(/^\d{4}-\d{2}-\d{2}$/u)
14
+ .refine((value) => {
15
+ // Разбор ISO-строки, а НЕ `Date.UTC(год, месяц, день)`: второй трактует год меньше 100 как
16
+ // 19xx, и `0099-01-01` — существующая дата — отвергался бы как несуществующая.
17
+ const parsed = new Date(`${value}T00:00:00.000Z`);
18
+ return !Number.isNaN(parsed.getTime()) && parsed.toISOString().slice(0, 10) === value;
19
+ }, 'Такой календарной даты не существует');
20
+ /** Момент С часовым поясом: момент без пояса сервер отвергает, иначе его читал бы пояс процесса. */
21
+ const momentWithOffsetSchema = z
22
+ .string()
23
+ .regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,6})?)?(?:Z|[+-]\d{2}:\d{2})$/u)
24
+ .refine((value) => !Number.isNaN(Date.parse(value)), 'Такого момента не существует');
25
+ /**
26
+ * Граница периода статистики шагов: дата `ГГГГ-ММ-ДД` (сутки в поясе канала, у конца включается весь день) — форма
27
+ * отгруженного инструмента — либо момент с часовым поясом.
28
+ */
29
+ const stepStatsBoundSchema = z.union([calendarDateSchema, momentWithOffsetSchema]);
30
+ /**
31
+ * Закрытый набор горизонтов сравнительной метрики. Свободное число позволяло бы подобрать окно
32
+ * под нужный ответ, поэтому один и тот же список держат и сервер, и мост.
33
+ */
34
+ export const REACTION_HORIZONS = [30, 60, 90, 180, 360, 720, 1440];
35
+ export const REACTION_RUN_WINDOW_DAYS = [1, 3, 5, 7, 14];
36
+ const reactionRunWindowSchema = z.union([
37
+ z.literal(REACTION_RUN_WINDOW_DAYS[0]),
38
+ z.literal(REACTION_RUN_WINDOW_DAYS[1]),
39
+ z.literal(REACTION_RUN_WINDOW_DAYS[2]),
40
+ z.literal(REACTION_RUN_WINDOW_DAYS[3]),
41
+ z.literal(REACTION_RUN_WINDOW_DAYS[4]),
42
+ ]);
43
+ const reactionHorizonSchema = z.union([
44
+ z.literal(REACTION_HORIZONS[0]),
45
+ z.literal(REACTION_HORIZONS[1]),
46
+ z.literal(REACTION_HORIZONS[2]),
47
+ z.literal(REACTION_HORIZONS[3]),
48
+ z.literal(REACTION_HORIZONS[4]),
49
+ z.literal(REACTION_HORIZONS[5]),
50
+ z.literal(REACTION_HORIZONS[6]),
51
+ ]);
52
+ /**
53
+ * Метки транспорта волны — ровно те, что живут в перечислении базы и приходят в
54
+ * `dimensions.transports` ответа. Регистр ВЕРХНИЙ и он несущий: сервер приводит фильтр к типу
55
+ * перечисления, поэтому посторонняя строка даёт отказ базы, а не пустой разрез.
10
56
  *
11
- * ⚠️ `.passthrough()` на каждом уровне обязателен по двум причинам: legacy-конфиги несут поля
12
- * вне этой схемы (`finalAction`, `maxCycleCount`, `webhookConfig`, …), и сама схема исполняется
13
- * на машине оператора — она обновляется независимо от бэкенда и не должна отвергать конфиг,
14
- * который бэкенд принял бы.
57
+ * ⛔ Отгруженная схема перечисляла их как `Telegram, WhatsApp, MAX, VK` — в v1.5 это работало,
58
+ * в v2 два значения из четырёх неверны. Списано с отгруженного описания без проверки против
59
+ * перечисления v2; поймали обе линии ворот.
15
60
  */
16
- const variableConditionSchema = z
17
- .object({
18
- variable: z.string().describe('Имя per-contact переменной'),
19
- op: z.enum(['eq', 'neq', 'in']),
20
- value: z
21
- .union([z.string(), z.array(z.string())])
22
- .describe("Строка для eq/neq, непустой массив непустых строк для 'in'"),
23
- })
24
- .passthrough();
61
+ // Этот набор сверяется с контрактом в wave-transports.spec.ts; трогая его, смотри туда.
62
+ export const WAVE_TRANSPORTS = [
63
+ 'SITE',
64
+ 'EMAIL',
65
+ 'SMS',
66
+ 'TELEGRAM',
67
+ 'FACEBOOK',
68
+ 'VK',
69
+ 'CHATIUM',
70
+ 'WHATSAPP',
71
+ 'VIBER',
72
+ 'MAX',
73
+ ];
25
74
  /**
26
- * Сообщение шага. Поля перечислены поимённо не ради валидации, а ради ОБНАРУЖИМОСТИ: раньше
27
- * здесь стоял безымянный объект, и «как задать в шаге WABA-шаблон вместо текста» неоткуда было
28
- * узнать — форма не описана ни в схеме тула, ни в OpenAPI.
75
+ * Регистр приводится, а значение — нет.
29
76
  *
30
- * `.passthrough()` обязателен: конфиги несут поля вне этого списка (wabaVariableMapping и др.),
31
- * а схема живёт на машине оператора и обновляется независимо от бэкенда.
77
+ * Отгруженный клиент шлёт `Telegram`, и отказывать ему было бы поломкой работающего вызова:
78
+ * значение то же, отличается только написание. А вот незнакомый транспорт отвергается здесь же —
79
+ * иначе он дошёл бы до приведения к перечислению и обрушил весь запрос.
32
80
  */
33
- const followUpMessageConfigSchema = z
34
- .object({
35
- type: z
36
- .string()
37
- .nullish()
38
- .describe("'text' — обычный текст в content; 'template' — ШАБЛОН WABA (Wazzup), тогда обязателен " +
39
- "templateId; 'media' — вложения. Шаблон уходит и при ЗАКРЫТОМ 24-часовом окне " +
40
- 'переписки, обычный текст — нет (шаг молча ждёт реплики клиента)'),
41
- content: z.string().nullish().describe('Текст для type=text'),
42
- templateId: z
43
- .string()
44
- .nullish()
45
- .describe('ID шаблона WABA. Берётся из besales_wazzup_templates_list — это id шаблона канала, ' +
46
- 'а не его имя'),
47
- templateValues: z
48
- .array(z.unknown())
49
- .nullish()
50
- .describe('Значения подстановок шаблона по порядку ({{1}}, {{2}}, …). Поддерживают переменные ' +
51
- 'контакта — они резолвятся перед отправкой'),
52
- contentMode: z
53
- .string()
54
- .nullish()
55
- .describe("'static' (по умолчанию) либо 'dynamic' — текст генерирует LLM"),
56
- generationContext: z.string().nullish().describe('Инструкция LLM при contentMode=dynamic'),
57
- fallbackContent: z.string().nullish().describe('Запасной текст, если генерация не удалась'),
58
- attachments: z
59
- .array(z.unknown())
60
- .nullish()
61
- .describe('Вложения: [{ storedFileId, caption? }]'),
62
- buttons: z.array(z.unknown()).nullish(),
63
- crmNote: z.string().nullish(),
64
- })
65
- .passthrough();
66
- const reactivationStepSchema = z
67
- .object({
68
- stepType: z.enum(['message', 'webhook']).optional(),
69
- scheduleMode: z
70
- .enum(['offset', 'clock'])
71
- .optional()
72
- .describe("'clock' — время суток + сдвиг дней вместо задержки от последней активности"),
73
- anchorMode: z
74
- .enum(['last_inbound', 'variable'])
75
- .optional()
76
- .describe("'variable' — расписание считается от даты из переменной контакта (календарная цепочка)"),
77
- anchorVariable: z
78
- .string()
79
- .optional()
80
- .describe('Имя переменной с якорной датой. Обязательно при anchorMode=variable; переменная должна ' +
81
- 'существовать у платформы и НЕ быть константой'),
82
- atTime: z.string().optional().describe('Время суток "HH:MM" для scheduleMode=clock'),
83
- // ⚠️ Нижняя граница — зеркало бэкенда (`MIN_CLOCK_DAY_OFFSET = -7`): отрицательный сдвиг —
84
- // касание ДО якоря («накануне эфира»). С `min(0)` MCP не мог пересохранить ни одну цепочку с
85
- // такими шагами (21.09.2026: «Светлана» с шагами dayOffset -1 отвергалась целиком).
86
- dayOffset: z
87
- .number()
88
- .int()
89
- .min(-7)
90
- .max(30)
91
- .optional()
92
- .describe('Сдвиг в днях от якоря для scheduleMode=clock; отрицательный — до якоря'),
93
- validityMinutes: z
94
- .number()
95
- .optional()
96
- .describe('Окно валидности слота. Крон ходит раз в 5 минут: окно меньше 5 минут он почти всегда пропустит'),
97
- slotGroup: z
98
- .string()
99
- .optional()
100
- .describe('Метка взаимоисключающих вариантов одного момента (first-match-wins). Варианты ОБЯЗАНЫ ' +
101
- 'идти в steps подряд: разнесённые по цепочке перестают быть взаимоисключающими'),
102
- conditions: z
103
- .array(variableConditionSchema)
104
- .max(3)
105
- .optional()
106
- .describe('Условия на переменные контакта; не прошли — шаг пропускается'),
107
- skipIfContactRepliedSincePreviousSlot: z.boolean().optional().describe("Не отправлять шаг, если клиент писал ПОСЛЕ предыдущего слота цепочки. Даёт правило «ответил — ближайшее касание пропускаем, через одно продолжаем»: ответ в 13:05 гасит касание в 16:00, а к 17:00 предыдущим слотом становится 16:00, ответ старше него — и цепочка идёт дальше. Прогресс при пропуске двигается, контакт не зависает. Только для календарного шага (scheduleMode=clock + anchorMode=variable): на остальных рантайм и так проверяет свежесть входящего, и флаг там отвергается."),
108
- delayHours: z.number().optional(),
109
- delayMinutes: z.number().optional(),
110
- messageConfig: followUpMessageConfigSchema.optional(),
111
- getcourse: z
112
- .object({
113
- delivery: z
114
- .object({
115
- mode: z.enum(['contact', 'all', 'explicit']),
116
- transports: z
117
- .array(z.enum([
118
- 'Site',
119
- 'Email',
120
- 'SMS',
121
- 'Telegram',
122
- 'Facebook',
123
- 'VK',
124
- 'Chatium',
125
- 'WhatsApp',
126
- 'Viber',
127
- 'MAX',
128
- ]))
129
- .optional()
130
- .describe("Только для mode='explicit'; в остальных режимах бэкенд отвергнет поле"),
131
- })
132
- .passthrough()
133
- .optional(),
134
- })
135
- .passthrough()
136
- .optional()
137
- .describe('Каналы отправки ШАГА, только GetCourse. По умолчанию (поля нет) набор решает состояние ' +
138
- "контакта: ответил — ровно его канал, молчит — все его привязки. 'all' — привязки плюс " +
139
- 'канал ответа плюс Email/Сайт/Chatium; SMS в него НЕ входит (один текст на весь набор, ' +
140
- "нужен свой короткий) и задаётся только через 'explicit' отдельным шагом. Пустое " +
141
- 'пересечение с разрешёнными каналами площадки — шаг пропускается, цепочка идёт дальше. ' +
142
- 'К шагу-вебхуку неприменимо'),
143
- })
144
- .passthrough()
145
- // ⚠️ Зеркалит правила бэкенда, чтобы промах ловился ЛОКАЛЬНО. Иначе вызов проходит нашу
146
- // проверку, пользователь подтверждает запись, и только сервер отвечает 400 — самый дорогой
147
- // момент, чтобы узнать про опечатку.
148
- .superRefine((step, ctx) => {
149
- const message = step.messageConfig;
150
- const isDynamic = message?.contentMode === 'dynamic';
151
- const hasAttachments = !!message?.attachments?.length;
152
- if (message?.type === 'template' && !message.templateId) {
153
- ctx.addIssue({
154
- code: z.ZodIssueCode.custom,
155
- path: ['messageConfig', 'templateId'],
156
- message: 'Для type=template обязателен templateId (id шаблона из besales_wazzup_templates_list)',
157
- });
158
- }
159
- if (message?.type === 'text' && !message.content && !isDynamic && !hasAttachments) {
160
- ctx.addIssue({
161
- code: z.ZodIssueCode.custom,
162
- path: ['messageConfig', 'content'],
163
- message: 'Для type=text обязателен content — кроме шага из одних вложений и contentMode=dynamic',
164
- });
165
- }
166
- const delivery = step.getcourse?.delivery;
167
- if (!delivery)
168
- return;
169
- if (step.stepType === 'webhook') {
170
- ctx.addIssue({
171
- code: z.ZodIssueCode.custom,
172
- path: ['getcourse', 'delivery'],
173
- message: 'Набор каналов неприменим к шагу-вебхуку: он ничего не отправляет клиенту',
174
- });
175
- return;
176
- }
177
- if (delivery.mode !== 'explicit') {
178
- if (delivery.transports !== undefined) {
179
- ctx.addIssue({
180
- code: z.ZodIssueCode.custom,
181
- path: ['getcourse', 'delivery', 'transports'],
182
- message: `Список каналов допустим только при mode='explicit'; в режиме '${delivery.mode}' он был бы проигнорирован`,
183
- });
184
- }
185
- return;
186
- }
187
- if (!delivery.transports?.length) {
188
- ctx.addIssue({
189
- code: z.ZodIssueCode.custom,
190
- path: ['getcourse', 'delivery', 'transports'],
191
- message: "Для mode='explicit' нужен непустой список каналов — иначе шаг не отправит ничего",
192
- });
193
- return;
194
- }
195
- // Один `commentText` на весь набор: длинный мессенджерный текст уехал бы в SMS целиком.
196
- if (delivery.transports.includes('SMS') && delivery.transports.length > 1) {
197
- ctx.addIssue({
198
- code: z.ZodIssueCode.custom,
199
- path: ['getcourse', 'delivery', 'transports'],
200
- message: 'SMS нельзя смешивать с другими каналами: у отправки один текст на весь набор. Вынесите SMS отдельным шагом со своим коротким текстом',
201
- });
202
- }
203
- });
204
- export const reactivationConfigSchema = z
205
- .object({
206
- enabled: z.boolean().optional(),
207
- filterMode: z
208
- .enum(['status', 'eventType', 'variable'])
209
- .optional()
210
- .describe('БАЗОВЫЙ отбор контактов: по статусу CRM, по типу события платформы либо ' +
211
- "'variable' = базового фильтра нет (отбор только по sequenceConditions). Условия по " +
212
- 'переменным ОРТОГОНАЛЬНЫ этому выбору и добавляются к нему через И — чтобы ветвить ' +
213
- "цепочки по варианту рассылки, сохранив отбор по событию, бери 'eventType' и задай " +
214
- "sequenceConditions, а НЕ 'variable'. Неизвестное значение НЕ включает ни один фильтр — " +
215
- 'цепочка уйдёт всем контактам канала, поэтому бэкенд отвергает такой конфиг'),
216
- sequenceConditions: z
217
- .array(variableConditionSchema)
218
- .optional()
219
- .describe('Условия принадлежности контакта цепочке, соединяются через И. Применяются при ЛЮБОМ ' +
220
- "filterMode (при 'variable' обязателен и непуст, иначе цепочка не выберет никого). " +
221
- 'Ветвление по измерениям рассылки GetCourse: WAVE_MAILING_VARIANT — UUID варианта из ' +
222
- 'каталога воркспейса, а НЕ его имя («first-ver» будет отвергнут); WAVE_PRODUCT — код ' +
223
- 'продукта строчными без пробелов («dbo»); WAVE_FUNNEL — КЛЮЧ воронки (f-код «f11», ' +
224
- 'иначе вся строка строчными), а НЕ метка запуска («f11 — ВК NR ДБО» будет отвергнут); ' +
225
- 'WAVE_SEGMENT — имя сегмента. Значения проставляет запуск рассылки, у контакта без ' +
226
- 'рассылки их нет. ' +
227
- 'ВАЖНО: отдельные цепочки НЕ взаимоисключающи — прогресс изолирован по sequenceId, ' +
228
- 'поэтому безусловная «ловящая» цепочка рядом с eq A и eq B не подстрахует, а УДВОИТ ' +
229
- 'отправку. Набор цепочек обязан быть строгим разбиением: eq A, eq B и fallback ' +
230
- 'neq A AND neq B (у контакта без переменной eq/in → false, neq → true)'),
231
- steps: z.array(reactivationStepSchema).min(1),
232
- sessionTimeVariable: z.string().min(1).optional().describe("ИМЯ переменной контакта с ЧАСОМ события (ЧЧ:ММ), парное к anchorVariable шага, который задаёт ДАТУ. Нужно потому, что поле-якорь во внешней CRM хранит только дату, а разбор нормализует её в служебный ПОЛДЕНЬ: без этого поля агент в своём промпте видит «Эфир: 21.08.2026 12:00» при эфире в 19:00. Задаётся НА ЦЕПОЧКУ (час слота одинаков для всех касаний и всех дней — dayOffset сдвигает дату, не час). Хранится ИМЯ, а не сам час: цепочка отбирает контактов условием по этой же переменной, и вторая копия значения разошлась бы с отбором молча. На расписание НЕ влияет — его задают atTime шагов; поле читает только промпт агента. Значение у контакта вне ЧЧ:ММ игнорируется: печатается одна дата, выдуманный час не подставляется."),
233
- sessionDayOffsets: z.array(z.number().int().min(0).max(30)).min(1).optional().describe("На каких dayOffset цепочки проходят САМИ эфиры ([0,1,2] — три дня подряд от якоря). Вывести из шагов нельзя: касания стоят и на днях без эфира (у вебинарной цепочки шаги занимают дни 0–5, а эфиров три — дни 4 и 5 это продажа), поэтому дни объявляются явно, как явно объявлено время в sessionTimeVariable. На расписание НЕ влияет — его задают atTime/dayOffset шагов; поле читает только промпт агента. Без объявления блок печатает ОДИН эфир по якорю: якорь несёт дату лишь ПЕРВОГО эфира, и на второй день агент видел «был вчера», не зная, что сегодня вечером эфир есть. Порядок задаёт нумерацию («эфир 2 из 3») и нормализуется по возрастанию."),
234
- sessionDurationMinutes: z.number().int().positive().max(1440).optional().describe("Сколько минут длится эфир. Объявляется, ТОЛЬКО если длительность действительно известна: с ней блок промпта утверждает «идёт сейчас» и перестаёт это утверждать по её истечении, без неё — только «уже начался», то есть факт, который нельзя опровергнуть временем. Дефолта нет намеренно: подставленная длительность это утверждение о мире, сделанное за клиента, а такие утверждения агент пересказывает человеку. Читается только при объявленном sessionDayOffsets."),
235
- contactVariablesOnSend: z
236
- .record(z.string().min(1), z.string().min(1).max(500))
237
- .refine((value) => Object.keys(value).length > 0 && Object.keys(value).length <= 10, {
238
- message: 'от 1 до 10 переменных',
239
- })
240
- .optional()
241
- .describe("Переменные, которые цепочка ЗАПИСЫВАЕТ контакту, как только РЕАЛЬНО отправила ему шаг-сообщение: { intro: \"это снова Светлана.\" }. Это «записка» для тех, кто будет писать человеку после цепочки. Рабочий пример — фраза знакомства: текст рассылки начинается с {intro}, у площадки рассылки объявлена КОНСТАНТА intro с обычной фразой («здравствуйте! Это Светлана, помощница…»), а цепочка персональной воронки пишет своим людям intro = «это снова Светлана…» — значение контакта в тексте рассылки побеждает умолчание, и человек после недели в воронке не получает знакомство заново. Настраивается НА ЦЕПОЧКУ, а не на шаг: шага, который доходит до всех, нет (лучший — 87 % людей), а запись на любом отправленном шаге покрывает 99 %. Пишется только после ПОДТВЕРЖДЁННОЙ отправки шага-сообщения (вебхук и неудавшаяся отправка не считаются); совпадающее значение повторно не пишется. Каждое имя обязано быть объявлено на площадке цепочки переменной КОНТАКТА (не константой) — иначе сохранение вернёт 400: при отправке опечатка была бы тихой. Не больше 10 переменных, значение — непустая строка до 500 символов (границы бэкенда MAX_CONTACT_VARIABLES_ON_SEND / MAX_CONTACT_VARIABLE_ON_SEND_VALUE_LENGTH)."),
242
- })
243
- .passthrough();
81
+ const waveTransportSchema = z.preprocess(
82
+ // Регистр приводится ТОЛЬКО у чисто латинского слова. Приведение по Unicode принимает написания,
83
+ // которых никто не объявлял: турецкая «ı» переходит в латинскую «I», и `SıTE` прошло бы как
84
+ // `SITE`. Значение всё равно вышло бы верным, но принимать незаявленную форму — значит обещать
85
+ // поведение, которого нет в контракте.
86
+ (value) => (typeof value === 'string' && /^[a-z]+$/iu.test(value) ? value.toUpperCase() : value), z.enum(WAVE_TRANSPORTS));
87
+ /**
88
+ * Потолок значений в одном фильтре. Столько же держит сервер: длинный `IN` вырождает план запроса.
89
+ *
90
+ * Отгруженная схема предела не объявляла, поэтому предел — ОСОЗНАННОЕ ужесточение против неё, и
91
+ * оно объявлено строками реестра отставания. Без него схема разрешала бы вызов, который сервер
92
+ * отвергает: инструмент обещал бы то, чего не может.
93
+ */
94
+ const REACTION_FILTER_MAX_VALUES = 50;
244
95
  /**
245
- * Применяет типизированную схему к `config` ТОЛЬКО для реактивационных цепочек.
96
+ * Многозначный фильтр уходит ПОВТОРЯЮЩИМИСЯ параметрами (`?segment=a&segment=b`).
246
97
  *
247
- * Через `z.union([reactivationConfigSchema, anyObjectSchema])` это делать нельзя: второй вариант
248
- * принимает любой объект, поэтому union проходит всегда и ограничения (`steps.min(1)`,
249
- * `filterMode` enum) не срабатывают ни разу — типизация выглядит рабочей, но её нет.
98
+ * Список через запятую здесь непригоден: приёмная сторона приводит одиночное значение к массиву,
99
+ * поэтому строка `a,b` стала бы ОДНИМ значением с запятой внутри. Разрез вышел бы пустым при
100
+ * непустой цифре — и отказа при этом не было бы, была бы тихая ложь.
250
101
  *
251
- * @param input - Разобранный ввод тула
252
- * @param ctx - Контекст zod для добавления ошибок
102
+ * Пустой массив не добавляет ни одного параметра, то есть читается как «фильтра нет». Отвергать
103
+ * его нельзя: отгруженный инструмент такой вызов принимает, и отказ сломал бы работающего клиента.
253
104
  */
254
- export const refineFollowUpConfig = (input, ctx) => {
255
- if (input.type !== 'INACTIVE_USER_REACTIVATION') {
256
- return;
105
+ function appendFilter(params, name, values) {
106
+ for (const value of values ?? []) {
107
+ params.append(name, value);
257
108
  }
258
- const parsed = reactivationConfigSchema.safeParse(input.config);
259
- if (parsed.success) {
260
- return;
109
+ }
110
+ function buildReactionsQuery(input) {
111
+ const params = new URLSearchParams();
112
+ params.set('from', input.from);
113
+ params.set('to', input.to);
114
+ if (input.horizon_minutes !== undefined) {
115
+ params.set('horizonMinutes', String(input.horizon_minutes));
261
116
  }
262
- for (const issue of parsed.error.issues) {
263
- ctx.addIssue({
264
- code: z.ZodIssueCode.custom,
265
- path: ['config', ...issue.path],
266
- message: issue.message,
267
- });
117
+ if (input.run_window_days !== undefined) {
118
+ params.set('runWindowDays', String(input.run_window_days));
268
119
  }
269
- };
270
- export const followUpSequenceListSchema = z.object({
271
- platform_id: uuidSchema,
272
- sequence_id: uuidSchema
273
- .optional()
274
- .describe('Вернуть одну цепочку вместе с полным конфигом'),
275
- include_config: z
276
- .boolean()
277
- .optional()
278
- .describe('Отдать конфиги всех цепочек. По умолчанию не отдаются — они объёмные'),
279
- });
280
- export const followUpStepStatsSchema = z.object({
281
- platform_id: uuidSchema,
282
- sequence_id: uuidSchema,
283
- from: z.string().optional().describe('Начало окна, ISO-дата. По умолчанию 30 дней назад'),
284
- to: z.string().optional().describe('Конец окна, ISO-дата. По умолчанию сейчас'),
285
- });
286
- /** Горизонты сравнения, разрешённые бэкендом. Свободное число он отвергает 400. */
287
- const REACTION_HORIZONS = [30, 60, 90, 180, 360, 720, 1440];
288
- export const followUpReactionsSchema = z.object({
289
- platform_id: uuidSchema,
290
- from: z.string().describe('Начало периода по дате отправки шага, YYYY-MM-DD (московские сутки)'),
291
- to: z
292
- .string()
293
- .describe('Конец периода, YYYY-MM-DD. Период длиннее 366 суток бэкенд отвергает'),
294
- sequence_id: z
295
- .array(uuidSchema)
296
- .optional()
297
- .describe('Фильтр цепочек. НЕ влияет на атрибуцию: окно ответа всегда считается по полной шкале ' +
298
- 'касаний контакта, иначе цифра менялась бы от набора фильтров'),
299
- horizon_minutes: z
300
- .union([
301
- z.literal(REACTION_HORIZONS[0]),
302
- z.literal(REACTION_HORIZONS[1]),
303
- z.literal(REACTION_HORIZONS[2]),
304
- z.literal(REACTION_HORIZONS[3]),
305
- z.literal(REACTION_HORIZONS[4]),
306
- z.literal(REACTION_HORIZONS[5]),
307
- z.literal(REACTION_HORIZONS[6]),
308
- ])
309
- .optional()
310
- .describe('Горизонт сравнительной метрики (на ШАГЕ). По умолчанию 90'),
311
- run_window_days: z
312
- .union([z.literal(1), z.literal(3), z.literal(5), z.literal(7), z.literal(14)])
313
- .optional()
314
- .describe('Окно ПРОХОЖДЕНИЯ цепочки для метрики runs: ответил ли человек хоть раз за N дней от ' +
315
- 'входа. По умолчанию 1. Не путать с horizon_minutes — там единица касание, здесь ' +
316
- 'прохождение.'),
317
- segment: z
318
- .array(z.string())
319
- .optional()
320
- .describe('Сегменты волны. Доступные значения приходят в ответе (`dimensions.segments`); у канала ' +
321
- 'без рассылок их нет вообще'),
322
- product: z.array(z.string()).optional().describe('Продукты волны (`dimensions.products`)'),
323
- channel: z
324
- .array(z.string())
325
- .optional()
326
- .describe('Транспорты волны (`dimensions.channels`), например Telegram/WhatsApp/MAX/VK'),
327
- });
120
+ if (input.only_replied_contacts !== undefined) {
121
+ params.set('onlyRepliedContacts', String(input.only_replied_contacts));
122
+ }
123
+ appendFilter(params, 'sequenceId', input.sequence_id);
124
+ appendFilter(params, 'segment', input.segment);
125
+ appendFilter(params, 'product', input.product);
126
+ appendFilter(params, 'transport', input.channel);
127
+ appendFilter(params, 'mailingVariantId', input.mailing_variant_id);
128
+ return `?${params.toString()}`;
129
+ }
328
130
  export const followUpTools = [
329
131
  defineTool({
330
132
  name: 'besales_followup_sequence_list',
331
133
  sideEffect: 'none',
332
134
  requiredFields: ['platform_id'],
135
+ // Перечень цепочек канала: besales_followup_sequence_upsert заменяет конфигурацию целиком,
136
+ // и работать по неполному перечню — значит не увидеть цепочку, которую собирался править.
333
137
  resultPolicy: { neverTruncate: true },
334
- schema: followUpSequenceListSchema,
335
- // Параметры клеим в путь: транспорт (`ApiToolRequest`) знает только method/path/body, и
336
- // отдельное поле `query` было бы молча выброшено — тул вернул бы 200 без учёта фильтров.
138
+ schema: z.object({
139
+ platform_id: uuidSchema,
140
+ sequence_id: uuidSchema.optional(),
141
+ include_config: z.boolean().optional(),
142
+ // ⚠️ Без умолчания: замещающая запись меняет конфигурацию цепочки целиком, и неполный
143
+ // перечень означает не увидеть цепочку, которую собирался править.
144
+ limit: z.number().int().min(1).max(FOLLOWUP_SEQUENCES_MAX_PAGE_SIZE).optional(),
145
+ cursor: z.string().min(1).optional(),
146
+ }),
337
147
  createRequest: (input) => ({
338
148
  method: 'GET',
339
- path: `/platforms/${input.platform_id}/follow-up/sequences${buildListQuery({
340
- sequence_id: input.sequence_id,
341
- include_config: input.include_config,
149
+ path: `/channels/${input.platform_id}/followup-sequences${buildListQuery({
150
+ sequenceId: input.sequence_id,
151
+ includeConfig: input.include_config,
152
+ limit: input.limit,
153
+ cursor: input.cursor,
342
154
  })}`,
343
155
  }),
344
- enhanceResponse: (response) => withInstructions(response, [
345
- 'besales_followup_sequence_upsert заменяет config ЦЕЛИКОМ: прочитай конфиг здесь (sequence_id) и пришли ПОЛНЫЙ желаемый набор шагов, а не дельту.',
346
- 'Без sequence_id и include_config конфиги не отдаются — так список остаётся дешёвым по контексту.',
156
+ enhanceResponse: (response, input) => withInstructions(assertCompleteList(response, {
157
+ pageRequested: input.limit !== undefined || input.cursor !== undefined,
158
+ toolName: 'besales_followup_sequence_list',
159
+ howToPage: `Позовите снова с limit (до ${FOLLOWUP_SEQUENCES_MAX_PAGE_SIZE}) и продолжайте по cursor, пока он не станет пустым.`,
160
+ }), [
161
+ 'Каждый элемент результата — WorkflowView follow-up цепочки канала; актуальная версия в latestVersion, исполняемые шаги — в latestVersion.steps.',
162
+ 'latestVersion.steps — РЕЗУЛЬТАТ трансляции, а не вход besales_followup_sequence_upsert. Upsert принимает конфигурацию в форме v1.5 (steps/finalAction/filterMode/sequenceConditions), трансляция односторонняя, и обратной функции нет: скопировать сюда прочитанные шаги нельзя — запрос будет отклонён.',
163
+ 'include_config=true возвращает type, trigger и config дословно; sequence_id включает конфигурацию автоматически. Для обзора используй limit; пустой список с sequence_id означает, что такой цепочки на канале нет.',
164
+ 'config:null с FOLLOWUP_CONFIG_NOT_WRITTEN_BY_FORM означает, что версию записали общим редактором или клоном канала: сохрани всю цепочку формой дожимов, чтобы открыть чтение и точечную правку. FOLLOWUP_TRIGGER_CHANGED_OUTSIDE_FORM означает, что настройки изменили вне формы; сначала восстанови полную конфигурацию.',
165
+ 'Для одной фразы используй besales_followup_step_message_set. При полной записи передай прочитанный config целиком.',
166
+ crmStagePoolMessage('hint'),
167
+ 'Настройка «выключать дожимы у оплатившего» видна как triggerConfig.stop_on_payment = true. Upsert заменяет конфигурацию целиком: правя такую цепочку, передай config.stopOnPayment: true, иначе стоп выключится (журнал аудита цепочки фиксирует только факт смены настройки, без значений).',
168
+ 'contactVariablesOnSend в строке цепочки — именованная записка; при полной правке передай её обратно в config.contactVariablesOnSend, иначе запись снимется.',
347
169
  ]),
348
170
  }),
349
171
  defineTool({
350
172
  name: 'besales_followup_step_stats',
351
173
  sideEffect: 'none',
352
174
  requiredFields: ['platform_id', 'sequence_id'],
353
- schema: followUpStepStatsSchema,
175
+ schema: z.object({
176
+ platform_id: uuidSchema,
177
+ sequence_id: uuidSchema,
178
+ from: stepStatsBoundSchema.optional(),
179
+ to: stepStatsBoundSchema.optional(),
180
+ }),
354
181
  createRequest: (input) => ({
355
182
  method: 'GET',
356
- path: `/platforms/${input.platform_id}/follow-up/sequences/${input.sequence_id}/step-stats${buildListQuery({ from: input.from, to: input.to })}`,
183
+ path: `/channels/${input.platform_id}/followup-sequences/${input.sequence_id}/step-stats${buildListQuery({ from: input.from, to: input.to })}`,
357
184
  }),
358
185
  enhanceResponse: (response) => withInstructions(response, [
359
- 'wasSent=false НЕ означает «отправка не удалась»: SEND_FAILED пишется только если до fence не дошло (мьют, стадия CRM, тихий канал).',
360
- 'SHADOWED — вариант слота, который не оценивался, потому что слот уже закрыт отправкой другого варианта. Это не ошибка.',
361
- 'SENT_UNVERIFIED — отправка зависла после fence: исходом владеет recovery, повтор запрещён.',
362
- 'waitingUpperBound — ВЕРХНЯЯ оценка ожидающих: прогресс создаётся всем включённым цепочкам платформы без проверки sequenceConditions.',
363
- 'Окно по умолчанию — 30 дней; для более раннего периода передай from/to.',
186
+ 'Ответ — объект: steps (шаги сообщения ТЕКУЩЕЙ версии по порядку, position с нуля, нулевые включены; удалённые шаги не показываются), contactsInChain, sequenceEnabled, применённое окно from/to и executionSteps. Единица счёта — попытка шага, а не человек.',
187
+ 'По шагу: sent — доказанно ушло; sendFailed — не ушло (отказ канала, подавление доставки, запрет политики; закрытый срок переписки сюда не попадает — шаг ждёт); sentUnverified — канал мог принять, повтор запрещён: ни успех, ни отказ.',
188
+ 'skipped — пропуски по причинам: ключ — код причины, человеку называй подпись label из byOutcome, а не код. «Не проверялось, время слота занял вариант выше» тоже здесь — это устройство слота, а не сбой.',
189
+ 'failedConditions — технические ключи непрошедших условий: переменная, contact.<поле>, tag/tag:<имя> или служебное поле. Человеку называй label из byOutcome.variables; ключом не подменяй подпись.',
190
+ 'waitingUpperBound — люди в идущих прогонах, чей следующий шаг сообщения — этот; не все его получат. Людей, кому цепочка ещё не запускалась, здесь нет — точная очередь ожидающих есть в отчёте воронки. contactsInChain — люди, у кого был прогон, плюс перенесённый прогресс прежней системы: после переключения число стартует почти с нуля.',
191
+ 'sequenceEnabled = false — цепочка выключена: нули значат «остановлена», а не «никого нет».',
192
+ 'Окно по умолчанию — последние 30 суток. from/to — дата ГГГГ-ММ-ДД (сутки в поясе канала, у конца включается весь последний день) или момент с часовым поясом; ответ называет применённое окно.',
193
+ 'executionSteps — исполнение шагов любого вида по журналу прогонов (completed/failed/skipped и последний старт): так видно, что падает, например, шаг CRM.',
364
194
  ]),
365
195
  }),
366
196
  defineTool({
367
197
  name: 'besales_followup_reactions',
368
198
  sideEffect: 'none',
199
+ // Порядок обязательных полей повторяет отгруженную схему: паритет сверяется равенством
200
+ // массивов, а не множеств.
369
201
  requiredFields: ['platform_id', 'from', 'to'],
370
- schema: followUpReactionsSchema,
202
+ schema: z
203
+ .object({
204
+ platform_id: uuidSchema,
205
+ from: calendarDateSchema,
206
+ to: calendarDateSchema,
207
+ sequence_id: z.array(uuidSchema).max(REACTION_FILTER_MAX_VALUES).optional(),
208
+ horizon_minutes: reactionHorizonSchema
209
+ .optional()
210
+ .describe('Горизонт сравнительной метрики, минуты. Набор закрыт. Если не передан, сервер подбирает горизонт по доле вырезанных касаний; выбранное значение и причину смотри в horizonMinutes и horizonReason ответа.'),
211
+ run_window_days: reactionRunWindowSchema.optional(),
212
+ only_replied_contacts: z.boolean().optional(),
213
+ segment: z.array(z.string()).max(REACTION_FILTER_MAX_VALUES).optional(),
214
+ product: z.array(z.string()).max(REACTION_FILTER_MAX_VALUES).optional(),
215
+ channel: z.array(waveTransportSchema).max(REACTION_FILTER_MAX_VALUES).optional(),
216
+ // Сверх отгруженной схемы: ответ отдаёт справочник dimensions.mailingVariants, и без
217
+ // фильтра он был бы носителем без читателя — значения видно, выбрать по ним нельзя.
218
+ // Входного asOf у моста нет. Сервер возвращает calculatedAt для раскрытия через API
219
+ // с тем же H и asOf; граница времени событий не фиксирует данные между запросами.
220
+ mailing_variant_id: z.array(uuidSchema).max(REACTION_FILTER_MAX_VALUES).optional(),
221
+ })
222
+ .strict(),
371
223
  createRequest: (input) => ({
372
224
  method: 'GET',
373
- // ⚠️ Ключи query — camelCase, в отличие от snake_case параметров тула: этот эндпоинт
374
- // разбирает их в DTO с `forbidNonWhitelisted`, и `sequence_id` вернул бы 400
375
- // «property should not exist». Соседний `sequence_list` принимает snake_case потому, что
376
- // его контроллер объявляет параметры поштучно, — на него ориентироваться нельзя.
377
- path: `/platforms/${input.platform_id}/follow-up/reactions${buildListQuery({
378
- from: input.from,
379
- to: input.to,
380
- sequenceId: input.sequence_id,
381
- horizonMinutes: input.horizon_minutes,
382
- runWindowDays: input.run_window_days,
383
- segment: input.segment,
384
- product: input.product,
385
- channel: input.channel,
386
- })}`,
225
+ path: `/channels/${input.platform_id}/followup-sequences/reactions${buildReactionsQuery(input)}`,
387
226
  }),
388
227
  enhanceResponse: (response) => withInstructions(response, [
389
- 'Метрик ТРИ и они НЕ взаимозаменяемы (третья — runs, см. ниже). `replied` — операционная: у каждого шага СВОЁ окно (до следующего касания), поэтому шаг с суточным интервалом почти всегда выглядит лучше часового. Сравнивать шаги по ней НЕЛЬЗЯ.',
390
- 'Сравнивать шаги можно ТОЛЬКО по `horizonReplied` (равный горизонт) и ТОЛЬКО там, где `comparableReliable: true`.',
391
- 'comparableReliable=false означает, что доля ЗАВЫШЕНА, а не просто шумна: цензурирование информативно — следующий шаг уходит лишь к промолчавшим, поэтому выжившие обогащены ответившими. Замер: 67 % вырезанных дали 20,8 % против настоящих 5,5 %. Первое лечение — horizon_minutes КОРОЧЕ интервала между шагами.',
392
- 'Но у частых цепочек подходящего горизонта НЕ СУЩЕСТВУЕТ: у вебинарной цепочки 35 % касаний имеют следующий шаг раньше 15 минут, то есть их вырезает даже минимальный горизонт 30. Не подбирай горизонт бесконечно — переходи на метрику runs.',
393
- 'runs — ТРЕТЬЯ метрика и ДРУГАЯ единица: прохождение цепочки, а не касание. «Ответил ли хоть раз за run_window_days от входа». Вырезать там некого (все шаги внутри окна принадлежат этому же прохождению), поэтому частота пингов на неё не влияет. Отвечает «работает ли цепочка», а НЕ «какой шаг сработал» — текст шага по ней не оптимизируется.',
394
- 'runs.immature — прохождения, у которых окно ещё не вышло. Они НЕ входят в runs.started, то есть доля считается от созревших. Растёт окно — растёт и число незрелых: это размен по ВРЕМЕНИ, а не по выборке.',
395
- 'Сравнивать ВЕРСИИ одного шага (A/B текста) надо по replied, а не по horizonReplied: у версий одного шага пауза до следующего касания одинаковая, значит окно равное и сравнение честное.',
396
- 'Знаменатели разные: `replied` считается от `resolvedSent` (без ещё открытых окон), `horizonReplied` — от `comparableSent`. От `sent` не считается НИ ОДНА доля.',
397
- '`horizonEngaged` — отреагировали ХОТЬ КАК-ТО в том же горизонте: ответили ИЛИ перешли по ссылке касания. Знаменатель тот же (`comparableSent`), разность `horizonEngaged - horizonReplied` — те, кто НЕ ответил, но кликнул. Молчание на текст ещё не значит, что касание не сработало.',
398
- '⚠️ НЕ складывай `horizonReplied` и `linkClicked`: ответивший часто ещё и кликает, и сумма задваивает его. Объединение уже посчитано — это `horizonEngaged`. `linkClicked` отвечает на другой вопрос (CTR ссылки) и считается от `linkIssued` бессрочно, без горизонта.',
399
- 'Ответ атрибутируется РОВНО ОДНОМУ касанию — ближайшему предшествующему. Окно закрывают шаг любой цепочки, волна рассылки и реплика живого оператора.',
400
- 'Цепочки с `measurable: false` шагов не записывают вообще (LOST_CLIENTS): их отсутствие в byStep означает «не меряем», а не «не работает».',
401
- 'Пустые массивы в `dimensions` — у канала нет рассылок, срезы по сегменту/продукту/мессенджеру там недоступны в принципе.',
402
- 'anchorExactShare < 1 — у части строк время отправки записано пакетно (отставание секунды). На окне в десятки минут это меньше процента.',
228
+ 'Зерно всех цифр — КАСАНИЕ (одна отправка контакту), а не человек: один контакт за период даёт столько строк, сколько раз мы ему писали.',
229
+ 'Метрик ДВЕ и они несводимы. Операционная доля replied / resolvedSent считает только ответы в окне до СЛЕДУЮЩЕГО касания с потолком 72 часа, поэтому следует за длиной окна: у последнего шага цепочки окно всегда шире, и по ней шаги между собой сравнивать НЕЛЬЗЯ.',
230
+ 'Реакция — живой ответ OR настоящий клик ссылки этого касания: horizonEngaged объединяет их без двойного счёта. horizonReplied отдельно считает только ответы; не складывай эти числители.',
231
+ 'Сравнительная доля horizonEngaged / comparableSent использует horizonMinutes из ответа (selected H), один для всех строк. Без horizon_minutes сервер подбирает горизонт сам; причину показывает horizonReason. Все события и зрелость ограничены calculatedAt (asOf). У этого инструмента нет входа asOf и раскрытия строк: calculatedAt описывает снимок одного ответа и не закрепляет данные между HTTP-запросами.',
232
+ 'Сравнивай только строки с comparableSent > 0 и comparableReliable=true. horizonReason=noData означает отсутствие зрелого пула; noReliableHorizon — нет надёжного горизонта. Ни noData, ни requested не разрешают сравнивать пустые группы.',
233
+ 'censored — все необратимо прерванные окна; maturedCensored — только достигшие sentAt + H ≤ asOf. censoredShare = maturedCensored / (comparableSent + maturedCensored); при пустом пуле сервер возвращает 0, это не доказательство сравнимости. Не подставляй terminal censored в знаменатель.',
234
+ 'ambiguous — ничьи: касание другого производителя в тот же момент. Они исключены и из числителей, и из знаменателя, поэтому attributableSent меньше sent ровно на ambiguous.',
235
+ 'Равенства сервера: sent = ambiguous + attributableSent; attributableSent = comparableSent + censored + immature. Общей корзины scopeUnresolved нет. Прерванная строка сопоставимой уже не станет.',
236
+ 'totals и runs не пересчитывай из строк моделью. runs имеет grain=passage и periodBasis=passageStartedAt, отдельное окно windowDays; с funnelId runs=null, runsUnavailableReason=funnelEntryGrain. Клик не является ответом агента и не создаёт глубокий диалог или оплату.',
237
+ 'byDayStep — разрез сутки × шаг по всем выбранным цепочкам, включая выбор нескольких цепочек. Это может быть большой массив строк.',
238
+ 'Условия шага называются техническим ключом contact.<поле>, tag/tag:<имя>; человекочитаемый label из byOutcome.variables служит подписью, а не ключом фильтра.',
239
+ 'runs — отдельный блок прохождений. run_window_days выбирает окно ответа в сутках: 1, 3, 5, 7 или 14; по умолчанию 1. Отсутствие параметра не выключает блок.',
240
+ 'only_replied_contacts оставляет в цифрах только контакты с живым входящим до снимка расчёта. Линза меняет состав строк, поэтому доли с ней и без неё несопоставимы; каталог dimensions и признак измеримости цепочки остаются общими.',
241
+ 'sequences отдаёт ПОЛНЫЙ каталог цепочек воркспейса. measurable=false с unmeasurableReason=noTouchesInPeriod означает «в периоде касаний не было», а не «цепочка сломана» — чинить там нечего. Признак считается отдельно от разреза и фильтрами не искажается.',
242
+ 'Разрезы segment/product/channel/mailingVariantId существуют только у каналов с рассылками; допустимые значения бери из dimensions ответа, а не выдумывай.',
243
+ 'Незнакомый сегмент или продукт даёт пустой разрез, а вот незнакомый ТРАНСПОРТ отвергается: сервер приводит его к перечислению, и посторонняя строка уронила бы весь запрос. Метки транспорта — в верхнем регистре (TELEGRAM, WHATSAPP, MAX, VK), их же отдаёт dimensions.transports.',
244
+ 'handedOff и crmStageMoved — исходы дожима помимо ответа в переписке. Переход сделки по стадиям измерим и там, где рассылок нет вовсе.',
245
+ 'Период считается по дате отправки касания в поясе КАНАЛА; длиннее 366 суток сервер отвергает.',
403
246
  ]),
404
247
  }),
405
248
  ];