@besales/mcp 0.48.0 → 1.0.0-beta.4

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 (604) hide show
  1. package/README.md +117 -163
  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 +54 -7
  23. package/dist/http/api-client.js +132 -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 +43 -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 +149 -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 +12389 -6657
  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 +81 -24
  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 +29 -39
  158. package/dist/tools/definitions/crm-platform.js +249 -352
  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/dialogue-reprocess.d.ts +5 -0
  197. package/dist/tools/definitions/dialogue-reprocess.js +107 -0
  198. package/dist/tools/definitions/dialogue-reprocess.js.map +1 -0
  199. package/dist/tools/definitions/edit-version-transport.test-fixtures.d.ts +13 -0
  200. package/dist/tools/definitions/edit-version-transport.test-fixtures.js +292 -0
  201. package/dist/tools/definitions/edit-version-transport.test-fixtures.js.map +1 -0
  202. package/dist/tools/definitions/edit-version.d.ts +5 -0
  203. package/dist/tools/definitions/edit-version.js +20 -0
  204. package/dist/tools/definitions/edit-version.js.map +1 -0
  205. package/dist/tools/definitions/external-api-channels.js +17 -15
  206. package/dist/tools/definitions/external-api-channels.js.map +1 -1
  207. package/dist/tools/definitions/feedback-document-access.d.ts +16 -0
  208. package/dist/tools/definitions/feedback-document-access.js +63 -0
  209. package/dist/tools/definitions/feedback-document-access.js.map +1 -0
  210. package/dist/tools/definitions/fixtures/shipped-setup-status.d.ts +3 -0
  211. package/dist/tools/definitions/fixtures/shipped-setup-status.js +9 -0
  212. package/dist/tools/definitions/fixtures/shipped-setup-status.js.map +1 -0
  213. package/dist/tools/definitions/follow-up-config.d.ts +79 -0
  214. package/dist/tools/definitions/follow-up-config.js +258 -0
  215. package/dist/tools/definitions/follow-up-config.js.map +1 -0
  216. package/dist/tools/definitions/follow-up-funnel-test.d.ts +4 -3
  217. package/dist/tools/definitions/follow-up-funnel-test.js +65 -52
  218. package/dist/tools/definitions/follow-up-funnel-test.js.map +1 -1
  219. package/dist/tools/definitions/follow-up-promotion-instructions.d.ts +2 -0
  220. package/dist/tools/definitions/follow-up-promotion-instructions.js +7 -0
  221. package/dist/tools/definitions/follow-up-promotion-instructions.js.map +1 -0
  222. package/dist/tools/definitions/follow-up-setup.d.ts +4 -28
  223. package/dist/tools/definitions/follow-up-setup.js +20 -87
  224. package/dist/tools/definitions/follow-up-setup.js.map +1 -1
  225. package/dist/tools/definitions/follow-up.d.ts +20 -122
  226. package/dist/tools/definitions/follow-up.js +200 -357
  227. package/dist/tools/definitions/follow-up.js.map +1 -1
  228. package/dist/tools/definitions/followup-getcourse-compat.d.ts +29 -0
  229. package/dist/tools/definitions/followup-getcourse-compat.js +62 -0
  230. package/dist/tools/definitions/followup-getcourse-compat.js.map +1 -0
  231. package/dist/tools/definitions/followup-sequence-config.schema.d.ts +10 -0
  232. package/dist/tools/definitions/followup-sequence-config.schema.js +14 -0
  233. package/dist/tools/definitions/followup-sequence-config.schema.js.map +1 -0
  234. package/dist/tools/definitions/funnel-analytics.d.ts +18 -0
  235. package/dist/tools/definitions/funnel-analytics.js +150 -0
  236. package/dist/tools/definitions/funnel-analytics.js.map +1 -0
  237. package/dist/tools/definitions/getcourse-anchor-refresh.d.ts +5 -9
  238. package/dist/tools/definitions/getcourse-anchor-refresh.js +26 -31
  239. package/dist/tools/definitions/getcourse-anchor-refresh.js.map +1 -1
  240. package/dist/tools/definitions/getcourse-cold-outbound-settings.d.ts +46 -0
  241. package/dist/tools/definitions/getcourse-cold-outbound-settings.js +37 -0
  242. package/dist/tools/definitions/getcourse-cold-outbound-settings.js.map +1 -0
  243. package/dist/tools/definitions/getcourse-cold-welcome.d.ts +14 -29
  244. package/dist/tools/definitions/getcourse-cold-welcome.js +190 -253
  245. package/dist/tools/definitions/getcourse-cold-welcome.js.map +1 -1
  246. package/dist/tools/definitions/getcourse-wave-welcome.messages.d.ts +10 -0
  247. package/dist/tools/definitions/getcourse-wave-welcome.messages.js +17 -0
  248. package/dist/tools/definitions/getcourse-wave-welcome.messages.js.map +1 -0
  249. package/dist/tools/definitions/help.js.map +1 -1
  250. package/dist/tools/definitions/icp-import-source.d.ts +75 -0
  251. package/dist/tools/definitions/icp-import-source.js +88 -0
  252. package/dist/tools/definitions/icp-import-source.js.map +1 -0
  253. package/dist/tools/definitions/inbound-analytics.d.ts +13 -0
  254. package/dist/tools/definitions/inbound-analytics.js +55 -0
  255. package/dist/tools/definitions/inbound-analytics.js.map +1 -0
  256. package/dist/tools/definitions/instagram-comment.templates.d.ts +19 -0
  257. package/dist/tools/definitions/instagram-comment.templates.js +34 -0
  258. package/dist/tools/definitions/instagram-comment.templates.js.map +1 -0
  259. package/dist/tools/definitions/instagram-settings-compat.d.ts +33 -0
  260. package/dist/tools/definitions/instagram-settings-compat.js +7 -0
  261. package/dist/tools/definitions/instagram-settings-compat.js.map +1 -0
  262. package/dist/tools/definitions/knowledge-chunking.d.ts +42 -0
  263. package/dist/tools/definitions/knowledge-chunking.js +83 -0
  264. package/dist/tools/definitions/knowledge-chunking.js.map +1 -0
  265. package/dist/tools/definitions/knowledge-space-search-fields.d.ts +12 -0
  266. package/dist/tools/definitions/knowledge-space-search-fields.js +30 -0
  267. package/dist/tools/definitions/knowledge-space-search-fields.js.map +1 -0
  268. package/dist/tools/definitions/knowledge.d.ts +24 -14
  269. package/dist/tools/definitions/knowledge.js +342 -233
  270. package/dist/tools/definitions/knowledge.js.map +1 -1
  271. package/dist/tools/definitions/legacy-trigger-repeat.d.ts +17 -0
  272. package/dist/tools/definitions/legacy-trigger-repeat.js +53 -0
  273. package/dist/tools/definitions/legacy-trigger-repeat.js.map +1 -0
  274. package/dist/tools/definitions/link-tracking.d.ts +8 -0
  275. package/dist/tools/definitions/link-tracking.js +141 -38
  276. package/dist/tools/definitions/link-tracking.js.map +1 -1
  277. package/dist/tools/definitions/mailing-variant-content.d.ts +75 -0
  278. package/dist/tools/definitions/mailing-variant-content.js +73 -0
  279. package/dist/tools/definitions/mailing-variant-content.js.map +1 -0
  280. package/dist/tools/definitions/model-comparison.d.ts +2 -1
  281. package/dist/tools/definitions/model-comparison.js +4 -5
  282. package/dist/tools/definitions/model-comparison.js.map +1 -1
  283. package/dist/tools/definitions/money-currency.d.ts +5 -0
  284. package/dist/tools/definitions/money-currency.js +10 -0
  285. package/dist/tools/definitions/money-currency.js.map +1 -0
  286. package/dist/tools/definitions/operator-workflow.d.ts +5 -5
  287. package/dist/tools/definitions/operator-workflow.js +80 -27
  288. package/dist/tools/definitions/operator-workflow.js.map +1 -1
  289. package/dist/tools/definitions/platform-funnel-analytics.d.ts +42 -0
  290. package/dist/tools/definitions/platform-funnel-analytics.js +72 -0
  291. package/dist/tools/definitions/platform-funnel-analytics.js.map +1 -0
  292. package/dist/tools/definitions/platform-getcourse-wave-field-bindings.d.ts +42 -0
  293. package/dist/tools/definitions/platform-getcourse-wave-field-bindings.js +51 -0
  294. package/dist/tools/definitions/platform-getcourse-wave-field-bindings.js.map +1 -0
  295. package/dist/tools/definitions/platform-settings-limits.d.ts +5 -0
  296. package/dist/tools/definitions/platform-settings-limits.js +6 -0
  297. package/dist/tools/definitions/platform-settings-limits.js.map +1 -0
  298. package/dist/tools/definitions/platform-settings-shipped-form.d.ts +37 -0
  299. package/dist/tools/definitions/platform-settings-shipped-form.js +310 -0
  300. package/dist/tools/definitions/platform-settings-shipped-form.js.map +1 -0
  301. package/dist/tools/definitions/platform-settings-update.d.ts +300 -0
  302. package/dist/tools/definitions/platform-settings-update.js +134 -0
  303. package/dist/tools/definitions/platform-settings-update.js.map +1 -0
  304. package/dist/tools/definitions/{getcourse-wave.d.ts → platform-setup-wave.d.ts} +75 -6
  305. package/dist/tools/definitions/platform-setup-wave.js +1079 -0
  306. package/dist/tools/definitions/platform-setup-wave.js.map +1 -0
  307. package/dist/tools/definitions/platform-setup.d.ts +697 -224
  308. package/dist/tools/definitions/platform-setup.js +313 -752
  309. package/dist/tools/definitions/platform-setup.js.map +1 -1
  310. package/dist/tools/definitions/platform-widget-page-rules.schema.d.ts +10 -0
  311. package/dist/tools/definitions/platform-widget-page-rules.schema.js +7 -0
  312. package/dist/tools/definitions/platform-widget-page-rules.schema.js.map +1 -0
  313. package/dist/tools/definitions/prompt-authoring.constants.d.ts +2 -0
  314. package/dist/tools/definitions/prompt-authoring.constants.js +3 -0
  315. package/dist/tools/definitions/prompt-authoring.constants.js.map +1 -0
  316. package/dist/tools/definitions/prompt-batch-controls.d.ts +5 -0
  317. package/dist/tools/definitions/prompt-batch-controls.js +40 -0
  318. package/dist/tools/definitions/prompt-batch-controls.js.map +1 -0
  319. package/dist/tools/definitions/prompt-draft-authoring.d.ts +5 -0
  320. package/dist/tools/definitions/prompt-draft-authoring.js +24 -0
  321. package/dist/tools/definitions/prompt-draft-authoring.js.map +1 -0
  322. package/dist/tools/definitions/prompt-text-projection.d.ts +11 -0
  323. package/dist/tools/definitions/prompt-text-projection.js +62 -0
  324. package/dist/tools/definitions/prompt-text-projection.js.map +1 -0
  325. package/dist/tools/definitions/reviewer-paid.d.ts +19 -0
  326. package/dist/tools/definitions/reviewer-paid.js +115 -0
  327. package/dist/tools/definitions/reviewer-paid.js.map +1 -0
  328. package/dist/tools/definitions/routing-condition-projection.d.ts +31 -0
  329. package/dist/tools/definitions/routing-condition-projection.js +97 -0
  330. package/dist/tools/definitions/routing-condition-projection.js.map +1 -0
  331. package/dist/tools/definitions/schedule-selection-hints.d.ts +3 -0
  332. package/dist/tools/definitions/schedule-selection-hints.js +42 -0
  333. package/dist/tools/definitions/schedule-selection-hints.js.map +1 -0
  334. package/dist/tools/definitions/{scheduled-tasks.d.ts → scheduled-task-alias.d.ts} +12 -10
  335. package/dist/tools/definitions/scheduled-task-alias.js +207 -0
  336. package/dist/tools/definitions/scheduled-task-alias.js.map +1 -0
  337. package/dist/tools/definitions/session.js +3 -3
  338. package/dist/tools/definitions/session.js.map +1 -1
  339. package/dist/tools/definitions/setup-init-operation.schema.d.ts +2 -0
  340. package/dist/tools/definitions/setup-init-operation.schema.js +6 -0
  341. package/dist/tools/definitions/setup-init-operation.schema.js.map +1 -0
  342. package/dist/tools/definitions/shared-input.helpers.d.ts +51 -0
  343. package/dist/tools/definitions/shared-input.helpers.js +323 -0
  344. package/dist/tools/definitions/shared-input.helpers.js.map +1 -0
  345. package/dist/tools/definitions/shared.d.ts +401 -307
  346. package/dist/tools/definitions/shared.js +430 -652
  347. package/dist/tools/definitions/shared.js.map +1 -1
  348. package/dist/tools/definitions/shipped-output-names.d.ts +19 -0
  349. package/dist/tools/definitions/shipped-output-names.js +123 -0
  350. package/dist/tools/definitions/shipped-output-names.js.map +1 -0
  351. package/dist/tools/definitions/task-state.d.ts +4 -4
  352. package/dist/tools/definitions/task-state.js +2 -1
  353. package/dist/tools/definitions/task-state.js.map +1 -1
  354. package/dist/tools/definitions/telegram-personal-capacity.d.ts +4 -0
  355. package/dist/tools/definitions/telegram-personal-capacity.js +18 -0
  356. package/dist/tools/definitions/telegram-personal-capacity.js.map +1 -0
  357. package/dist/tools/definitions/telegram-personal-management.d.ts +34 -0
  358. package/dist/tools/definitions/telegram-personal-management.js +139 -0
  359. package/dist/tools/definitions/telegram-personal-management.js.map +1 -0
  360. package/dist/tools/definitions/telegram-personal-restrictions.d.ts +19 -0
  361. package/dist/tools/definitions/telegram-personal-restrictions.js +109 -0
  362. package/dist/tools/definitions/telegram-personal-restrictions.js.map +1 -0
  363. package/dist/tools/definitions/telegram-pool-policy.d.ts +8 -0
  364. package/dist/tools/definitions/telegram-pool-policy.js +56 -0
  365. package/dist/tools/definitions/telegram-pool-policy.js.map +1 -0
  366. package/dist/tools/definitions/touch-history-alias.d.ts +4 -0
  367. package/dist/tools/definitions/touch-history-alias.js +99 -0
  368. package/dist/tools/definitions/touch-history-alias.js.map +1 -0
  369. package/dist/tools/definitions/trigger-action-item.schema.d.ts +254 -0
  370. package/dist/tools/definitions/trigger-action-item.schema.js +121 -0
  371. package/dist/tools/definitions/trigger-action-item.schema.js.map +1 -0
  372. package/dist/tools/definitions/trigger-argument.schema.d.ts +14 -0
  373. package/dist/tools/definitions/trigger-argument.schema.js +23 -0
  374. package/dist/tools/definitions/trigger-argument.schema.js.map +1 -0
  375. package/dist/tools/definitions/trigger-claim-alias.d.ts +10 -0
  376. package/dist/tools/definitions/trigger-claim-alias.js +90 -0
  377. package/dist/tools/definitions/trigger-claim-alias.js.map +1 -0
  378. package/dist/tools/definitions/trigger-echo-projection.d.ts +1 -0
  379. package/dist/tools/definitions/trigger-echo-projection.js +41 -0
  380. package/dist/tools/definitions/trigger-echo-projection.js.map +1 -0
  381. package/dist/tools/definitions/trigger-upsert.tool.d.ts +41 -0
  382. package/dist/tools/definitions/trigger-upsert.tool.js +159 -0
  383. package/dist/tools/definitions/trigger-upsert.tool.js.map +1 -0
  384. package/dist/tools/definitions/v15-port-descriptions.d.ts +11 -0
  385. package/dist/tools/definitions/v15-port-descriptions.js +30 -0
  386. package/dist/tools/definitions/v15-port-descriptions.js.map +1 -0
  387. package/dist/tools/definitions/variables.d.ts +44 -0
  388. package/dist/tools/definitions/variables.js +310 -0
  389. package/dist/tools/definitions/variables.js.map +1 -0
  390. package/dist/tools/definitions/voice-action-input.d.ts +9 -0
  391. package/dist/tools/definitions/voice-action-input.js +141 -0
  392. package/dist/tools/definitions/voice-action-input.js.map +1 -0
  393. package/dist/tools/definitions/widget-customization-compat.d.ts +51 -0
  394. package/dist/tools/definitions/widget-customization-compat.js +23 -0
  395. package/dist/tools/definitions/widget-customization-compat.js.map +1 -0
  396. package/dist/tools/definitions.d.ts +1134 -617
  397. package/dist/tools/definitions.js +63 -27
  398. package/dist/tools/definitions.js.map +1 -1
  399. package/dist/tools/description-localization.js +3 -2
  400. package/dist/tools/description-localization.js.map +1 -1
  401. package/dist/tools/follow-up-request.d.ts +19 -0
  402. package/dist/tools/follow-up-request.js +81 -0
  403. package/dist/tools/follow-up-request.js.map +1 -0
  404. package/dist/tools/followup-revision.d.ts +4 -0
  405. package/dist/tools/followup-revision.js +29 -0
  406. package/dist/tools/followup-revision.js.map +1 -0
  407. package/dist/tools/incomplete-list.js +4 -0
  408. package/dist/tools/incomplete-list.js.map +1 -1
  409. package/dist/tools/inventory.js +47 -11
  410. package/dist/tools/inventory.js.map +1 -1
  411. package/dist/tools/operation-recovery.d.ts +4 -0
  412. package/dist/tools/operation-recovery.js +33 -0
  413. package/dist/tools/operation-recovery.js.map +1 -0
  414. package/dist/tools/registry-mapping-primary.cases.d.ts +2 -0
  415. package/dist/tools/registry-mapping-primary.cases.js +765 -0
  416. package/dist/tools/registry-mapping-primary.cases.js.map +1 -0
  417. package/dist/tools/registry-mapping-secondary.cases.d.ts +2 -0
  418. package/dist/tools/registry-mapping-secondary.cases.js +626 -0
  419. package/dist/tools/registry-mapping-secondary.cases.js.map +1 -0
  420. package/dist/tools/registry-mapping.cases.d.ts +8 -0
  421. package/dist/tools/registry-mapping.cases.js +170 -0
  422. package/dist/tools/registry-mapping.cases.js.map +1 -0
  423. package/dist/tools/registry-test-fixtures.d.ts +50 -0
  424. package/dist/tools/registry-test-fixtures.js +120 -0
  425. package/dist/tools/registry-test-fixtures.js.map +1 -0
  426. package/dist/tools/registry.d.ts +2 -0
  427. package/dist/tools/registry.js +84 -52
  428. package/dist/tools/registry.js.map +1 -1
  429. package/dist/tools/result.d.ts +1 -0
  430. package/dist/tools/result.js +90 -22
  431. package/dist/tools/result.js.map +1 -1
  432. package/dist/tools/toolsets.d.ts +16 -0
  433. package/dist/tools/toolsets.js +25 -1
  434. package/dist/tools/toolsets.js.map +1 -1
  435. package/dist/types/api-contract.gen.d.ts +131892 -22453
  436. package/dist/utils/credential-signatures.d.ts +3 -0
  437. package/dist/utils/credential-signatures.js +10 -0
  438. package/dist/utils/credential-signatures.js.map +1 -0
  439. package/dist/utils/data-source-column-name.d.ts +10 -0
  440. package/dist/utils/data-source-column-name.js +36 -0
  441. package/dist/utils/data-source-column-name.js.map +1 -0
  442. package/dist/utils/logger.d.ts +1 -0
  443. package/dist/utils/logger.js +32 -8
  444. package/dist/utils/logger.js.map +1 -1
  445. package/dist/utils/secret-read-boundary.d.ts +2 -0
  446. package/dist/utils/secret-read-boundary.js +88 -0
  447. package/dist/utils/secret-read-boundary.js.map +1 -0
  448. package/dist/utils/setup-secrets.d.ts +4 -0
  449. package/dist/utils/setup-secrets.js +40 -0
  450. package/dist/utils/setup-secrets.js.map +1 -0
  451. package/docs/agent-models.md +9 -0
  452. package/docs/agent-usage-guide.full.ru.md +1 -4
  453. package/docs/analytics-contract.md +67 -0
  454. package/docs/async-operation-lifecycle.md +10 -3
  455. package/docs/connect.ru.md +144 -4
  456. package/docs/contact-company-profile.md +17 -0
  457. package/docs/contact-recommendations.md +7 -0
  458. package/docs/crm-stage-pool.md +73 -0
  459. package/docs/customer-data.md +61 -0
  460. package/docs/dialogue-reprocess.md +37 -0
  461. package/docs/edit-versions.md +36 -0
  462. package/docs/failure-semantics.md +17 -9
  463. package/docs/help-navigation.md +15 -42
  464. package/docs/host-compatibility-matrix.md +72 -93
  465. package/docs/host-setup.md +33 -35
  466. package/docs/invariants/public-api-and-contracts.md +16 -0
  467. package/docs/legacy-action-settings.md +21 -0
  468. package/docs/main-transfer-dependencies.md +38 -0
  469. package/docs/mcp2-parity.md +50 -0
  470. package/docs/modules/analytics.md +79 -0
  471. package/docs/modules/besales-mcp.md +144 -0
  472. package/docs/modules/dialog-review-report.md +38 -0
  473. package/docs/modules/dialogue-followup-adapters.md +39 -0
  474. package/docs/modules/message-reactions.md +17 -0
  475. package/docs/modules/network-mode.md +284 -0
  476. package/docs/modules/prompt-batch-and-dialogue-controls.md +69 -0
  477. package/docs/pii-policy.md +21 -16
  478. package/docs/response-size-budget.md +197 -7
  479. package/docs/secret-read-boundary.md +102 -0
  480. package/docs/task-state.md +7 -2
  481. package/docs/telegram-personal-management.md +50 -0
  482. package/docs/telegram-personal-restrictions.md +87 -0
  483. package/docs/telegram-pool-policy.md +19 -0
  484. package/docs/tool-effects.md +15 -9
  485. package/docs/tool-surface.md +205 -4
  486. package/docs/voice-actions-and-inbox.md +95 -0
  487. package/docs/wazzup-instagram-comments.md +26 -0
  488. package/package.json +17 -10
  489. package/scripts/api-source-loader.spec.mjs +40 -0
  490. package/scripts/audit-bridge-controls.mjs +129 -0
  491. package/scripts/audit-revert-mutants.mjs +107 -0
  492. package/scripts/bridge-api-input.spec.mjs +98 -0
  493. package/scripts/bridge-controls-mutants.mjs +130 -0
  494. package/scripts/brx3-shipped-refusals.spec.mjs +149 -0
  495. package/scripts/brx4-ledger-payload.spec.mjs +127 -0
  496. package/scripts/build-onprem.mjs +108 -0
  497. package/scripts/connect-clients.sh +141 -0
  498. package/scripts/connect-scopes.mjs +166 -0
  499. package/scripts/connect-scopes.spec.mjs +83 -0
  500. package/scripts/emit-personal-link-carrier.mjs +31 -0
  501. package/scripts/emit-setup-init-schemas.mjs +24 -0
  502. package/scripts/emit-tool-routes.mjs +878 -0
  503. package/scripts/emit-tool-routes.spec.mjs +300 -0
  504. package/scripts/followup-registry.spec.mjs +107 -0
  505. package/scripts/generate-crm-rotation-contract.mjs +98 -0
  506. package/scripts/generate-followup-session-contract.mjs +16 -0
  507. package/scripts/getcourse-text-source.spec.mjs +110 -0
  508. package/scripts/icp-import-verification/mutate.cjs +70 -0
  509. package/scripts/import-secret-read-contract.mjs +53 -0
  510. package/scripts/install-claude-desktop.js +1 -1
  511. package/scripts/lag-decisions.mjs +37 -0
  512. package/scripts/lag-decisions.spec.mjs +87 -0
  513. package/scripts/lag-open-task-owners.mjs +46 -0
  514. package/scripts/lag-open-task-owners.spec.mjs +78 -0
  515. package/scripts/lag-payload.mjs +10 -0
  516. package/scripts/legacy-action-lag.spec.mjs +22 -0
  517. package/scripts/legacy-field-refusal.shipped.spec.mjs +99 -0
  518. package/scripts/mcpcompat-handler.mjs +34 -0
  519. package/scripts/mcpcompat-loader.mjs +36 -0
  520. package/scripts/mcpcompat-typescript.mjs +3 -0
  521. package/scripts/platform-settings-shipped-parity.spec.mjs +89 -0
  522. package/scripts/prbr-round1-recheck.spec.mjs +605 -0
  523. package/scripts/prbr-shipped-compatibility.spec.mjs +276 -0
  524. package/scripts/publish-mcp-registry.mjs +98 -0
  525. package/scripts/publish-mcp-registry.spec.mjs +68 -0
  526. package/scripts/record-scheduled-task-call.mjs +26 -0
  527. package/scripts/refusal-probe.mjs +17 -0
  528. package/scripts/refusal-probe.spec.mjs +29 -0
  529. package/scripts/registry-diff.mjs +502 -0
  530. package/scripts/registry-diff.spec.mjs +787 -0
  531. package/scripts/request-query.mjs +43 -0
  532. package/scripts/request-query.spec.mjs +82 -0
  533. package/scripts/route-lag.mjs +23 -0
  534. package/scripts/route-lag.spec.mjs +30 -0
  535. package/scripts/sample-args.mjs +174 -0
  536. package/scripts/sample-args.spec.mjs +160 -0
  537. package/scripts/shipped-definitions.mjs +197 -0
  538. package/scripts/shipped-definitions.spec.mjs +57 -0
  539. package/scripts/shipped-inputs.spec.mjs +136 -0
  540. package/scripts/shipped-recordings.spec.mjs +19 -0
  541. package/scripts/shipped-ref.d.mts +5 -0
  542. package/scripts/shipped-ref.mjs +20 -0
  543. package/scripts/shipped-ref.spec.mjs +59 -0
  544. package/scripts/shipped-registry.mjs +107 -0
  545. package/scripts/shipped-sample-candidates.mjs +69 -0
  546. package/scripts/shipped-sample-candidates.spec.mjs +117 -0
  547. package/scripts/shipped-sample.mjs +871 -0
  548. package/scripts/shipped-sample.spec.mjs +451 -0
  549. package/scripts/sync-agent-model-schemas.mjs +72 -0
  550. package/scripts/sync-api-contracts.mjs +85 -0
  551. package/scripts/sync-api-contracts.spec.mjs +144 -0
  552. package/scripts/sync-contract-ledger-schemas.mjs +161 -0
  553. package/scripts/sync-crm-stage-pool-schema.mjs +85 -0
  554. package/scripts/sync-prompt-draft-schema.mjs +92 -0
  555. package/scripts/sync-route-map.mjs +94 -0
  556. package/scripts/sync-schema-descriptions.mjs +25 -0
  557. package/scripts/sync-tool-inventory.mjs +27 -0
  558. package/scripts/sync-trigger-argument-schema.mjs +97 -0
  559. package/scripts/sync-trigger-argument-schema.spec.mjs +91 -0
  560. package/scripts/sync-trigger-event-schema.mjs +20 -0
  561. package/scripts/sync-trigger-repeat-mapping.mjs +12 -0
  562. package/scripts/sync-trigger-task-schema.mjs +45 -0
  563. package/scripts/sync-voice-actions-contract.mjs +67 -0
  564. package/scripts/sync-voice-actions-tools.mjs +97 -0
  565. package/scripts/sync-wave-id-schemas.mjs +55 -0
  566. package/scripts/telegram-personal-confirmation-mutants.mjs +74 -0
  567. package/scripts/tool-input-schemas.mjs +46 -0
  568. package/scripts/tool-input-schemas.spec.mjs +50 -0
  569. package/scripts/verify-followup-adapters.mjs +235 -0
  570. package/scripts/verify-secret-read-import.mjs +84 -0
  571. package/scripts/verify-secret-read-mutants.mjs +143 -0
  572. package/dist/tools/definitions/analytics.d.ts +0 -40
  573. package/dist/tools/definitions/analytics.js +0 -233
  574. package/dist/tools/definitions/analytics.js.map +0 -1
  575. package/dist/tools/definitions/broadcast-mailing-variants.d.ts +0 -41
  576. package/dist/tools/definitions/broadcast-mailing-variants.js +0 -194
  577. package/dist/tools/definitions/broadcast-mailing-variants.js.map +0 -1
  578. package/dist/tools/definitions/dialogue-audit.d.ts +0 -38
  579. package/dist/tools/definitions/dialogue-audit.js +0 -292
  580. package/dist/tools/definitions/dialogue-audit.js.map +0 -1
  581. package/dist/tools/definitions/getcourse-wave.js +0 -519
  582. package/dist/tools/definitions/getcourse-wave.js.map +0 -1
  583. package/dist/tools/definitions/operational-overview.d.ts +0 -3
  584. package/dist/tools/definitions/operational-overview.js +0 -23
  585. package/dist/tools/definitions/operational-overview.js.map +0 -1
  586. package/dist/tools/definitions/scheduled-tasks.js +0 -173
  587. package/dist/tools/definitions/scheduled-tasks.js.map +0 -1
  588. package/dist/tools/definitions/trigger-contact-claims.d.ts +0 -7
  589. package/dist/tools/definitions/trigger-contact-claims.js +0 -60
  590. package/dist/tools/definitions/trigger-contact-claims.js.map +0 -1
  591. package/dist/tools/registry-mapping-cases-core.d.ts +0 -38
  592. package/dist/tools/registry-mapping-cases-core.js +0 -963
  593. package/dist/tools/registry-mapping-cases-core.js.map +0 -1
  594. package/dist/tools/registry-mapping-cases-platform.d.ts +0 -2
  595. package/dist/tools/registry-mapping-cases-platform.js +0 -1052
  596. package/dist/tools/registry-mapping-cases-platform.js.map +0 -1
  597. package/dist/tools/trigger-action-config.d.ts +0 -49
  598. package/dist/tools/trigger-action-config.js +0 -171
  599. package/dist/tools/trigger-action-config.js.map +0 -1
  600. package/docs/evals/model-behavior-scorecard.md +0 -80
  601. package/docs/operation-coverage.md +0 -114
  602. package/scripts/mock-credentials.js +0 -77
  603. package/scripts/model-eval-server.js +0 -213
  604. package/scripts/run-model-eval.js +0 -447
@@ -1,514 +1,45 @@
1
+ import { withEditVersionInstructions, editVersionInstruction } from './edit-version.js';
2
+ import { agentSettingsTools } from './agent-settings.js';
3
+ import { triggerSetupActionItemSchema } from './trigger-action-item.schema.js';
4
+ import { followupSequenceConfigSchema as followupCompatSequenceConfigSchema } from './followup-getcourse-compat.js';
5
+ import { followUpPromotionInstructions } from './follow-up-promotion-instructions.js';
6
+ import { triggerUpsertTool } from './trigger-upsert.tool.js';
1
7
  import { z } from 'zod';
2
- import { assertCompleteList } from '../incomplete-list.js';
8
+ import { crmStagePoolMessage } from './crm-stage-pool.messages.js';
9
+ import { refineFollowUpConfig } from './follow-up-config.js';
3
10
  import { followUpSetupTools } from './follow-up-setup.js';
4
- import { getCourseWaveTools } from './getcourse-wave.js';
5
- import { normalizeTriggerActions } from '../trigger-action-config.js';
6
- import { PLATFORM_AGENTS_MAX_PAGE_SIZE, agentOutputConfigSchema, agentRuntimeConfigSchema, agentScopeSchema, agentToolPatchSchema, anyObjectSchema, behaviorErrorHandlingSchema, behaviorGreetingSchema, behaviorMediaHandlingSchema, behaviorMessageFilterSchema, behaviorMessageSplittingSchema, behaviorOperatorScheduleSchema, behaviorPrivacySchema, behaviorTypingBehaviorSchema, behaviorUrlHandlingSchema, buildListQuery, compactObject, defineTool, feedbackSheetRowSchema, mapBehaviorErrorHandlingInput, mapBehaviorGreetingInput, mapBehaviorMediaHandlingInput, mapBehaviorOperatorScheduleInput, mapBehaviorTypingInput, mapBehaviorUrlHandlingInput, mapOutputConfigInput, mapPipelineAutoFinishInput, mapPipelineCrmBehaviorInput, mapPlatformAccessControlInput, mapPlatformBitrix24BotSettingsInput, mapPlatformCrmBehaviorInput, mapPlatformGeneralSettingsInput, mapPlatformGetcourseSettingsInput, mapPlatformFunnelAnalyticsInput, mapPlatformInstagramCommentInput, mapPlatformSalebotSettingsInput, mapPlatformSmsgorodSettingsInput, mapPlatformVariablesConfigInput, mapPlatformWidgetMarketingInput, mapRuntimeConfigInput, modelLaneSchema, pipelineAutoFinishSchema, pipelineCrmBehaviorSchema, platformAccessControlSchema, platformBitrix24BotSettingsSchema, platformCrmBehaviorSchema, platformGeneralSettingsSchema, platformGetcourseSettingsSchema, platformFunnelAnalyticsSchema, platformInstagramCommentSchema, platformSalebotSettingsSchema, platformSetupConfirmationSchema, platformSmsgorodSettingsSchema, platformVariablesConfigSchema, mapPromptPatchOperationInput, platformWidgetMarketingSchema, PROMPT_BATCH_IDEMPOTENCY_KEY_MAX_LENGTH, PROMPT_BATCH_MAX_AGENTS, PROMPT_DIFF_MAX_LINES_LIMIT, promptPatchOperationSchema, routingRuleConditionSchema, routingRuleLeadStatusSchema, routingStrategySchema, setupConfirmation, triggerScopeSchema, uuidSchema, withInstructions, } from './shared.js';
11
+ import { withProjectedRoutingRule } from './routing-condition-projection.js';
12
+ import { withoutDraftPromptText, withoutDuplicatedPromptText } from './prompt-text-projection.js';
13
+ import { droppedShippedFields, shippedFormConflicts, shippedFormErrorHandlingSchema, shippedFormGreetingSchema, shippedFormMessageFiltersSchema, shippedFormMessageSplittingSchema, shippedFormOperatorScheduleSchema, shippedFormPrivacySchema, shippedFormTypingBehaviorSchema, translateShippedBehavior, } from './behavior-shipped-form.js';
14
+ import { behaviorCrmSchema, behaviorMediaHandlingSchema, behaviorUnsupportedInputHandlingSchema, behaviorUrlHandlingSchema, buildListQuery, compactObject, defineTool, feedbackSheetRowSchema, followUpSequenceTypeSchema, followUpTriggerSchema, knowledgeSpaceIdSchema, mapPipelineAutoFinishInput, mapPipelineCrmBehaviorInput, mapPromptPatchOperationInput, pipelineAutoFinishSchema, pipelineCrmBehaviorSchema, platformSetupConfirmationSchema, PROMPT_BATCH_IDEMPOTENCY_KEY_MAX_LENGTH, PROMPT_BATCH_MAX_AGENTS, PROMPT_DIFF_MAX_LINES_LIMIT, promptPatchOperationSchema, routingRuleConditionSchema, routingRuleLeadStatusSchema, routingStrategySchema, setupConfirmation, uuidSchema, withInstructions, withSchemaVersion, } from './shared.js';
15
+ import { platformSettingsSections, platformSettingsUpdateSchema, } from './platform-settings-update.js';
16
+ import { platformSetupWaveTools } from './platform-setup-wave.js';
17
+ import { feedbackDocumentConfirmationSchema } from './feedback-document-access.js';
7
18
  /**
8
- * Потолки названия и условия триггера — зеркала `AGENT_TRIGGER_NAME_MAX_LENGTH` и
9
- * `AGENT_TRIGGER_CONDITION_MAX_LENGTH` бэкенда. Границы общие с формой интерфейса: форма шлёт
10
- * все поля целиком на каждом сохранении, и записанное здесь значение длиннее потолка оператор
11
- * уже не смог бы сохранить из неё.
19
+ * Потолок БАЗЫ имени копии цепочки дожимов. Зеркалит `@MaxLength` DTO v2: без него агент получал
20
+ * бы поздний 400 вместо ранней понятной ошибки.
21
+ *
22
+ * ⚠️ Отгружаемая линия знает 200 — предел индекса v1.5. В v2 имя цепочки ограничено 160 на всей
23
+ * API-границе, поэтому здесь сознательно у́же; сужение объявлено строкой реестра отставания.
12
24
  */
13
- const TRIGGER_NAME_MAX_LENGTH = 100;
14
- const TRIGGER_CONDITION_MAX_LENGTH = 4000;
25
+ const FOLLOWUP_CLONE_NAME_MAX_LENGTH = 160;
26
+ export const triggerActionItemSchema = triggerSetupActionItemSchema;
27
+ export const followupSequenceConfigSchema = followupCompatSequenceConfigSchema;
15
28
  export const platformSetupTools = [
16
- defineTool({
17
- name: 'besales_workspace_overview',
18
- sideEffect: 'none',
19
- requiredFields: [],
20
- defaultWorkspaceId: true,
21
- schema: z.object({
22
- workspace_id: uuidSchema.optional(),
23
- }),
24
- createRequest: (input) => ({
25
- method: 'GET',
26
- path: `/workspaces/${input.workspace_id}/overview`,
27
- }),
28
- enhanceResponse: (response) => withInstructions(response, [
29
- 'Single-shot snapshot всего workspace: platforms (с agentsCount), ICP profiles (с segments/samples counts), feedback sheets, MCP connections summary.',
30
- 'Используй ПЕРВЫМ когда user задаёт open-ended вопросы вида "что у меня есть?" / "покажи мою настройку" — заменяет N round-trips.',
31
- '`setupCompleteness` — readiness-сигнал «что недоделано»: channelsConnected/Pending, crmConnected, hasAnchorAgent, hasKnowledge, knowledgeLinkedToChannel, hasTriggers/Followups, hasIcp, lastSandboxRunAt, suggestedNextPhase. Используй suggestedNextPhase как мягкий hint следующего фокуса (не приказ); продолжай настройку с него, а не с нуля.',
32
- 'После overview перейди на drill-down: `besales_platform_context_get` для конкретной платформы, `besales_agent_list` для агентов внутри неё.',
33
- ]),
34
- }),
35
- defineTool({
36
- name: 'besales_workspace_navigate',
37
- sideEffect: 'none',
38
- closedWorld: true,
39
- requiredFields: ['intent'],
40
- defaultWorkspaceId: true,
41
- resultPolicy: { neverTruncate: true },
42
- schema: z
43
- .object({
44
- workspace_id: uuidSchema.optional(),
45
- intent: z.enum([
46
- 'CREATE_BOT',
47
- 'IMPROVE_AGENT',
48
- 'DIAGNOSE_CONTACT',
49
- 'AUDIT_DIALOGUES',
50
- 'CAMPAIGN_REPORT',
51
- 'CONNECT_CRM',
52
- 'CONNECT_DATASOURCE',
53
- 'CONFIGURE_FOLLOWUP',
54
- 'CONTINUE_TASK',
55
- 'FREEFORM',
56
- ]),
57
- bot_type: z.enum(['FAQ', 'SALES', 'BOOKING', 'OUTBOUND', 'SUPPORT', 'UNKNOWN']).optional(),
58
- platform_id: uuidSchema.optional(),
59
- agent_id: uuidSchema.optional(),
60
- contact_id: uuidSchema.optional(),
61
- task_id: uuidSchema.optional(),
62
- question: z.string().trim().min(2).max(500).optional(),
63
- })
64
- .strict(),
65
- createRequest: (input) => ({
66
- method: 'POST',
67
- path: `/workspaces/${input.workspace_id}/navigation`,
68
- body: compactObject({
69
- intent: input.intent,
70
- botType: input.bot_type,
71
- platformId: input.platform_id,
72
- agentId: input.agent_id,
73
- contactId: input.contact_id,
74
- taskId: input.task_id,
75
- question: input.question,
76
- }),
77
- }),
78
- enhanceResponse: (response) => withInstructions(response, [
79
- 'next.tool и next.arguments — один адресный следующий шаг; placeholders перечислены в requiredUserInput и не должны угадываться.',
80
- 'Сохранённый overview — evidence только на момент ответа. Перед записью перечитай выбранный объект, а после записи выполни next.verifyWith.',
81
- 'CREATE_BOT учитывает bot_type: FAQ не требует ICP/CRM автоматически, SALES/BOOKING/OUTBOUND требуют ICP и условий до доказательства готовности.',
82
- 'FREEFORM возвращает help route и не запускает обязательный шестишаговый мастер.',
83
- ]),
84
- }),
85
- defineTool({
86
- name: 'besales_platform_context_get',
87
- sideEffect: 'none',
88
- requiredFields: ['platform_id'],
89
- resultPolicy: {
90
- neverTruncate: true,
91
- droppablePaths: ['agents[].baseSystemPrompt'],
92
- narrowingHint: 'Снимок канала отдаётся целиком и на канале с десятками агентов не помещается в ответ. Работайте по одному агенту: besales_agent_list для перечня, besales_prompt_patch_get для промпта.',
93
- },
94
- schema: z.object({
95
- platform_id: uuidSchema,
96
- sections: z
97
- .array(z.enum([
98
- 'platform',
99
- 'agent_summaries',
100
- 'agents_full',
101
- 'router',
102
- 'behavior',
103
- 'follow_up',
104
- 'pipeline_settings',
105
- 'readiness',
106
- ]))
107
- .min(1)
108
- .optional(),
109
- }),
110
- createRequest: (input) => ({
111
- method: 'GET',
112
- path: `/platforms/${input.platform_id}/setup/context` +
113
- (input.sections
114
- ? `?sections=${encodeURIComponent(input.sections.join(','))}`
115
- : ''),
116
- }),
117
- enhanceResponse: (response) => withInstructions(response, [
118
- 'Для точечного чтения передай sections; agent_summaries не содержит полный промпт, agents_full содержит.',
119
- 'Read readiness flags, then call targeted mutation tools. Do not ask the user for workspace_id.',
120
- 'Prompt content changes still go through besales_prompt_* tools and besales_prompt_finalize.',
121
- ]),
122
- }),
123
- defineTool({
124
- name: 'besales_trigger_action_catalog_get',
125
- sideEffect: 'none',
126
- requiredFields: ['platform_id'],
127
- resultPolicy: { neverTruncate: true },
128
- schema: z.object({
129
- platform_id: uuidSchema,
130
- action_type: z.string().trim().min(1).optional(),
131
- }),
132
- createRequest: (input) => ({
133
- method: 'GET',
134
- path: `/platforms/${input.platform_id}/setup/trigger-action-catalog` +
135
- (input.action_type ? `?actionType=${encodeURIComponent(input.action_type)}` : ''),
136
- }),
137
- enhanceResponse: (response) => withInstructions(response, [
138
- 'Каталог построен из боевого CreateTriggerActionDto и канона TRIGGER_ACTION_CONFIG.',
139
- 'Перед созданием нового actionType запроси его отдельно через action_type и используй minimalExample без угадывания имени config-поля.',
140
- 'После записи выполни verification из записи каталога; перечитывание контекста проверяет сохранение, но не внешний эффект.',
141
- ]),
142
- }),
143
- defineTool({
144
- name: 'besales_agent_list',
145
- sideEffect: 'none',
146
- requiredFields: ['platform_id'],
147
- resultPolicy: { neverTruncate: true },
148
- schema: z.object({
149
- platform_id: uuidSchema,
150
- limit: z.number().int().min(1).max(PLATFORM_AGENTS_MAX_PAGE_SIZE).optional(),
151
- cursor: z.string().min(1).optional(),
152
- query: z.string().min(1).optional(),
153
- }),
154
- createRequest: (input) => {
155
- const query = new URLSearchParams();
156
- if (input.limit !== undefined)
157
- query.set('limit', String(input.limit));
158
- if (input.cursor)
159
- query.set('cursor', input.cursor);
160
- if (input.query)
161
- query.set('q', input.query);
162
- const suffix = query.size > 0 ? `?${query.toString()}` : '';
163
- return { method: 'GET', path: `/platforms/${input.platform_id}/agents${suffix}` };
164
- },
165
- enhanceResponse: (response, input) => assertCompleteList(response, {
166
- pageRequested: input.limit !== undefined || input.cursor !== undefined,
167
- toolName: 'besales_agent_list',
168
- howToPage: `Повтори вызов с limit до ${PLATFORM_AGENTS_MAX_PAGE_SIZE} и cursor из ответа, пока cursor не станет пустым.`,
169
- }),
170
- }),
171
- defineTool({
172
- name: 'besales_agent_get',
173
- sideEffect: 'none',
174
- requiredFields: ['agent_id'],
175
- resultPolicy: { neverTruncate: true },
176
- schema: z.object({
177
- agent_id: uuidSchema,
178
- }),
179
- createRequest: (input) => ({
180
- method: 'GET',
181
- path: `/agents/${input.agent_id}`,
182
- }),
183
- }),
184
- defineTool({
185
- name: 'besales_agent_readiness_get',
186
- sideEffect: 'none',
187
- closedWorld: true,
188
- requiredFields: ['agent_id'],
189
- resultPolicy: { neverTruncate: true },
190
- schema: z.object({ agent_id: uuidSchema }).strict(),
191
- createRequest: (input) => ({
192
- method: 'GET',
193
- path: `/agents/${input.agent_id}/readiness`,
194
- }),
195
- enhanceResponse: (response) => withInstructions(response, [
196
- 'Сейчас readiness всегда отвечает NOT_PROVEN: API не фиксирует версию зависимых настроек (behavior, routing, triggers, knowledge, ICP), и повтор sandbox этого не снимает. Не обещай пользователю READY.',
197
- 'Выполни адресные пункты missing и перечитай readiness; promptAndAgentCurrent=true означает только актуальность промпта и записи агента.',
198
- 'passRate не является quality. Нужны COMPLETED, свежая конфигурация, findings, qualityRate и checksRate с expectations.',
199
- 'crmAuthorization=NOT_EVALUATED не подтверждает live-доступ CRM; проверяй его отдельной health/authorization операцией, если CRM нужна сценарию.',
200
- ]),
201
- }),
202
- defineTool({
203
- name: 'besales_agent_variable_overrides_get',
204
- sideEffect: 'none',
205
- requiredFields: ['platform_id', 'agent_id'],
206
- resultPolicy: { neverTruncate: true },
207
- schema: z.object({
208
- platform_id: uuidSchema,
209
- agent_id: uuidSchema,
210
- }),
211
- createRequest: (input) => ({
212
- method: 'GET',
213
- path: `/platforms/${input.platform_id}/agents/${input.agent_id}/variable-overrides`,
214
- }),
215
- enhanceResponse: (response) => withInstructions(response, [
216
- 'Read-only: текущие перезаписи переменных агента. `workspaceOverrides[]` — перезаписи WorkspaceVariable ({{{name}}}); `customOverrides[]` — перезаписи платформенной CustomVariable ({name}). Каждая: id переменной + name + type + overrideValue.',
217
- 'Читай ПЕРЕД besales_agent_update: поля agent_workspace_variable_overrides / agent_variable_overrides заменяют набор ЦЕЛИКОМ (delete отсутствующих + upsert присланных). Чтобы не затереть уже выставленную перезапись (напр. registration_link), переотправь её вместе с новыми.',
218
- 'Пустой набор → у агента нет перезаписей, он наследует дефолты переменных воркспейса/платформы.',
219
- ]),
220
- }),
221
- defineTool({
222
- name: 'besales_getcourse_departments_list',
223
- sideEffect: 'none',
224
- requiredFields: ['platform_id'],
225
- schema: z.object({
226
- platform_id: uuidSchema,
227
- }),
228
- createRequest: (input) => ({
229
- method: 'GET',
230
- path: `/platforms/${input.platform_id}/getcourse/departments`,
231
- }),
232
- enhanceResponse: (response) => withInstructions(response, [
233
- 'Живой список отделов GetCourse Inbox школы ({ id, title }).',
234
- 'Используй department.id как target_department_id в besales_platform_settings_update (getcourse_settings) для department-routing.',
235
- ]),
236
- }),
237
- ...getCourseWaveTools,
238
- defineTool({
239
- name: 'besales_wazzup_templates_list',
240
- sideEffect: 'none',
241
- requiredFields: ['platform_id'],
242
- defaultWorkspaceId: true,
243
- schema: z.object({
244
- workspace_id: uuidSchema.optional(),
245
- platform_id: uuidSchema,
246
- }),
247
- createRequest: (input) => ({
248
- method: 'GET',
249
- path: `/workspaces/${input.workspace_id}/wazzup-waves/templates/${input.platform_id}`,
250
- }),
251
- enhanceResponse: (response) => withInstructions(response, [
252
- 'Шаблоны WABA платформы Wazzup: templateGuid, title, status модерации Meta, bodyText, variableCount (сколько значений переменных нужно), usable + unsupportedReasons.',
253
- 'В волне используй ТОЛЬКО шаблоны с usable=true. Остальные либо не одобрены Meta, либо содержат медиа-заголовок / переменную в URL-кнопке — там значения ушли бы не в те слоты.',
254
- 'variableCount считается по МАКСИМАЛЬНОМУ индексу {{n}}: «{{1}} … {{2}} … {{1}}» — это 2 значения, а не 3.',
255
- ]),
256
- }),
257
- defineTool({
258
- name: 'besales_wazzup_wave_import',
259
- sideEffect: 'spend',
260
- requiredFields: ['platform_id', 'template_guid', 'contacts'],
261
- defaultWorkspaceId: true,
262
- schema: z
263
- .object({
264
- workspace_id: uuidSchema.optional(),
265
- platform_id: uuidSchema,
266
- template_guid: z.string().trim().max(100),
267
- template_values: z.array(z.string()).max(20).optional(),
268
- contacts: z
269
- .array(z.object({
270
- phone: z.string().trim().max(32),
271
- name: z.string().max(200).optional(),
272
- }))
273
- .min(1)
274
- .max(500),
275
- funnel: z.string().max(200).optional(),
276
- segment: z.string().max(200).optional(),
277
- product_code: z
278
- .string()
279
- .trim()
280
- .max(100)
281
- .regex(/^[^\s/]+$/, 'product_code: без пробелов и «/»')
282
- .optional(),
283
- product_name: z.string().max(200).optional(),
284
- cohort_label: z.string().max(200).optional(),
285
- confirm: z.boolean().optional(),
286
- /**
287
- * Обязателен ВМЕСТЕ с confirm=true: волна необратима и платна (каждый WABA-шаблон
288
- * тарифицируется Meta). Dry-run (без confirm) подтверждения не требует.
289
- */
290
- explicit_confirmation: z.literal(true).optional(),
291
- confirmation_reason: z.string().optional(),
292
- })
293
- .refine((input) => !input.confirm || input.explicit_confirmation === true, {
294
- message: 'Реальный запуск волны требует explicit_confirmation=true: сообщения платные и необратимые',
295
- path: ['explicit_confirmation'],
296
- }),
297
- createRequest: (input) => ({
298
- method: 'POST',
299
- path: `/workspaces/${input.workspace_id}/wazzup-waves/import`,
300
- body: compactObject({
301
- platformId: input.platform_id,
302
- templateGuid: input.template_guid,
303
- templateValues: input.template_values,
304
- funnel: input.funnel,
305
- segment: input.segment,
306
- productCode: input.product_code,
307
- productName: input.product_name,
308
- cohortLabel: input.cohort_label,
309
- contacts: input.contacts?.map((c) => compactObject({ phone: c.phone, name: c.name })),
310
- confirm: input.confirm,
311
- }),
312
- }),
313
- enhanceResponse: (response) => withInstructions(response, [
314
- 'Волна WhatsApp через Wazzup: одобренный WABA-шаблон уходит по когорте телефонов. Ответы получателей обрабатывает AI-агент платформы, волна видна в «Аналитике рассылок» (канал WhatsApp).',
315
- 'БЕЗ confirm=true — DRY-RUN: прогоняется ПОЛНЫЙ preflight (платформа, живой WABA-канал, шаблон, число значений) и возвращается previewText — НИ ОДНО сообщение не отправляется. Покажи previewText пользователю и запускай реально только с confirm=true.',
316
- 'Реальный запуск требует ОДНОВРЕМЕННО confirm=true и explicit_confirmation=true — второе ставится только после явного согласия пользователя на отправку платных сообщений.',
317
- 'КАЖДОЕ маркетинговое сообщение WhatsApp ПЛАТНОЕ, а Meta ограничивает число уникальных получателей в сутки (на старте 250, дальше растёт после верификации бизнеса). Не запускай большие когорты без явного согласия пользователя.',
318
- 'template_guid бери из besales_wazzup_templates_list (только usable=true). Длина template_values обязана совпасть с variableCount шаблона, иначе запуск отклонят.',
319
- 'Повторная отправка ТОГО ЖЕ шаблона тому же контакту в течение суток пропускается автоматически (защита от двойного списания). Другой шаблон той же когорте не блокируется.',
320
- 'Пропускаются контакты, остановившие бота, ждущие оператора и заблокированные — они попадут в skipped, а не в failed.',
321
- 'В ответе confirm-запуска — jobId. Опрашивай его через besales_wazzup_wave_status до status=COMPLETED (отправки идут с паузами).',
322
- ]),
323
- }),
324
- defineTool({
325
- name: 'besales_wazzup_wave_status',
326
- sideEffect: 'none',
327
- requiredFields: ['job_id'],
328
- defaultWorkspaceId: true,
329
- schema: z.object({
330
- workspace_id: uuidSchema.optional(),
331
- job_id: uuidSchema,
332
- }),
333
- createRequest: (input) => ({
334
- method: 'GET',
335
- path: `/workspaces/${input.workspace_id}/wazzup-waves/${input.job_id}`,
336
- }),
337
- enhanceResponse: (response) => withInstructions(response, [
338
- 'Статус волны WhatsApp: status (PROCESSING|COMPLETED), processedRows, sent/failed/skipped, errors (построчные причины).',
339
- 'skipped — сознательные пропуски (клиент остановил бота, ждёт оператора, недавно уже получал этот шаблон). Это НЕ ошибки: сумма sent+failed+skipped равна числу обработанных строк.',
340
- 'Доставка приходит вебхуками WhatsApp и живёт ОТДЕЛЬНО от исхода отправки: delivered/read/deliveryFailed + deliveryErrors (коды). Докладывай их вместе с sent — «отправлено» означает лишь, что Wazzup принял сообщение.',
341
- 'delivered и deliveryFailed взаимоисключающи; read — подмножество delivered. unknownOutcome — строки, занятые под отправку без известного исхода (краш между claim и ответом Wazzup); автоматически они НЕ переотправляются и требуют ручного разбора.',
342
- ]),
343
- }),
344
- defineTool({
345
- name: 'besales_agent_create',
346
- sideEffect: 'write',
347
- requiredFields: ['platform_id', 'name', 'model_lane'],
348
- schema: z.object({
349
- platform_id: uuidSchema,
350
- name: z.string(),
351
- description: z.string().nullable().optional(),
352
- model_lane: modelLaneSchema,
353
- // Явный id модели (override). Если задан — побеждает model_lane.
354
- // Список доступных моделей — besales_model_catalog_list.
355
- model: z.string().optional(),
356
- default_icp_profile_id: uuidSchema.optional(),
357
- // Phase 1 — перезаписи переменных на уровне агента (бьют по CustomVariable платформы).
358
- agent_variable_overrides: z
359
- .array(z.object({
360
- custom_variable_id: uuidSchema,
361
- override_value: z.union([z.string(), z.number(), z.boolean()]),
362
- }))
363
- .optional(),
364
- // Перезаписи переменных воркспейса на уровне агента (бьют по WorkspaceVariable).
365
- agent_workspace_variable_overrides: z
366
- .array(z.object({
367
- workspace_variable_id: uuidSchema,
368
- override_value: z.union([z.string(), z.number(), z.boolean()]),
369
- }))
370
- .optional(),
371
- }),
372
- createRequest: (input) => ({
373
- path: `/platforms/${input.platform_id}/agents`,
374
- body: compactObject({
375
- name: input.name,
376
- description: input.description,
377
- modelLane: input.model_lane,
378
- model: input.model,
379
- defaultIcpProfileId: input.default_icp_profile_id,
380
- agentVariableOverrides: input.agent_variable_overrides?.map((o) => ({
381
- customVariableId: o.custom_variable_id,
382
- overrideValue: o.override_value,
383
- })),
384
- agentWorkspaceVariableOverrides: input.agent_workspace_variable_overrides?.map((o) => ({
385
- workspaceVariableId: o.workspace_variable_id,
386
- overrideValue: o.override_value,
387
- })),
388
- }),
389
- }),
390
- }),
391
- defineTool({
392
- name: 'besales_agent_clone',
393
- sideEffect: 'write',
394
- requiredFields: ['platform_id', 'source_agent_id', 'name'],
395
- schema: z.object({
396
- // Платформа-источник; клон приземляется на неё же (cross-platform не поддерживается).
397
- platform_id: uuidSchema,
398
- // Исходный AgentChat для глубокого копирования (обязан принадлежать platform_id).
399
- source_agent_id: uuidSchema,
400
- // Системное имя нового агента; при коллизии backend добавит суффикс _N.
401
- name: z.string(),
402
- // Отображаемое имя нового агента; если не задано — зеркалит name.
403
- display_name: z.string().optional(),
404
- }),
405
- createRequest: (input) => ({
406
- method: 'POST',
407
- path: `/platforms/${input.platform_id}/agents/${input.source_agent_id}/clone`,
408
- body: compactObject({
409
- name: input.name,
410
- displayName: input.display_name,
411
- }),
412
- }),
413
- enhanceResponse: (response) => withInstructions(response, [
414
- 'Клон — глубокая копия исходного агента на ТОЙ ЖЕ платформе (platform_id): baseSystemPrompt, knowledge namespaces, модель/model-lane/runtime, tools + builtin tools, перезаписи переменных (agent + workspace), ICP-линки и ВСЕ триггеры+действия скопированы на новый agent id (в ответе agent.id).',
415
- 'НЕ скопированы (осознанно): routing rules (per-router) и per-platform behavior. Клон инертен, пока не привязан к роутеру — добавь routing rule (besales_routing_rule_upsert), чтобы диалоги на него попадали.',
416
- 'Промпт идентичен источнику; PromptHub авто-bootstrap создаст новую версию при первой prompt-операции (besales_prompt_*). Cross-platform клон не поддерживается — для переноса на другую платформу используй besales_platform_clone_*.',
417
- ]),
418
- }),
419
- defineTool({
420
- name: 'besales_agent_update',
421
- sideEffect: 'write',
422
- requiredFields: ['platform_id', 'agent_id'],
423
- schema: z.object({
424
- platform_id: uuidSchema,
425
- agent_id: uuidSchema,
426
- name: z.string().optional(),
427
- description: z.string().nullable().optional(),
428
- model_lane: modelLaneSchema.optional(),
429
- // Явный id модели (override). Если задан — побеждает model_lane.
430
- // Список доступных моделей — besales_model_catalog_list.
431
- model: z.string().optional(),
432
- default_icp_profile_id: uuidSchema.nullable().optional(),
433
- use_global_history: z.boolean().optional(),
434
- adapt_to_user_language: z.boolean().optional(),
435
- // v1.5 Increment 3 Group B — typed sections.
436
- runtime_config: agentRuntimeConfigSchema.optional(),
437
- output_config: agentOutputConfigSchema.optional(),
438
- knowledge_space_ids: z.array(uuidSchema).optional(),
439
- agent_scope: agentScopeSchema.optional(),
440
- // Phase 1 — перезаписи переменных на уровне агента (полная замена набора).
441
- agent_variable_overrides: z
442
- .array(z.object({
443
- custom_variable_id: uuidSchema,
444
- override_value: z.union([z.string(), z.number(), z.boolean()]),
445
- }))
446
- .optional(),
447
- // Перезаписи переменных воркспейса на уровне агента (полная замена набора).
448
- agent_workspace_variable_overrides: z
449
- .array(z.object({
450
- workspace_variable_id: uuidSchema,
451
- override_value: z.union([z.string(), z.number(), z.boolean()]),
452
- }))
453
- .optional(),
454
- }),
455
- createRequest: (input) => ({
456
- method: 'PATCH',
457
- path: `/platforms/${input.platform_id}/agents/${input.agent_id}`,
458
- body: compactObject({
459
- name: input.name,
460
- description: input.description,
461
- modelLane: input.model_lane,
462
- model: input.model,
463
- defaultIcpProfileId: input.default_icp_profile_id,
464
- useGlobalHistory: input.use_global_history,
465
- adaptToUserLanguage: input.adapt_to_user_language,
466
- runtimeConfig: input.runtime_config
467
- ? mapRuntimeConfigInput(input.runtime_config)
468
- : undefined,
469
- outputConfig: input.output_config ? mapOutputConfigInput(input.output_config) : undefined,
470
- knowledgeSpaceIds: input.knowledge_space_ids,
471
- agentScope: input.agent_scope,
472
- agentVariableOverrides: input.agent_variable_overrides?.map((o) => ({
473
- customVariableId: o.custom_variable_id,
474
- overrideValue: o.override_value,
475
- })),
476
- agentWorkspaceVariableOverrides: input.agent_workspace_variable_overrides?.map((o) => ({
477
- workspaceVariableId: o.workspace_variable_id,
478
- overrideValue: o.override_value,
479
- })),
480
- }),
481
- }),
482
- }),
29
+ ...platformSetupWaveTools,
30
+ ...agentSettingsTools,
483
31
  // Phase B (2026-05-27): `besales_agent_legacy_self_analysis_set` удалён.
484
32
  // В v2 заменён post_processors (Routing Studio Critic node) + post_processor_bindings.
485
- defineTool({
486
- name: 'besales_agent_tools_update',
487
- sideEffect: 'write',
488
- requiredFields: ['platform_id', 'agent_id', 'tools'],
489
- schema: z.object({
490
- platform_id: uuidSchema,
491
- agent_id: uuidSchema,
492
- tools: z.array(agentToolPatchSchema).min(1),
493
- }),
494
- createRequest: (input) => ({
495
- method: 'PATCH',
496
- path: `/platforms/${input.platform_id}/agents/${input.agent_id}/tools`,
497
- body: {
498
- tools: input.tools.map((tool) => compactObject({
499
- toolId: tool.tool_id,
500
- priority: tool.priority,
501
- isEnabled: tool.is_enabled,
502
- agentSpecificConditions: tool.agent_specific_conditions,
503
- })),
504
- },
505
- }),
506
- }),
507
33
  defineTool({
508
34
  name: 'besales_router_update',
509
35
  sideEffect: 'write',
510
36
  requiredFields: ['platform_id'],
511
37
  schema: z.object({
38
+ expected_version: z
39
+ .string()
40
+ .min(1)
41
+ .regex(/^[A-Za-z0-9_.-]+$/u)
42
+ .optional(),
512
43
  platform_id: uuidSchema,
513
44
  name: z.string().optional(),
514
45
  model: z.string().optional(),
@@ -522,8 +53,9 @@ export const platformSetupTools = [
522
53
  }),
523
54
  createRequest: (input) => ({
524
55
  method: 'PATCH',
525
- path: `/platforms/${input.platform_id}/router`,
56
+ path: `/channels/${input.platform_id}/router`,
526
57
  body: compactObject({
58
+ expectedVersion: input.expected_version,
527
59
  name: input.name,
528
60
  model: input.model,
529
61
  temperature: input.temperature,
@@ -535,12 +67,18 @@ export const platformSetupTools = [
535
67
  ...setupConfirmation(input),
536
68
  }),
537
69
  }),
70
+ enhanceResponse: withEditVersionInstructions,
538
71
  }),
539
72
  defineTool({
540
73
  name: 'besales_routing_rule_upsert',
541
74
  sideEffect: 'write',
542
75
  requiredFields: ['platform_id', 'routing_strategy', 'custom_router_prompt'],
543
76
  schema: z.object({
77
+ expected_version: z
78
+ .string()
79
+ .min(1)
80
+ .regex(/^[A-Za-z0-9_.-]+$/u)
81
+ .optional(),
544
82
  platform_id: uuidSchema,
545
83
  routing_rule_id: uuidSchema.optional(),
546
84
  routing_strategy: routingStrategySchema,
@@ -561,26 +99,19 @@ export const platformSetupTools = [
561
99
  }),
562
100
  createRequest: (input) => ({
563
101
  method: input.routing_rule_id ? 'PATCH' : 'POST',
564
- path: `/platforms/${input.platform_id}/router/routing-rules`,
102
+ path: `/channels/${input.platform_id}/router/routing-rules`,
565
103
  body: compactObject({
104
+ expectedVersion: input.expected_version,
566
105
  routingRuleId: input.routing_rule_id,
567
106
  routingStrategy: input.routing_strategy,
568
107
  dealMode: input.deal_mode,
569
108
  customVariableId: input.custom_variable_id,
570
109
  variableValue: input.variable_value,
571
110
  conditionLogic: input.condition_logic,
572
- conditions: input.conditions?.map((condition) => ({
111
+ conditions: input.conditions?.map((condition) => compactObject({
573
112
  customVariableId: condition.custom_variable_id,
574
- // Набор — источник истины; legacy-скаляр пробрасываем как есть (API примет обе формы).
575
- // Без этого маппинга variable_values терялся бы молча: до правки сюда уходил только скаляр.
576
- // Незаданную форму не отправляем вовсе: явный undefined в теле выглядел бы как
577
- // «поле передано пустым» и мешал бы взаимоисключающей валидации на стороне API.
578
- ...(condition.variable_values !== undefined
579
- ? { variableValues: condition.variable_values }
580
- : {}),
581
- ...(condition.variable_value !== undefined
582
- ? { variableValue: condition.variable_value }
583
- : {}),
113
+ variableValue: condition.variable_value,
114
+ variableValues: condition.variable_values,
584
115
  })),
585
116
  customRouterPrompt: input.custom_router_prompt,
586
117
  isEnabled: input.is_enabled,
@@ -596,102 +127,9 @@ export const platformSetupTools = [
596
127
  ...setupConfirmation(input),
597
128
  }),
598
129
  }),
130
+ enhanceResponse: (response) => withEditVersionInstructions(withProjectedRoutingRule(response)),
599
131
  }),
600
- defineTool({
601
- name: 'besales_trigger_upsert',
602
- sideEffect: 'write',
603
- requiredFields: ['platform_id', 'agent_id'],
604
- schema: z.object({
605
- platform_id: uuidSchema,
606
- agent_id: uuidSchema,
607
- trigger_id: uuidSchema.optional(),
608
- // `.trim()` — как у формы и бэкенда: строка из пробелов пустая, «Оплата » равна «Оплата».
609
- name: z.string().trim().min(1).max(TRIGGER_NAME_MAX_LENGTH).optional(),
610
- condition: z.string().trim().min(1).max(TRIGGER_CONDITION_MAX_LENGTH).optional(),
611
- is_enabled: z.boolean().optional(),
612
- priority: z.number().int().min(1).max(100).optional(),
613
- stop_propagation: z.boolean().optional(),
614
- /** Повтор ВНУТРИ одного ответа модели. Горизонт — этот ответ, дальше состояние теряется. */
615
- allow_repeated_calls: z.boolean().optional(),
616
- /**
617
- * Одно срабатывание на контакт НАВСЕГДА (право в `agent_trigger_contact_claims`).
618
- * Ось другая, чем у `allow_repeated_calls`: тот живёт один ответ, этот переживает
619
- * все следующие сообщения. Для действий, пишущих в чужие системы (заметка в CRM).
620
- */
621
- run_once_per_contact: z.boolean().optional(),
622
- scope: triggerScopeSchema,
623
- metadata: anyObjectSchema.optional(),
624
- /**
625
- * Действия триггера. Конфиг действия кладётся в поле, ИМЯ которого зависит от actionType:
626
- * правило `camelCase(actionType) + 'Config'`, но у пяти типов имена легаси
627
- * (см. `TRIGGER_ACTION_CONFIG_NAMES`). Имя в ОТВЕТЕ API другое — MCP принимает оба.
628
- */
629
- actions: z.array(anyObjectSchema).optional(),
630
- replace_actions: z.boolean().optional(),
631
- ...platformSetupConfirmationSchema,
632
- }).superRefine((input, ctx) => {
633
- if (!input.actions?.length) {
634
- return;
635
- }
636
- for (const issue of normalizeTriggerActions(input.actions)
637
- .issues) {
638
- ctx.addIssue({
639
- code: z.ZodIssueCode.custom,
640
- path: ['actions', issue.index],
641
- message: issue.message,
642
- });
643
- }
644
- }),
645
- createRequest: (input) => ({
646
- method: input.trigger_id ? 'PATCH' : 'POST',
647
- path: input.trigger_id
648
- ? `/platforms/${input.platform_id}/agents/${input.agent_id}/triggers/${input.trigger_id}`
649
- : `/platforms/${input.platform_id}/agents/${input.agent_id}/triggers`,
650
- body: compactObject({
651
- name: input.name,
652
- condition: input.condition,
653
- isEnabled: input.is_enabled,
654
- priority: input.priority,
655
- stopPropagation: input.stop_propagation,
656
- allowRepeatedCalls: input.allow_repeated_calls,
657
- runOncePerContact: input.run_once_per_contact,
658
- scope: input.scope,
659
- metadata: input.metadata,
660
- // Конфиг под именем связи (как его отдаёт besales_platform_context_get) переименовывается
661
- // в ключ входа: бэкенд с forbidNonWhitelisted отверг бы имя ответа как «лишнее свойство».
662
- actions: input.actions
663
- ? normalizeTriggerActions(input.actions).actions
664
- : undefined,
665
- replaceActions: input.replace_actions,
666
- ...setupConfirmation(input),
667
- }),
668
- }),
669
- enhanceResponse: (response) => withInstructions(response, [
670
- 'Конфиг действия кладётся в поле, имя которого зависит от actionType: правило ' +
671
- 'camelCase(actionType)+"Config" (CRM_UPDATE_FIELD → crmUpdateFieldConfig). Пять исключений: ' +
672
- 'CRM_MOVE_STAGE → crmConfig, SCHEDULE_FOLLOWUP → scheduleFollowUpConfig, ' +
673
- 'SUMMARIZE_DIALOG → summarizeConfig, SEND_TELEGRAM_CHANNEL_MESSAGE → telegramChannelConfig, ' +
674
- 'CRM_RENAME_DEAL → renameDealConfig. В ОТВЕТЕ тот же конфиг приходит под именем связи ' +
675
- '(crmMoveStage, summarizeAction, telegramChannelMessage, renameDeal, scheduleFollowUp) — ' +
676
- 'пересылать прочитанное можно как есть: MCP переименует конфиг и снимет поля, которые ' +
677
- 'ответ отдаёт, а вход не принимает (id, triggerId, createdAt, updatedAt, пустые связи).',
678
- 'Действие с обязательным конфигом, отправленное без него, бэкенд отвергает: раньше оно ' +
679
- 'сохранялось пустым, отвечало 200, а отказ всплывал только в живом диалоге.',
680
- 'replace_actions=true заменяет ВЕСЬ набор действий триггера (delete-and-recreate, как в UI) — ' +
681
- 'сперва прочитай текущие действия (besales_platform_context_get) и передай ПОЛНЫЙ желаемый набор, ' +
682
- 'а не дельту, иначе потеряешь не переданные действия.',
683
- 'Без replace_actions передача actions на существующем триггере отклоняется (защита от случайной потери).',
684
- 'SILENT_AI: оси молчания РАЗДЕЛЬНЫЕ (silenceBot — бот перестаёт отвечать; ' +
685
- 'silenceFollowUps — цепочки перестают инициировать касания), и обе включены ПО УМОЛЧАНИЮ. ' +
686
- 'При replace_actions передавай их ЯВНО: пересобрав действие без этих полей, ты молча ' +
687
- 'вернёшь выключенную ось во включённую (дефолт = прежнее поведение экшена, а не ' +
688
- '«как было»). Обе выключенные отвергаются.',
689
- 'allow_repeated_calls и run_once_per_contact — РАЗНЫЕ оси, не синонимы: первый про повтор ' +
690
- 'внутри одного ответа модели, второй запрещает срабатывание навсегда после первого ' +
691
- 'успешного действия у этого контакта. Для действий, пишущих в чужие системы (заметка в CRM, ' +
692
- 'создание сделки), нужен именно run_once_per_contact.',
693
- ]),
694
- }),
132
+ triggerUpsertTool,
695
133
  defineTool({
696
134
  name: 'besales_trigger_delete',
697
135
  sideEffect: 'write',
@@ -707,7 +145,7 @@ export const platformSetupTools = [
707
145
  .strict(),
708
146
  createRequest: (input) => ({
709
147
  method: 'DELETE',
710
- path: `/platforms/${input.platform_id}/agents/${input.agent_id}/triggers/${input.trigger_id}`,
148
+ path: `/channels/${input.platform_id}/agents/${input.agent_id}/triggers/${input.trigger_id}`,
711
149
  body: setupConfirmation(input),
712
150
  }),
713
151
  enhanceResponse: (response) => withInstructions(response, [
@@ -721,62 +159,174 @@ export const platformSetupTools = [
721
159
  requiredFields: ['platform_id'],
722
160
  schema: z
723
161
  .object({
162
+ expected_version: z
163
+ .string()
164
+ .min(1)
165
+ .regex(/^[A-Za-z0-9_.-]+$/u)
166
+ .optional(),
724
167
  platform_id: uuidSchema,
725
- // v1.5 Increment 3 Group C.1 (Phase B, 2026-05-27): только typed sections.
726
- greeting: behaviorGreetingSchema.optional(),
168
+ // Секции с прежними именами полей принимают и прежнюю форму вызова (перевод — behavior-shipped-form.ts).
169
+ greeting: shippedFormGreetingSchema.optional(),
727
170
  media_handling: behaviorMediaHandlingSchema.optional(),
171
+ unsupported_input_handling: behaviorUnsupportedInputHandlingSchema.optional(),
728
172
  url_handling: behaviorUrlHandlingSchema.optional(),
729
- error_handling: behaviorErrorHandlingSchema.optional(),
730
- operator_schedule: behaviorOperatorScheduleSchema.optional(),
731
- typing_behavior: behaviorTypingBehaviorSchema.optional(),
732
- message_filters: z.array(behaviorMessageFilterSchema).optional(),
733
- message_splitting: behaviorMessageSplittingSchema.optional(),
734
- privacy: behaviorPrivacySchema.optional(),
173
+ error_handling: shippedFormErrorHandlingSchema.optional(),
174
+ operator_schedule: shippedFormOperatorScheduleSchema.optional(),
175
+ typing_behavior: shippedFormTypingBehaviorSchema.optional(),
176
+ message_filters: shippedFormMessageFiltersSchema.optional(),
177
+ message_splitting: shippedFormMessageSplittingSchema.optional(),
178
+ privacy: shippedFormPrivacySchema.optional(),
179
+ crm_behavior: behaviorCrmSchema.optional(),
735
180
  ...platformSetupConfirmationSchema,
736
181
  })
737
- .strict(),
182
+ .strict()
183
+ .superRefine((value, context) => {
184
+ for (const conflict of shippedFormConflicts(value)) {
185
+ context.addIssue({
186
+ code: 'custom',
187
+ path: conflict.path,
188
+ message: conflict.message,
189
+ });
190
+ }
191
+ }),
192
+ createRequest: (input) => {
193
+ // ⛔ Сервер видит только канон новой версии: прежние имена и форма переводятся ЗДЕСЬ, одной функцией.
194
+ const sections = translateShippedBehavior({
195
+ greeting: input.greeting,
196
+ error_handling: input.error_handling,
197
+ operator_schedule: input.operator_schedule,
198
+ typing_behavior: input.typing_behavior,
199
+ message_filters: input.message_filters,
200
+ message_splitting: input.message_splitting,
201
+ privacy: input.privacy,
202
+ });
203
+ const section = (name) => withSchemaVersion(sections[name]);
204
+ return {
205
+ method: 'PATCH',
206
+ path: `/channels/${input.platform_id}/behavior`,
207
+ body: compactObject({
208
+ expectedVersion: input.expected_version,
209
+ greeting: section('greeting'),
210
+ mediaHandling: withSchemaVersion(input.media_handling),
211
+ unsupportedInputHandling: withSchemaVersion(input.unsupported_input_handling),
212
+ urlHandling: withSchemaVersion(input.url_handling),
213
+ errorHandling: section('error_handling'),
214
+ operatorSchedule: section('operator_schedule'),
215
+ typingBehavior: section('typing_behavior'),
216
+ messageFilters: section('message_filters'),
217
+ messageSplitting: section('message_splitting'),
218
+ privacy: section('privacy'),
219
+ crmBehavior: withSchemaVersion(input.crm_behavior),
220
+ ...setupConfirmation(input),
221
+ }),
222
+ };
223
+ },
224
+ enhanceResponse: (response, input) => withInstructions(response, [
225
+ editVersionInstruction(),
226
+ ...droppedShippedFields(input).map((field) => `Поле ${field} прежней версии не исполнялось и там, в новой не хранится — значение отброшено.`),
227
+ 'Секция СЛИВАЕТСЯ с текущей: присылай только те поля, которые меняешь — соседние сохранятся. null у поля очищает его.',
228
+ 'У канала, который ещё не настраивали, сливать не с чем: ПЕРВАЯ запись секции обязана быть полной. Текущее состояние читается besales_platform_context_get (поле behavior).',
229
+ 'В message_filters.rules образец source должен быть непустым после trim(), но значимые краевые пробелы сохраняются. Несимволы Unicode запрещены и в source, и в target. Сервер раскрывает в target \\n, \\t, \\r и \\\\ за один проход; чтение экранирует обратную черту, поэтому прочитанное target можно отправить обратно без двойного раскрытия.',
230
+ '⚠️ Требуют explicit_confirmation: смена вызова оператора у вложений/ссылок/ошибок, включение PROCESS_WITH_LLM у картинки или документа (в модель уходит содержимое чужих файлов), выключение паузы после ответа оператора, выключение обезличивания и расширение списка исключённых типов PII, смена включённости и типа входящего фильтра по сделке.',
231
+ 'crm_behavior.inbound_deal_filter — входящий фильтр по сделке GetCourse: бот отвечает только тем, у кого есть подходящая сделка (метка TAG либо значение поля CUSTOM_FIELD, для него нужен ещё field_id — ИМЯ поля). Включённый фильтр обязан быть полным, иначе отказ BEHAVIOR_SECTION_INVALID с путём inbound_deal_filter. Раздел сливается с сохранённым CRM-поведением: у канала без привязанной CRM его не записать.',
232
+ ]),
233
+ }),
234
+ defineTool({
235
+ name: 'besales_followup_sequence_upsert',
236
+ sideEffect: 'write',
237
+ requiredFields: ['platform_id', 'name', 'type', 'trigger', 'config'],
238
+ schema: z
239
+ .object({
240
+ platform_id: uuidSchema,
241
+ sequence_id: uuidSchema.optional(),
242
+ expected_version: z
243
+ .string()
244
+ .regex(/^[1-9][0-9]{0,9}$/u)
245
+ .optional()
246
+ .describe('expected_version — исходная editRevision открытой формы цепочки; передай её явно для защиты от перезаписи чужих изменений. Без expected_version для PATCH нужны read:workflows и write:workflows: мост читает текущую ревизию перед записью; ошибка чтения отменяет запись. Это защищает только окно между GET и PATCH, но не изменения после открытия формы и до GET. Конфликт 409 возвращается без автоматического повтора.'),
247
+ name: z.string(),
248
+ description: z.string().nullable().optional(),
249
+ type: followUpSequenceTypeSchema,
250
+ enabled: z.boolean().optional(),
251
+ trigger: followUpTriggerSchema,
252
+ config: followupSequenceConfigSchema,
253
+ ...platformSetupConfirmationSchema,
254
+ })
255
+ .superRefine(refineFollowUpConfig)
256
+ .superRefine((input, context) => {
257
+ if (input.trigger !== 'USER_INACTIVITY' &&
258
+ input.trigger !== 'LOST_CLIENTS' &&
259
+ (Object.hasOwn(input.config, 'assign_responsible_operator_ids') ||
260
+ Object.hasOwn(input.config, 'assignResponsibleOperatorIds')))
261
+ context.addIssue({
262
+ code: 'custom',
263
+ path: ['config'],
264
+ message: crmStagePoolMessage('unsupported'),
265
+ });
266
+ }),
738
267
  createRequest: (input) => ({
739
- method: 'PATCH',
740
- path: `/platforms/${input.platform_id}/agent-behavior`,
268
+ method: input.sequence_id ? 'PATCH' : 'POST',
269
+ path: input.sequence_id
270
+ ? `/channels/${input.platform_id}/followup-sequences/${input.sequence_id}`
271
+ : `/channels/${input.platform_id}/followup-sequences`,
272
+ ...(input.sequence_id && input.expected_version === undefined
273
+ ? {
274
+ followupRevisionLookup: {
275
+ path: `/channels/${input.platform_id}/followup-sequences?sequenceId=${input.sequence_id}`,
276
+ sequenceId: input.sequence_id,
277
+ },
278
+ }
279
+ : {}),
741
280
  body: compactObject({
742
- greeting: input.greeting ? mapBehaviorGreetingInput(input.greeting) : undefined,
743
- mediaHandling: input.media_handling
744
- ? mapBehaviorMediaHandlingInput(input.media_handling)
745
- : undefined,
746
- urlHandling: input.url_handling
747
- ? mapBehaviorUrlHandlingInput(input.url_handling)
748
- : undefined,
749
- errorHandling: input.error_handling
750
- ? mapBehaviorErrorHandlingInput(input.error_handling)
751
- : undefined,
752
- operatorSchedule: input.operator_schedule
753
- ? mapBehaviorOperatorScheduleInput(input.operator_schedule)
754
- : undefined,
755
- typingBehavior: input.typing_behavior
756
- ? mapBehaviorTypingInput(input.typing_behavior)
757
- : undefined,
758
- messageFilters: input.message_filters
759
- ? input.message_filters.map((filter) => ({
760
- id: filter.id,
761
- source: filter.source,
762
- target: filter.target,
763
- enabled: filter.enabled,
764
- order: filter.order,
765
- }))
766
- : undefined,
767
- messageSplitting: input.message_splitting
768
- ? { messageChunkSeparator: input.message_splitting.message_chunk_separator }
769
- : undefined,
770
- privacy: input.privacy
771
- ? {
772
- anonymizationEnabled: input.privacy.anonymization_enabled,
773
- contactNamePersonalizationMode: input.privacy.contact_name_personalization_mode,
774
- anonymizationDisabledTypes: input.privacy.anonymization_disabled_types,
775
- }
776
- : undefined,
281
+ name: input.name,
282
+ description: input.description,
283
+ type: input.type,
284
+ expectedVersion: input.expected_version,
285
+ enabled: input.enabled,
286
+ trigger: input.trigger,
287
+ config: input.config,
777
288
  ...setupConfirmation(input),
778
289
  }),
779
290
  }),
291
+ enhanceResponse: (response) => withInstructions(response, [
292
+ crmStagePoolMessage('hint'),
293
+ ...followUpPromotionInstructions,
294
+ 'Аудитория цепочки задаётся двумя частями: базовым фильтром config.filterMode и условиями config.sequenceConditions, которые СУЖАЮТ его через «И». Поддерживаются три режима: "variable" (базового фильтра нет, условия обязательны) и "eventType" (нужен непустой config.allowedEventTypes из значений START, IN_PROCESS, FINISH_WIN, FINISH_LOST, FAILED, OPERATOR_TAKEOVER, FINISH_AUTO). Режим "status" требует config.allowedStatuses; отсутствие режима отклоняется.',
295
+ 'Условие пишется как {variable: "ИМЯ", op: "eq"|"neq"|"in", value}: строка для eq/neq, непустой массив строк для in. Условия соединяются только через «И». Переменная называется ИМЕНЕМ; константа, секрет и одноимённые переменные разных уровней отклоняются.',
296
+ '⚠️ Цепочки НЕ исключают друг друга: у каждой свой прогресс. Набор обязан быть строгим разбиением — «= A», «= B» и подстраховка «≠ A И ≠ B». Безусловная цепочка рядом с точными не подстраховывает, а УДВАИВАЕТ отправку тем, у кого значение есть. У контакта без значения eq/in ложны, neq истинно — именно поэтому подстраховка пишется отрицаниями, а не пустым набором условий.',
297
+ 'config.stopOnPayment: true — выключать дожимы у оплатившего: при зачёте оплаты человеку ставится «дожимы выключены навсегда» на каналах, где такая цепочка включена (все его карточки в школе GetCourse и канал, из которого пришёл оплаченный заказ). Только true/false; читается у цепочки бездействия (USER_INACTIVITY), у «пропавших клиентов» не действует. Оператор может включить дожимы обратно — это держится до следующего зачёта оплаты (ночной разбор засчитывает оплату через часы после неё).',
298
+ 'Календарная цепочка: у КАЖДОГО шага scheduleMode="clock", anchorMode="variable" и anchorVariable — имя переменной карточки с датой (ГГГГ-ММ-ДД или ДД.ММ.ГГГГ, можно со временем), плюс atTime (ЧЧ:ММ) и dayOffset (от −7 до 30 дней от даты). Такая цепочка запускается датой в карточке и перепиской на канале — в том числе у того, кто только получил наше первое сообщение; ответ клиента её не прерывает; касание сдвигается вместе с датой; опоздавшее дольше validityMinutes (по умолчанию 45) касание пропускается. Варианты одного момента — подряд идущие шаги с одинаковым slotGroup: уходит первый, чьи conditions выполнены. Некалендарный шаг в такой цепочке и finalAction отвергаются; skipIfContactRepliedSincePreviousSlot пропускает касание после ответа на предыдущий отличный момент.',
299
+ 'config.contactVariablesOnSend — записка после успешной отправки: объект из 1–10 пар «имя переменной контакта этого канала → непустой текст до 500 кодовых единиц». Подготовь переменную контакта на канале цепочки и одноимённую константу канала рассылки: при холодной отправке значение контакта побеждает константу. Доступно цепочкам молчания и календаря, у потерянных клиентов сервер откажет. null снимает записку; отсутствие поля при полной правке тоже снимет её.',
300
+ 'Если description или enabled не переданы, их прежнее значение сохраняется. null или пустая строка очищает описание.',
301
+ 'Перенесённая цепочка сохраняет номер по месту исходного шага: добавление в конец даёт следующий номер, вставка или удаление сдвигает номера новых выдач. Уже выданные коды не меняются. Собственная цепочка нумерует группы действий между ожиданиями; номер назначает сервер. У пропавших клиентов номера нет.',
302
+ 'Ответ записи может содержать warnings[] с кодом и сообщением о неготовой CRM-стадии. Это предупреждение, а не отказ; проверь состояние CRM до включения цепочки.',
303
+ ]),
304
+ }),
305
+ defineTool({
306
+ name: 'besales_followup_sequence_clone',
307
+ sideEffect: 'write',
308
+ requiredFields: ['platform_id', 'sequence_id'],
309
+ schema: z
310
+ .object({
311
+ platform_id: uuidSchema,
312
+ // Источник копирования; обязан принадлежать platform_id (cross-platform не поддерживается).
313
+ sequence_id: uuidSchema,
314
+ // База имени копии. Не передана — берётся имя источника; суффикс добавляется в любом случае.
315
+ name: z.string().max(FOLLOWUP_CLONE_NAME_MAX_LENGTH).optional(),
316
+ })
317
+ .strict(),
318
+ createRequest: (input) => ({
319
+ method: 'POST',
320
+ path: `/channels/${input.platform_id}/followup-sequences/${input.sequence_id}/clone`,
321
+ body: compactObject({ name: input.name }),
322
+ }),
323
+ enhanceResponse: (response) => withInstructions(response, [
324
+ 'Копия создана ВЫКЛЮЧЕННОЙ и такой останется, пока её не включат явно: событие «контакт затих» веерится на КАЖДУЮ включённую цепочку канала, поэтому включённая копия слала бы те же касания тем же людям вторым потоком.',
325
+ 'Скопировано только ОПРЕДЕЛЕНИЕ (имя, описание, триггер, шаги и переменные последней версии). Прогресс контактов, история отправок и запланированные касания источника не копируются и не затрагиваются.',
326
+ 'Перед включением копии убедись, что условия цепочек образуют строгое разбиение (например «= A» / «= B» / «≠ A И ≠ B»). Две цепочки без взаимоисключающих условий удвоят отправку — они выполняются независимо.',
327
+ 'Копия остаётся на ТОМ ЖЕ канале. Для переноса на другой канал используй besales_platform_clone_* — определение ссылается на статусы CRM, переменные и файлы своего канала.',
328
+ '⚠️ Повтор вызова НЕ идемпотентен: он создаёт следующую копию (`…-copy-2`, `…-copy-3`). Переданный name — это БАЗА имени, суффикс копии добавляется всегда; свободное имя ищется среди неудалённых цепочек всего воркспейса.',
329
+ ]),
780
330
  }),
781
331
  ...followUpSetupTools,
782
332
  defineTool({
@@ -785,6 +335,11 @@ export const platformSetupTools = [
785
335
  requiredFields: ['platform_id'],
786
336
  schema: z
787
337
  .object({
338
+ expected_version: z
339
+ .string()
340
+ .min(1)
341
+ .regex(/^[A-Za-z0-9_.-]+$/u)
342
+ .optional(),
788
343
  platform_id: uuidSchema,
789
344
  // v1.5 Increment 3 Group C.3 (Phase B, 2026-05-27): только typed sections.
790
345
  crm_pipeline_behavior: pipelineCrmBehaviorSchema.optional(),
@@ -794,8 +349,9 @@ export const platformSetupTools = [
794
349
  .strict(),
795
350
  createRequest: (input) => ({
796
351
  method: 'PATCH',
797
- path: `/platforms/${input.platform_id}/pipeline-settings`,
352
+ path: `/channels/${input.platform_id}/pipeline-settings`,
798
353
  body: compactObject({
354
+ expectedVersion: input.expected_version,
799
355
  crmPipelineBehavior: input.crm_pipeline_behavior
800
356
  ? mapPipelineCrmBehaviorInput(input.crm_pipeline_behavior)
801
357
  : undefined,
@@ -803,88 +359,43 @@ export const platformSetupTools = [
803
359
  ...setupConfirmation(input),
804
360
  }),
805
361
  }),
362
+ enhanceResponse: withEditVersionInstructions,
806
363
  }),
807
364
  defineTool({
808
365
  name: 'besales_platform_settings_update',
809
366
  sideEffect: 'write',
810
367
  requiredFields: ['platform_id'],
811
- schema: z
812
- .object({
813
- platform_id: uuidSchema,
814
- // v1.5 Increment 3 Group C.2 (Phase B, 2026-05-27).
815
- // Flat-only fields — backward compat для existing UI clients (deprecated через 2 weeks).
816
- // Новый код должен использовать generalSettings.* typed section.
817
- name: z.string().nullable().optional(),
818
- off_message: z.string().optional(),
819
- timezone: z.string().optional(),
820
- // Typed sections (single source of truth для access/variables/crm/widget/instagram).
821
- access_control: platformAccessControlSchema.optional(),
822
- variables_config: platformVariablesConfigSchema.optional(),
823
- crm_behavior: platformCrmBehaviorSchema.optional(),
824
- widget_marketing: platformWidgetMarketingSchema.optional(),
825
- instagram_comment_behavior: platformInstagramCommentSchema.optional(),
826
- // Настройки раздела «Воронка канала»: ворота решения, цель «Пути до стадии», пороги.
827
- // Бэкенд делегирует запись сервисам раздела — их валидация не обходится.
828
- funnel_analytics: platformFunnelAnalyticsSchema.optional(),
829
- // v1.5 Increment 4c — per-channel typed sections (hard 400 для unsupported channel type)
830
- general_settings: platformGeneralSettingsSchema.optional(),
831
- salebot_settings: platformSalebotSettingsSchema.optional(),
832
- smsgorod_settings: platformSmsgorodSettingsSchema.optional(),
833
- bitrix24_bot_settings: platformBitrix24BotSettingsSchema.optional(),
834
- getcourse_settings: platformGetcourseSettingsSchema.optional(),
835
- ...platformSetupConfirmationSchema,
836
- })
837
- .strict(),
368
+ // Пространство выбирает ключ подключения для составной правки настроек.
369
+ defaultWorkspaceId: true,
370
+ schema: platformSettingsUpdateSchema,
838
371
  createRequest: (input) => ({
839
372
  method: 'PATCH',
840
- path: `/platforms/${input.platform_id}/settings`,
841
- body: compactObject({
842
- name: input.name,
843
- offMessage: input.off_message,
844
- timezone: input.timezone,
845
- accessControl: input.access_control
846
- ? mapPlatformAccessControlInput(input.access_control)
847
- : undefined,
848
- variablesConfig: input.variables_config
849
- ? mapPlatformVariablesConfigInput(input.variables_config)
850
- : undefined,
851
- crmBehavior: input.crm_behavior
852
- ? mapPlatformCrmBehaviorInput(input.crm_behavior)
853
- : undefined,
854
- widgetMarketing: input.widget_marketing
855
- ? mapPlatformWidgetMarketingInput(input.widget_marketing)
856
- : undefined,
857
- instagramCommentBehavior: input.instagram_comment_behavior
858
- ? mapPlatformInstagramCommentInput(input.instagram_comment_behavior)
859
- : undefined,
860
- funnelAnalytics: input.funnel_analytics
861
- ? mapPlatformFunnelAnalyticsInput(input.funnel_analytics)
862
- : undefined,
863
- generalSettings: input.general_settings
864
- ? mapPlatformGeneralSettingsInput(input.general_settings)
865
- : undefined,
866
- salebotSettings: input.salebot_settings
867
- ? mapPlatformSalebotSettingsInput(input.salebot_settings)
868
- : undefined,
869
- smsgorodSettings: input.smsgorod_settings
870
- ? mapPlatformSmsgorodSettingsInput(input.smsgorod_settings)
871
- : undefined,
872
- bitrix24BotSettings: input.bitrix24_bot_settings
873
- ? mapPlatformBitrix24BotSettingsInput(input.bitrix24_bot_settings)
874
- : undefined,
875
- getcourseSettings: input.getcourse_settings
876
- ? mapPlatformGetcourseSettingsInput(input.getcourse_settings)
877
- : undefined,
373
+ path: `/channels/${input.platform_id}/settings`,
374
+ body: {
375
+ ...platformSettingsSections(input),
878
376
  ...setupConfirmation(input),
879
- }),
377
+ ...compactObject({ expectedVersion: input.expected_version }),
378
+ },
880
379
  }),
881
380
  enhanceResponse: (response) => withInstructions(response, [
882
- 'funnel_analytics — настройки раздела «Воронка канала»: ворота решения (тройка стадий), целевая стадия «Пути до стадии», пороги. null у ворот и цели — СБРОС, отсутствие поля — «не трогать».',
883
- '⚠️ Ворота проверяются бэкендом: три стадии обязаны быть РАЗНЫМИ и существовать в каталоге площадки — иначе 400. Совпади «одобрено» с «отклонено», доля одобрения стала бы вечными 50 % при любых данных.',
884
- '⚠️ Секция НЕ попадает в audit log площадки: besales_audit_revert её НЕ откатит. Чтобы вернуть прежнее, пришлите прежние значения тем же тулом либо сбросьте через null.',
885
- 'Per-channel typed sections (salebot/smsgorod/bitrix24Bot/getcourse) — hard 400 при mismatched platform.type.',
886
- 'generalSettings.* — closes Phase B gap для name/offMessage/timezone/isActive; flat fields deprecated через 2 недели.',
887
- 'Response.warnings[] содержит Phase A soft-warnings для widgetMarketing/instagramCommentBehavior на mismatched channel (hard reject после 2026-06-10).',
381
+ editVersionInstruction(),
382
+ 'general_settings обновляет имя, сообщение при выключенном ИИ, зону, включённость канала, включённость ответов агента и phone_parsing_country. От страны разбора зависит, получит ли агент инструмент сохранения телефона; UZ значит, что девятизначный номер трактуется как узбекский, RU — инструмент выдаётся без разбора девяти цифр (российский номер разбирается по своей длине, девятизначный отклоняется). null снимает настройку и инструмент.',
383
+ 'У виджета general_settings.page_rules задаёт показ: mode ALL — везде, ALLOW — только на указанных страницах (пустой список — нигде), DENY — кроме указанных. patterns — до 200 полных адресов или масок со звёздочкой до 2000 знаков; маска раздела с /* включает сам раздел. Правило заменяется целиком, null снимает его. Проверка выполняется сервером при подключении; это правило отображения, а не защита доступа.',
384
+ 'crm_behavior принимает create_deal_on_first_outbound, finish_auto_enabled, finish_auto_days, send_finish_auto_note_to_crm, finish_auto_note_template, getcourse_create_deal_payment_tracking_enabled и getcourse_status_deal_fallback_enabled. finish_auto_days — целое число от 1 до защитного потолка 36500; null у finish_auto_note_template снимает шаблон и на свежем канале без сохранённых crm_behavior/auto_finish.',
385
+ 'Если crm_behavior ещё не сохранён, единственное активное CRM-подключение требуется для send_to_crm, создания сделки по первой исходящей, стратегии и фиксированного ответственного, четырёх флагов отправки заметок, трёх полей маркера сделки, четырёх шаблонов заметок и обоих GetCourse-флагов. Ноль или несколько подключений дают 422 CRM_CONNECTION_UNRESOLVED. При сохранённом crm_behavior подключение этим маршрутом повторно не проверяется.',
386
+ 'Опасные изменения create_deal_on_first_outbound, send_finish_auto_note_to_crm и getcourse_create_deal_payment_tracking_enabled требуют explicit_confirmation. Учёт оплат заказов агента GetCourse по умолчанию включён: при отсутствующем сохранённом ключе false требует подтверждения, а true проходит как неизменное действующее значение. Включение автозавершения не требует подтверждения, опасна отправка заметки.',
387
+ 'Настройки веб-виджета живут в general_settings, НЕ в widget_marketing: список сайтов (allowed_origins), лимит обращений в минуту (rate_limit — целое число от 1 до 600), передача адреса страницы (show_page_info) и оформление (customization с одиннадцатью разделами). В widget_marketing остаются только две карты — соответствия маркетинговых полей CRM и перенос адреса входа в переменную. Прежняя форма тоже принимается и переводится: widget_marketing.web_widget_allowed_origins / _show_page_info / _rate_limit_per_minute / _customization уходят в general_settings (пустой или незаданный прежний список сайтов — «работать везде», как у прежней версии), web_widget_marketing_field_mappings и web_widget_entry_url_variable_mapping — в две карты раздела, access_control.is_active и is_ai_enabled — в general_settings. Прежнее и новое имя одного поля в одном вызове — отказ, кроме is_active: access_control.is_active и general_settings.is_active принимаются вместе, приоритет у general_settings.is_active.',
388
+ 'Список сайтов принимает голый домен (site.ru), домен с портом (site.ru:8443), полный адрес (https://site.ru) и «*» (работать везде). Пустой список означает «не работать нигде» — это выключение виджета, а не сброс настройки. Список ЗАМЕЩАЕТСЯ целиком, разделы оформления сливаются.',
389
+ 'smsgorod_settings сохраняет channel (DIGIT/CHAR) и sender на SMS-канале с подключением SMS-город. bitrix24_bot_settings сохраняет bot_name и ignore_crm_stage_gate на Bitrix24 Bot; смена ignore_crm_stage_gate требует explicit_confirmation=true. bot_id/bot_code/open_line_id управляются подключением: допустимо только точное ненулевое эхо, изменение/null даёт 422 BITRIX24_BOT_IDENTITY_MANAGED. Ответ bitrix24BotSettingsApply различает сохранение и применение у провайдера; не обещай применение при отложенном/неизвестном исходе.',
390
+ 'crm_behavior.use_cross_platform_history сохраняет канальный выбор истории между каналами одного человека, включая false. Неверный тип канала — 400 BRIDGE_SETTINGS_CHANNEL_TYPE_MISMATCH; нет подключения, неверный sender или отсутствует подтверждение — адресный 422. Отказ любой секции не означает частично сохранённый запрос.',
391
+ 'getcourse_settings принимается на канале GetCourse и пишется слиянием: соседние настройки не трогаются. Исключение — field_variable_map: её принимает канал ЛЮБОГО типа (виджет, мессенджер), и там поля заказа школы ложатся в переменные канала по человеку, которого опознали в школе по почте или по ссылке рассылки; прочие поля раздела на канале не GetCourse пропускаются предупреждением. Домен школы, кэш отделов, шаблонные пользователь и заказ здесь не пишутся — ответ назовёт причину и правильное место. wave_field_bindings — в какие поля сделки школы status-волна сама ставит свои метки: тип запуска (OUTGOING), продукт (кодом или названием — product_value_source), сегмент, воронка, каналы (набор через «+», например VK+Telegram). У роли — field_id (номер поля сделки) и field_label; один номер поля — одна роль. Объект ЗАМЕНЯЕТ сохранённые привязки целиком (роль, не названная в запросе, снимается), null снимает все; ручное поле запуска волны в поле роли даёт отказ WAVE_DEAL_FIELD_BINDING_CONFLICT; текущие привязки — в besales_platform_context_get, channel.connection.providerConfig.wave_field_bindings. field_variable_map ЗАМЕНЯЕТ карту «поле сделки → переменная» канала целиком (null очищает): поле называется так, как в школе (регистр не важен), переменная — строковая не-константная переменная ЭТОГО канала, поле и переменная — по разу. Негодная переменная — отказ FIELD_VARIABLE_MAP_VARIABLE_INVALID с перечнем подходящих (allowedVariableNames); текущая карта — в besales_platform_context_get, channel.getcourseFieldVariableMap.',
392
+ 'getcourse_settings.guard_active_series / guard_active_application / guard_paid — режимы ПРЕДОХРАНИТЕЛЯ холодных отправок канала (вебинарная серия, действующая заявка, оплата продукта отправки): OFF — выключено, WARN — только записывается, BLOCK — отправка останавливается; null — «не настраивали» (действует BLOCK у всех трёх правил). quiet_days — тихий период канала в сутках (0 — правила нет, null — действует тихий период пространства). Эти поля сохраняются одним PATCH вместе с остальными секциями: ошибка любой секции отменяет всю запись. Ответ — в getcourseOutboundSettings (хранимое и действующее). Ослаблять правило ради одного запуска — не здесь: у пакета «Первого сообщения» для этого есть поле guards.',
393
+ 'funnel_analytics — настройки раздела «Воронка канала»: ворота решения (три РАЗНЫЕ стадии «отправлено → одобрено | отклонено», только целиком), цель «Пути до стадии», пороги engaged_inbound_count (2–20) и stuck_threshold_hours (1–720). Стадия — stage_id из справочника либо pipeline_crm_id (подключение из besales_crm_list) + pipeline_id и status_id (числовые или строковые коды из besales_crm_pipeline_status_list); стадия обязана быть живой и в воронке, привязанной к каналу, иначе 422 FUNNEL_ANALYTICS_STAGE_INVALID с полем и причиной. null сбрасывает к «не настраивали», отсутствие поля не трогает, пустой раздел не принимается. Проверяются только присланные поля: уже негодная стадия в нетронутом поле приходит предупреждением FUNNEL_STAGE_UNUSABLE, а не отказом. Хранимое после записи — в ответе, funnelAnalytics. Коды Bitrix24 вида C3:NEW передавай строкой из справочника; числовая форма отгруженного клиента тоже принимается.',
394
+ 'Тихий режим бота и создание отсутствующего заказа требуют explicit_confirmation (отказ приходит как EXPLICIT_CONFIRMATION_REQUIRED).',
395
+ 'getcourse_settings.open_invoice_silence_enabled и четыре соседних поля (open_invoice_table_id, open_invoice_product_column, open_invoice_topic_column, open_invoice_topic_variable) настраивают молчание бота при подходящем открытом платном счёте за последние 14 суток по московской дате. Для включения все четыре поля должны быть сохранены; передача любого из пяти требует explicit_confirmation=true. Таблица знаний должна принадлежать рабочей области; колонка продукта содержит номера продуктов GetCourse, на которые ссылаются предложения открытого счёта, колонка темы — тему, переменная темы — строковая переменная контакта. Если данные школы, предложение или таблица неизвестны, бот отвечает; задержка кэша после оплаты возможна до 45 секунд. Используй серверные подписи причины на языке канала (ru/en/es/id/uz), не показывай внутренний код.',
396
+ 'Деньги GetCourse (revenue_offer_ids, revenue_offers_paid_since) тоже требуют explicit_confirmation. Порядок: сначала дата у ЭТОГО канала (раньше или тем же вызовом), затем набор; снять дату можно только вместе с пустым набором. Предупреждение SECTION_ISSUE:getcourseSettings:revenue_offers_paid_since в ответе значит: у канала хранится набор без даты — задай дату. У канала виджета из денежных полей принимаются только revenue_offer_ids и revenue_offers_paid_since; карта field_variable_map принимается тоже. Денежные поля — метка продажи: совпавшее предложение разрешает автозачёт, а общий арбитр по заказам агента и рассылкам выбирает «Входящие» или «Исходящие»; прочие поля раздела пропускаются предупреждением. Порядок тот же, метка работает только при одной школе GetCourse в рабочей области (иначе WIDGET_SALE_LABEL_NEEDS_SINGLE_SCHOOL), предупреждение о метке без даты — SECTION_ISSUE:getcourseSettings:sale_label_paid_since.',
397
+ 'target_department_id работает только при включённом входящем фильтре по сделке: без него перенос диалога в отдел молча не сработает. Фильтр задаётся здесь полями crm_behavior.inbound_deal_filter_enabled / _type / _value / _field_id (включённость и тип требуют explicit_confirmation, включённый фильтр обязан быть полным) либо разделом crm_behavior.inbound_deal_filter инструмента besales_behavior_update.',
398
+ 'Response.warnings[] называет пропущенный раздел: widgetMarketing и instagramCommentBehavior — на неподходящем типе канала, generalSettings.widget — когда настройки виджета присланы каналу, который виджетом не является.',
888
399
  ]),
889
400
  }),
890
401
  defineTool({
@@ -900,13 +411,17 @@ export const platformSetupTools = [
900
411
  // где audit logs пишутся с platformId=null).
901
412
  platform_id: uuidSchema.optional(),
902
413
  audit_log_id: uuidSchema,
414
+ explicit_confirmation: z.boolean().optional(),
903
415
  })
904
416
  .strict(),
905
417
  createRequest: (input) => {
906
418
  if (input.platform_id) {
907
419
  return {
908
420
  method: 'POST',
909
- path: `/platforms/${input.platform_id}/audit/${input.audit_log_id}/revert`,
421
+ path: `/channels/${input.platform_id}/audit/${input.audit_log_id}/revert`,
422
+ ...(input.explicit_confirmation === undefined
423
+ ? {}
424
+ : { body: { explicitConfirmation: input.explicit_confirmation } }),
910
425
  };
911
426
  }
912
427
  return {
@@ -915,19 +430,26 @@ export const platformSetupTools = [
915
430
  };
916
431
  },
917
432
  enhanceResponse: (response) => withInstructions(response, [
433
+ 'Откат опасных настроек, в том числе откат клона, требует отдельного согласия человека и explicit_confirmation=true; без него сервер возвращает EXPLICIT_CONFIRMATION_REQUIRED. Безопасный откат подтверждения не требует.',
918
434
  'Передай `platform_id` для platform-scoped logs (audit через platform-setup-adapter).',
919
435
  'Опусти `platform_id` для workspace-scoped logs (variables-adapter и аналоги).',
436
+ 'Откат удаления переменной возвращает и собранные значения контактов. Ответ несёт `variableValues: { backedUp, restored }`: если `restored` меньше `backedUp`, разницу составляют люди, стёртые между удалением и откатом — их значения не вернёт ничто. Скажи об этом человеку числом, а не словом «успешно».',
920
437
  ]),
921
438
  }),
922
439
  defineTool({
923
440
  name: 'besales_feedback_sheet_link',
924
441
  sideEffect: 'write',
442
+ resultPolicy: {
443
+ neverTruncate: true,
444
+ narrowingHint: 'Выбери документ с меньшим числом связей; для текущего документа перечитай полный список через besales_feedback_document_access_get.',
445
+ },
925
446
  requiredFields: ['agent_id', 'source_url'],
926
447
  schema: z.object({
927
448
  agent_id: uuidSchema,
928
449
  source_url: z.string().url(),
929
- access_mode: z.enum(['READ_ONLY', 'EDITABLE']).default('READ_ONLY'),
450
+ access_mode: z.enum(['READ_ONLY', 'EDITABLE']).optional(),
930
451
  agent_version_id: uuidSchema.optional(),
452
+ ...feedbackDocumentConfirmationSchema,
931
453
  }),
932
454
  createRequest: (input) => ({
933
455
  path: `/agents/${input.agent_id}/feedback-sheets`,
@@ -935,12 +457,16 @@ export const platformSetupTools = [
935
457
  sourceUrl: input.source_url,
936
458
  accessMode: input.access_mode,
937
459
  agentVersionId: input.agent_version_id,
460
+ confirmDocumentAccessChange: input.confirm_document_access_change,
461
+ expectedDocumentSnapshot: input.expected_document_snapshot,
938
462
  }),
939
463
  }),
940
464
  enhanceResponse: (response) => withInstructions(response, [
941
- 'Таблица привязана к промпту. Расшарьте её на service account из поля serviceAccountEmail (Viewer для READ_ONLY, Editor для EDITABLE).',
465
+ 'Таблица привязана к промпту. Email для настройки доступа в Google приходит в serviceAccountEmail.',
942
466
  'Прочитайте замечания через besales_feedback_sheet_read по feedbackSheet.id.',
943
- 'accessMode определяет режим: READ_ONLY — только предлагаете правки промпта; EDITABLE — дополнительно отмечаете статусы строк (Phase 2).',
467
+ 'accessMode — намерение всего документа, независимое от прав Google. Без access_mode новая связь наследует текущий режим; новый документ начинает с READ_ONLY.',
468
+ 'Перед сменой режима прочитайте besales_feedback_document_access_get, покажите все связи и получите согласие человека; передайте confirm_document_access_change=true и expected_document_snapshot.',
469
+ 'Повторная привязка возвращает 409 с currentLink. Сохраните прежнюю связь и её версию; не делайте автоматические unlink/link.',
944
470
  ]),
945
471
  }),
946
472
  defineTool({
@@ -1024,7 +550,7 @@ export const platformSetupTools = [
1024
550
  requiredFields: ['agent_id'],
1025
551
  schema: z.object({
1026
552
  agent_id: uuidSchema,
1027
- namespace_record_id: uuidSchema.optional(),
553
+ namespace_record_id: knowledgeSpaceIdSchema.optional(),
1028
554
  }),
1029
555
  createRequest: (input) => ({
1030
556
  path: `/agents/${input.agent_id}/facts/classify-and-migrate`,
@@ -1033,8 +559,8 @@ export const platformSetupTools = [
1033
559
  }),
1034
560
  }),
1035
561
  enhanceResponse: (response) => withInstructions(response, [
1036
- 'Active facts разобраны: Q&A pairs созданы через QaService, document chunks отмечены как pending.',
1037
- 'Мигрированные chunks перемещены в секцию `## Migrated` в AgentChat.factualContext (audit trail).',
562
+ 'Active facts разобраны: Q&A pairs созданы в knowledge-пространстве, document chunks перенесены отдельными документами.',
563
+ 'Мигрированные chunks перемещены в секцию `## Migrated` в факты агента (audit trail).',
1038
564
  'Если категория `document` — text→document loader pending, повторно вызовы безопасны (idempotent per chunk).',
1039
565
  ]),
1040
566
  }),
@@ -1044,15 +570,20 @@ export const platformSetupTools = [
1044
570
  sideEffect: 'write',
1045
571
  requiredFields: ['agent_id', 'factual_context'],
1046
572
  schema: z.object({
573
+ expected_version: uuidSchema.optional(),
1047
574
  agent_id: uuidSchema,
1048
575
  factual_context: z.string(),
1049
576
  }),
1050
577
  createRequest: (input) => ({
1051
578
  method: 'PUT',
1052
579
  path: `/agents/${input.agent_id}/facts`,
1053
- body: { factualContext: input.factual_context },
580
+ body: compactObject({
581
+ factualContext: input.factual_context,
582
+ expectedVersion: input.expected_version,
583
+ }),
1054
584
  }),
1055
585
  enhanceResponse: (response) => withInstructions(response, [
586
+ editVersionInstruction(),
1056
587
  'factualContext записан целиком (PUT-семантика, replace not patch).',
1057
588
  'Если в warnings есть `soft_limit_exceeded` (~8000 chars / 2K tokens) — рекомендую запустить `besales_facts_classify_and_migrate`.',
1058
589
  'Структура: `## Active facts` блок инъектится в системный промпт; `## Migrated` — лог миграций (не инъектится).',
@@ -1069,18 +600,33 @@ export const platformSetupTools = [
1069
600
  // текст здесь незаменим: по нему строят якоря правок, и усечённый даёт промах якоря.
1070
601
  resultPolicy: { neverTruncate: true, maxResultBytes: 400_000 },
1071
602
  sideEffect: 'write',
603
+ closedWorld: true,
1072
604
  requiredFields: ['agent_id'],
1073
605
  schema: z.object({
1074
606
  agent_id: uuidSchema,
607
+ include_prompt_text: z.boolean().optional(),
608
+ mode: z.enum(['START', 'CONTINUE', 'RESTART']).optional(),
609
+ draft_id: uuidSchema.optional(),
610
+ expected_content_hash: z
611
+ .string()
612
+ .regex(/^[a-f0-9]{64}$/)
613
+ .optional(),
1075
614
  }),
1076
615
  createRequest: (input) => ({
1077
616
  method: 'POST',
1078
617
  path: `/agents/${input.agent_id}/prompt/drafts`,
618
+ body: compactObject({
619
+ mode: input.mode,
620
+ draftId: input.draft_id,
621
+ expectedContentHash: input.expected_content_hash,
622
+ }),
1079
623
  }),
1080
- enhanceResponse: (response) => withInstructions(response, [
1081
- 'PromptDraft создан. ID в `draft.id`. TTL 24h, resets на каждом `_apply`.',
624
+ enhanceResponse: (response, input) => withInstructions(input.include_prompt_text === true ? response : withoutDraftPromptText(response), [
625
+ 'Текст промпта по умолчанию НЕ возвращается: приходят отпечаток и длина. Нужен сам текст — ' +
626
+ 'besales_prompt_patch_get либо include_prompt_text=true. Без текста не построить якоря правок.',
627
+ 'При CREATED создан новый черновик; при CONTINUED возвращён выбранный свой черновик. При PROMPT_DRAFT_CHOICE_REQUIRED прочитай besales_prompt_drafts_mine и попроси человека выбрать CONTINUE или RESTART с draft_id и expected_content_hash.',
1082
628
  'Дальше: `besales_prompt_patch_apply(draft_id, operations[])` → batch правок → `besales_prompt_patch_commit(draft_id)`.',
1083
- 'Если `conflictsWithOtherUsers` непустой — другой пользователь редактирует тот же агент. Не блокирует, но warning.',
629
+ 'conflictingDraftCount — число черновиков других авторов. Их идентификаторы и сроки не выдаются; conflictsWithOtherUsers всегда пустой.',
1084
630
  'Server-side hash → клиенту не нужно знать про activePromptContentHash.',
1085
631
  'Гигиена: правь формулировки ПО МЕСТУ в существующих секциях; не добавляй override-блоки/дубли-секции в конец (антипаттерн → тех-долг). Сначала прочти весь промпт (besales_prompt_patch_get) и найди, где правило уже есть. См. «Редактирование промпта» в serverInstructions.',
1086
632
  ]),
@@ -1092,6 +638,7 @@ export const platformSetupTools = [
1092
638
  // текст здесь незаменим: по нему строят якоря правок, и усечённый даёт промах якоря.
1093
639
  resultPolicy: { neverTruncate: true, maxResultBytes: 400_000 },
1094
640
  sideEffect: 'none',
641
+ closedWorld: true,
1095
642
  requiredFields: ['agent_id', 'draft_id'],
1096
643
  schema: z.object({
1097
644
  agent_id: uuidSchema,
@@ -1103,10 +650,11 @@ export const platformSetupTools = [
1103
650
  }),
1104
651
  }),
1105
652
  // Остаток до лимитов линтера ДО сборки черновика. Порядок здесь обязан совпадать с
1106
- // mcp-tools.json (registry.spec проверяет parity), поэтому вставка строго после _patch_get.
653
+ // mcp-tools.json (registry.spec сверяет имена позиционно), поэтому вставка строго после _patch_get.
1107
654
  defineTool({
1108
655
  name: 'besales_prompt_headroom',
1109
656
  sideEffect: 'none',
657
+ closedWorld: true,
1110
658
  requiredFields: ['agent_id'],
1111
659
  // .strict() — иначе опечатка `draftId` вместо `draft_id` молча отбрасывается zod'ом,
1112
660
  // и тулза измеряет закоммиченный промпт вместо черновика.
@@ -1143,7 +691,10 @@ export const platformSetupTools = [
1143
691
  createRequest: (input) => ({
1144
692
  method: 'POST',
1145
693
  path: `/agents/${input.agent_id}/prompt/diff`,
1146
- body: { compareAgentId: input.compare_agent_id, maxLines: input.max_lines },
694
+ body: {
695
+ compareAgentId: input.compare_agent_id,
696
+ maxLines: input.max_lines,
697
+ },
1147
698
  }),
1148
699
  enhanceResponse: (response) => withInstructions(response, [
1149
700
  '`identicalBytes: true` — текущие тексты совпадают побайтово, значит один и тот же набор patch-операций найдёт те же якоря. Это НЕ гарантия одинакового исхода commit: lint резолвит канал каждого агента отдельно (одна и та же markdown-правка проходит в веб-виджете и падает в Telegram), а свой черновик каждый агент коммитит независимо.',
@@ -1159,11 +710,13 @@ export const platformSetupTools = [
1159
710
  // текст здесь незаменим: по нему строят якоря правок, и усечённый даёт промах якоря.
1160
711
  resultPolicy: { neverTruncate: true, maxResultBytes: 400_000 },
1161
712
  sideEffect: 'write',
713
+ closedWorld: true,
1162
714
  requiredFields: ['agent_id', 'draft_id', 'operations'],
1163
715
  schema: z.object({
1164
716
  agent_id: uuidSchema,
1165
717
  draft_id: uuidSchema,
1166
718
  operations: z.array(promptPatchOperationSchema).min(1),
719
+ include_prompt_text: z.boolean().optional(),
1167
720
  }),
1168
721
  createRequest: (input) => ({
1169
722
  method: 'PATCH',
@@ -1172,12 +725,12 @@ export const platformSetupTools = [
1172
725
  operations: input.operations.map(mapPromptPatchOperationInput),
1173
726
  },
1174
727
  }),
1175
- enhanceResponse: (response) => withInstructions(response, [
728
+ enhanceResponse: (response, input) => withInstructions(input.include_prompt_text === true ? response : withoutDraftPromptText(response), [
729
+ 'Текст промпта по умолчанию НЕ возвращается: приходят отпечаток и длина. Изменился ли текст — ' +
730
+ 'видно по отпечатку; нужен сам текст для следующих якорей — include_prompt_text=true или ' +
731
+ 'besales_prompt_patch_get.',
1176
732
  'Operations применены. `appliedCount` — успешно, `skippedCount` — anchor не найден или growth guard сработал (>30% size).',
1177
733
  'Если `skippedCount > 0` — проверь target_text / anchor_text на точность. matchVariants[] помогает fuzzy-match.',
1178
- 'Текста черновика в ответе НЕТ — приезжает `diff` (`removedLines`/`addedLines`, `charactersDelta`) и `draft.characters`. Промпт целиком ты уже прочитал на `_start`; перечитать — `besales_prompt_patch_get`.',
1179
- 'Пустые `removedLines`/`addedLines` — НЕ признак «ничего не применилось»: дифф это разность МНОЖЕСТВ строк, и `move_text_after_text` (как и правка одних пробелов) даёт пустые списки. Факт изменения читай по `diff.contentChanged`, объём — по `charactersDelta`.',
1180
- '`diff.truncated: true` — изменённых строк больше потолка; тогда сверяйся через `besales_prompt_patch_get`.',
1181
734
  'TTL draft сброшен на 24h.',
1182
735
  'Когда правки готовы — `besales_prompt_patch_commit(draft_id)`.',
1183
736
  ]),
@@ -1194,9 +747,10 @@ export const platformSetupTools = [
1194
747
  method: 'POST',
1195
748
  path: `/agents/${input.agent_id}/prompt/drafts/${input.draft_id}/commit`,
1196
749
  }),
1197
- enhanceResponse: (response) => withInstructions(response, [
1198
- 'Commit: lint pass → новая PromptVersion в prompt-services → AgentChat.baseSystemPrompt обновлён.',
1199
- 'В ответе только адресация версии (`newVersion.id`, `newVersion.version`) и метаданные черновика — текст промпта не дублируется.',
750
+ enhanceResponse: (response) => withInstructions(withoutDuplicatedPromptText(response), [
751
+ 'Текст промпта приходил здесь ДВАЖДЫ — в черновике и в новой версии. Копия из черновика ' +
752
+ 'заменена отпечатком; авторитетна версия (newVersion.content) — именно она уехала агенту.',
753
+ 'Commit: lint pass → новая PromptVersion в prompt-services → системный промпт агента обновлён.',
1200
754
  'Если ошибка 400 с `lintIssues` — поправь через `_apply` (hard_fail issues блокируют commit).',
1201
755
  'Если ошибка 409 PROMPT_DRAFT_REBASE_REQUIRED — другой commit прошёл первым. Discard этот draft и сделай новый.',
1202
756
  'Server-side hash → клиенту не нужно передавать activePromptContentHash.',
@@ -1208,6 +762,7 @@ export const platformSetupTools = [
1208
762
  defineTool({
1209
763
  name: 'besales_prompt_patch_discard',
1210
764
  sideEffect: 'write',
765
+ closedWorld: true,
1211
766
  requiredFields: ['agent_id', 'draft_id'],
1212
767
  schema: z.object({
1213
768
  agent_id: uuidSchema,
@@ -1223,6 +778,9 @@ export const platformSetupTools = [
1223
778
  defineTool({
1224
779
  name: 'besales_prompt_batch_start',
1225
780
  sideEffect: 'spend',
781
+ // Жёсткий гейт: правка уезжает разом на парк до 200 боевых агентов, у очереди одна
782
+ // попытка и авто-отката нет. Аннотация тут не помогает — она подсказка, которой хост
783
+ // вправе не поверить, а это условие входа, которое обойти нельзя.
1226
784
  requiredFields: ['agent_ids', 'operations', 'explicit_confirmation'],
1227
785
  schema: z
1228
786
  .object({
@@ -1242,19 +800,21 @@ export const platformSetupTools = [
1242
800
  operations: input.operations.map(mapPromptPatchOperationInput),
1243
801
  allOrNothing: input.all_or_nothing,
1244
802
  idempotencyKey: input.idempotency_key,
1245
- platformId: input.platform_id,
803
+ channelId: input.platform_id,
1246
804
  }),
1247
805
  }),
1248
806
  enhanceResponse: (response) => withInstructions(response, [
1249
- 'Прогон фоновый: опрашивай `besales_prompt_batch_status` по `runId`, пока `counts.PENDING` и `counts.PREPARED` не станут нулями.',
807
+ 'Прогон фоновый: опрашивай `besales_prompt_batch_status` по `runId` до конечного состояния; STOPPED может сохранять не начатых агентов.',
1250
808
  '`SKIPPED` — не ошибка: смотри `skipReason`, чаще всего это NO_OPERATIONS_APPLIED (у агента другой промпт, якоря не нашлись).',
1251
- 'Упавших агентов докатывай `besales_prompt_batch_resume` — повторный `_start` создаст ВТОРОЙ прогон и применит операции ещё раз.',
809
+ 'После потери ответа читай `besales_prompt_batch_by_key` с исходным idempotency_key. Повтор start с тем же ключом и составом возвращает тот же прогон; другой состав — 409. Новый ключ рискует второй раскаткой.',
810
+ 'Для остановки после текущего агента используй `besales_prompt_batch_stop`, для продолжения оставшихся — `besales_prompt_batch_resume`.',
1252
811
  'Перед раскаткой на парк проверь запас длины у самого тяжёлого агента через `besales_prompt_headroom`.',
1253
812
  ]),
1254
813
  }),
1255
814
  defineTool({
1256
815
  name: 'besales_prompt_batch_status',
1257
816
  sideEffect: 'none',
817
+ resultPolicy: { neverTruncate: true, maxResultBytes: 400_000 },
1258
818
  requiredFields: ['run_id'],
1259
819
  schema: z.object({ run_id: uuidSchema }).strict(),
1260
820
  createRequest: (input) => ({
@@ -1272,8 +832,9 @@ export const platformSetupTools = [
1272
832
  path: `/prompt-batch/runs/${input.run_id}/resume`,
1273
833
  }),
1274
834
  enhanceResponse: (response) => withInstructions(response, [
1275
- 'Докатываются только FAILED-агенты. Уже закоммиченные не трогаются — повторное применение операций удвоило бы вставки.',
835
+ 'Продолжаются оставшиеся и сброшенные барьером агенты вместе с отказавшими, в том числе откатанные подготовкой allOrNothing. Уже записанные не повторяются.',
1276
836
  '400 «Run is still in progress» означает, что прогон жив: дождись, а не повторяй resume.',
837
+ '409 — исход прежней операции не установлен: перечитай статус и не запускай новый прогон; 404 — прогон недоступен, 503 — управление или проверка секретов недоступны.',
1277
838
  ]),
1278
839
  }),
1279
840
  // S2.6 extra — besales_prompt_lint (после patches, чтобы matched catalog order)
@@ -1315,7 +876,7 @@ export const platformSetupTools = [
1315
876
  enhanceResponse: (response) => withInstructions(response, [
1316
877
  'Standalone lint: проверка ДО `besales_prompt_finalize` (избегает цикла «finalize → 400 → fix»).',
1317
878
  'Severity: `hard_fail` блокирует finalize; `warn` — рекомендация; `info` — заметки.',
1318
- 'Если передан `agent_id` — channel и agentScope резолвятся из AgentChat (markdown-checker и scope-consistency активны).',
879
+ 'Если передан `agent_id` — channel и agentScope резолвятся из агента (markdown-checker и scope-consistency активны).',
1319
880
  ]),
1320
881
  }),
1321
882
  ];