@besales/mcp 1.0.0-beta.7 → 1.0.0-beta.9

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 (72) hide show
  1. package/README.md +41 -6
  2. package/dist/auth/oauth-client.d.ts +1 -1
  3. package/dist/auth/oauth-client.js +2 -0
  4. package/dist/auth/oauth-client.js.map +1 -1
  5. package/dist/resources/concepts/sandbox.md +8 -1
  6. package/dist/resources/concepts/triggers.md +1 -0
  7. package/dist/resources/docs/platforms.md +10 -1
  8. package/dist/resources/docs/trigger-actions.md +24 -0
  9. package/dist/resources/workflows/iterate-with-sandbox.md +6 -2
  10. package/dist/resources/workflows/platform-setup-from-scratch.md +27 -0
  11. package/dist/schemas/mcp-tools.json +360 -12
  12. package/dist/tools/definitions/agent-design.d.ts +1 -1
  13. package/dist/tools/definitions/agent-design.js +13 -7
  14. package/dist/tools/definitions/agent-design.js.map +1 -1
  15. package/dist/tools/definitions/broadcast-analytics.js +1 -1
  16. package/dist/tools/definitions/broadcast-analytics.js.map +1 -1
  17. package/dist/tools/definitions/broadcast-campaigns.d.ts +29 -0
  18. package/dist/tools/definitions/broadcast-campaigns.js +107 -0
  19. package/dist/tools/definitions/broadcast-campaigns.js.map +1 -0
  20. package/dist/tools/definitions/dialogue-export.js +2 -0
  21. package/dist/tools/definitions/dialogue-export.js.map +1 -1
  22. package/dist/tools/definitions/follow-up.d.ts +1 -1
  23. package/dist/tools/definitions/platform-setup-wave.d.ts +1 -1
  24. package/dist/tools/definitions/platform-setup.d.ts +11 -1
  25. package/dist/tools/definitions/telegram-outreach-calendar.d.ts +17 -0
  26. package/dist/tools/definitions/telegram-outreach-calendar.js +68 -0
  27. package/dist/tools/definitions/telegram-outreach-calendar.js.map +1 -0
  28. package/dist/tools/definitions/telegram-personal-profile.d.ts +2 -0
  29. package/dist/tools/definitions/telegram-personal-profile.js +14 -0
  30. package/dist/tools/definitions/telegram-personal-profile.js.map +1 -1
  31. package/dist/tools/definitions/telegram-session-import.d.ts +5 -0
  32. package/dist/tools/definitions/telegram-session-import.js +33 -0
  33. package/dist/tools/definitions/telegram-session-import.js.map +1 -0
  34. package/dist/tools/definitions/trigger-action-item.schema.d.ts +10 -0
  35. package/dist/tools/definitions/trigger-action-item.schema.js +28 -11
  36. package/dist/tools/definitions/trigger-action-item.schema.js.map +1 -1
  37. package/dist/tools/definitions/trigger-upsert.tool.d.ts +1 -0
  38. package/dist/tools/definitions/trigger-upsert.tool.js +13 -0
  39. package/dist/tools/definitions/trigger-upsert.tool.js.map +1 -1
  40. package/dist/tools/definitions.d.ts +48 -6
  41. package/dist/tools/definitions.js +6 -0
  42. package/dist/tools/definitions.js.map +1 -1
  43. package/dist/tools/registry-mapping.cases.js +133 -93
  44. package/dist/tools/registry-mapping.cases.js.map +1 -1
  45. package/dist/tools/registry.js +10 -11
  46. package/dist/tools/registry.js.map +1 -1
  47. package/dist/tools/result.d.ts +1 -1
  48. package/dist/tools/result.js +60 -39
  49. package/dist/tools/result.js.map +1 -1
  50. package/dist/types/api-contract.gen.d.ts +2220 -216
  51. package/docs/async-operation-lifecycle.md +13 -2
  52. package/docs/failure-semantics.md +11 -1
  53. package/docs/secret-read-boundary.md +7 -0
  54. package/docs/telegram-personal-management.md +66 -22
  55. package/docs/telegram-session-import.md +53 -0
  56. package/package.json +8 -7
  57. package/scripts/body-idempotency-contract.mjs +95 -0
  58. package/scripts/generate-followup-session-contract.mjs +14 -7
  59. package/scripts/generated-output.mjs +9 -0
  60. package/scripts/sync-agent-model-schemas.mjs +11 -11
  61. package/scripts/sync-api-contracts.mjs +99 -40
  62. package/scripts/sync-crm-stage-pool-schema.mjs +6 -7
  63. package/scripts/sync-route-map.mjs +189 -35
  64. package/scripts/sync-sandbox-request-key.mjs +40 -0
  65. package/scripts/sync-telegram-profile-photo.mjs +57 -0
  66. package/scripts/sync-telegram-session-import.mjs +39 -0
  67. package/scripts/sync-tool-inventory.mjs +15 -7
  68. package/scripts/sync-trigger-argument-schema.mjs +31 -14
  69. package/scripts/sync-trigger-event-schema.mjs +11 -6
  70. package/scripts/sync-trigger-step-reference-schema.mjs +21 -0
  71. package/scripts/sync-wave-id-schemas.mjs +7 -6
  72. package/scripts/telegram-personal-profile-mutants.mjs +59 -18
@@ -996,7 +996,7 @@
996
996
  },
997
997
  {
998
998
  "name": "besales_sandbox_run_start",
999
- "description": "Start sandbox run для agent (full multi-persona × multi-scenario testing). Queued async. Без вопроса запускай обычный прогон: mode=single_agent и client_mode=scripted (умолчания схемы) — это дешёвый, воспроизводимый прогон для регрессии и проверки кандидата промпта до публикации (candidate_prompt). Перед запуском спроси пользователя одним коротким вопросом с ценой в одну фразу только если нужен client_mode=simulated (LLM играет клиента — дороже и каждый раз по-разному), оба режима клиента (= два прогона) либо mode=workflow (все агенты канала через роутер — шире и дороже). request_key (UUID) — идемпотентность повторного запуска: для повтора того же намерения передай тот же ключ; без поля мост генерирует один ключ на вызов, транспорт внутри вызова использует его повторно. icp_profile_id: UUID — выбранный портрет, null — без выбора, отсутствие — основной портрет агента.",
999
+ "description": "Start sandbox run для agent (full multi-persona × multi-scenario testing). Queued async. Без вопроса запускай обычный прогон: mode=single_agent и client_mode=scripted (умолчания схемы) — это дешёвый, воспроизводимый прогон для регрессии и проверки кандидата промпта до публикации (candidate_prompt). Перед запуском спроси пользователя одним коротким вопросом с ценой в одну фразу только если нужен client_mode=simulated (LLM играет клиента — дороже и каждый раз по-разному), оба режима клиента (= два прогона) либо mode=workflow (все агенты канала через роутер — шире и дороже). request_key (UUID) — идемпотентность повторного запуска: для повтора того же намерения передай тот же ключ; без поля мост генерирует один ключ на вызов, транспорт внутри вызова использует его повторно. icp_profile_id: UUID — выбранный портрет, null — без выбора, отсутствие — основной портрет агента. Сохрани request_key. При таймауте или 5xx повтори вызов с тем же request_key и тем же намерением: вернётся тот же прогон. Новый ключ — новый платный прогон; другое намерение с прежним ключом даёт START_KEY_CONFLICT.",
1000
1000
  "inputSchema": {
1001
1001
  "type": "object",
1002
1002
  "required": [
@@ -1079,7 +1079,7 @@
1079
1079
  "request_key": {
1080
1080
  "type": "string",
1081
1081
  "format": "uuid",
1082
- "description": "Ключ идемпотентности запуска; один на намерение. Если пропущен, мост генерирует UUID один раз на вызов."
1082
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
1083
1083
  },
1084
1084
  "icp_profile_id": {
1085
1085
  "type": [
@@ -3889,7 +3889,7 @@
3889
3889
  },
3890
3890
  {
3891
3891
  "name": "besales_trigger_upsert",
3892
- "description": "Create trigger, patch trigger metadata, or replace its full action set (replace_actions=true) for an agent. Without replace_actions existing actions are not bulk-replaced; webhook, operator, silent AI, CRM, calendar, outbound and follow-up actions require explicit_confirmation. В ответе вместо самих шагов и условий приходит их количество (actionsCount / activationsCount): эхо повторяло отправленное целиком и уносило контекст на каждой правке, а правят их десятками подряд. Текущий состав читается через besales_platform_context_get. Включённое действие, сохраняющее почту, названную клиентом (шаг SAVE_CONTACT_INFO с полем email ровно {{slots.email}}), записывается только с allow_repeat_in_conversation=true, иначе 422: первая попытка заняла бы право до закрытия переписки, и исправленный адрес сохранить было бы нельзя. Действию, записывающему значение из переписки (поле CRM без шаблона — input_type ai_text или ai_dropdown; заметка с input_type=ai_text; переменная с value_source=MODEL; поле школы из ai_fields с вариантами options), повтор рекомендован, но не обязателен: частичное извлечение занимает право, и названное позже без allow_repeat_in_conversation=true не запишется. В getcourseCreateDealConfig для GETCOURSE_CREATE_DEAL можно передать reuse_open_invoice=true: переиспользуется только открытый счёт с продуктом из предложения шага; нового заказа нет. Срок давности счёта: по умолчанию не старше 14 суток; open_invoice_age=ANY_AGE — без срока, WITHIN_MAX_AGE — 14 суток. Отсутствующий ключ получает 14 суток, в том числе у перенесённых шагов; ключ умолчания при сохранении удаляется. Количество открытых счетов считается в пределах выбранного срока. ru/en/es/id/uz используют подпись поля и двух вариантов на языке пользователя. Упорядоченный список уникальных ответственных сотрудников своего подключения amoCRM. Пропуск ключа сохраняет прежний пул цепочки; [] или null снимают. При полной замене действий передай прочитанный пул явно. Ссылки — UUID из каталога операторов CRM, а не номера пользователей. Голосовые шаги: канон stepType=VOICE_INITIATE_OUTBOUND_CALL / VOICE_TRANSFER_CALL и config. Старые initiateOutboundCall/initiateOutboundCallConfig и transferCall/transferCallConfig принимаются как ввод. Конфликты и непустой чужой конфиг отклоняются до HTTP; снимается только служебное эхо верхнего уровня, вложенные поля сохраняются. Редактирование не выполняет звонок или перевод. При replace_actions=true явно сохраняй обе оси SILENT_MODE: config.silence_bot и config.silence_followups. Пропущенная ось получает true, а не прежнее значение. Для старого конверта — silenceBot/silenceFollowUps. Для автоматического запуска по событию передай trigger вместо scope и строкового condition верхнего уровня. NEW_CONVERSATION — начало новой переписки; CONTACT_MESSAGE — сообщение клиента; OPERATOR_REPLY — ответ живого оператора; AGENT_REPLY — после ответа бота клиенту, пустой или молчаливый ход события не даёт. Шаги событийного триггера статичные: без arguments, {{args.*}} и полей «заполняет ИИ» — автозапуск не получает значений ИИ. Для шагов с оператором или отправкой требуется explicit_confirmation=true. Горизонт allow_repeat_in_conversation — ПЕРЕПИСКА. В trigger.condition можно использовать conversation.lastActionFailureCode, если сервер его знает.",
3892
+ "description": "Create trigger, patch trigger metadata, or replace its full action set (replace_actions=true) for an agent. Without replace_actions existing actions are not bulk-replaced; webhook, operator, silent AI, CRM, calendar, outbound and follow-up actions require explicit_confirmation. В ответе вместо самих шагов и условий приходит их количество (actionsCount / activationsCount): эхо повторяло отправленное целиком и уносило контекст на каждой правке, а правят их десятками подряд. Текущий состав читается через besales_platform_context_get. Включённое действие, сохраняющее почту, названную клиентом (шаг SAVE_CONTACT_INFO с полем email ровно {{slots.email}}), записывается только с allow_repeat_in_conversation=true, иначе 422: первая попытка заняла бы право до закрытия переписки, и исправленный адрес сохранить было бы нельзя. Действию, записывающему значение из переписки (поле CRM без шаблона — input_type ai_text или ai_dropdown; заметка с input_type=ai_text; переменная с value_source=MODEL; поле школы из ai_fields с вариантами options), повтор рекомендован, но не обязателен: частичное извлечение занимает право, и названное позже без allow_repeat_in_conversation=true не запишется. В getcourseCreateDealConfig для GETCOURSE_CREATE_DEAL можно передать reuse_open_invoice=true: переиспользуется только открытый счёт с продуктом из предложения шага; нового заказа нет. Срок давности счёта: по умолчанию не старше 14 суток; open_invoice_age=ANY_AGE — без срока, WITHIN_MAX_AGE — 14 суток. Отсутствующий ключ получает 14 суток, в том числе у перенесённых шагов; ключ умолчания при сохранении удаляется. Количество открытых счетов считается в пределах выбранного срока. ru/en/es/id/uz используют подпись поля и двух вариантов на языке пользователя. Упорядоченный список уникальных ответственных сотрудников своего подключения amoCRM. Пропуск ключа сохраняет прежний пул цепочки; [] или null снимают. При полной замене действий передай прочитанный пул явно. Ссылки — UUID из каталога операторов CRM, а не номера пользователей. Голосовые шаги: канон stepType=VOICE_INITIATE_OUTBOUND_CALL / VOICE_TRANSFER_CALL и config. Старые initiateOutboundCall/initiateOutboundCallConfig и transferCall/transferCallConfig принимаются как ввод. Конфликты и непустой чужой конфиг отклоняются до HTTP; снимается только служебное эхо верхнего уровня, вложенные поля сохраняются. Редактирование не выполняет звонок или перевод. При replace_actions=true явно сохраняй обе оси SILENT_MODE: config.silence_bot и config.silence_followups. Пропущенная ось получает true, а не прежнее значение. Для старого конверта — silenceBot/silenceFollowUps. Для автоматического запуска по событию передай trigger вместо scope и строкового condition верхнего уровня. NEW_CONVERSATION — начало новой переписки; CONTACT_MESSAGE — сообщение клиента; OPERATOR_REPLY — ответ живого оператора; AGENT_REPLY — после ответа бота клиенту, пустой или молчаливый ход события не даёт. Шаги событийного триггера статичные: без arguments, {{args.*}} и полей «заполняет ИИ» — автозапуск не получает значений ИИ. Для шагов с оператором или отправкой требуется explicit_confirmation=true. Горизонт allow_repeat_in_conversation — ПЕРЕПИСКА. В trigger.condition можно использовать conversation.lastActionFailureCode, если сервер его знает. Правка одного шага: нетронутые шаги присылай как { stepId } (id — из besales_platform_context_get, раздел agents_full), изменённый — { stepId, stepType, config } с полной настройкой из снимка; HTTP-запрос и шаг со скрытыми полями — только { stepId }, пропуск скрытого шага запрещён. После записи id шагов меняются — перед следующей правкой перечитай снимок. Подробно — besales://docs/trigger-actions.",
3893
3893
  "inputSchema": {
3894
3894
  "type": "object",
3895
3895
  "required": [
@@ -4906,6 +4906,23 @@
4906
4906
  }
4907
4907
  ],
4908
4908
  "description": "Совместимый ввод голосового конфига. Используй один config или одно прежнее имя; relation вместе с input, даже null, отклоняется до HTTP."
4909
+ },
4910
+ "stepId": {
4911
+ "description": "Ссылка на сохранённый шаг этого триггера (id из besales_platform_context_get)",
4912
+ "type": "string",
4913
+ "format": "uuid",
4914
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
4915
+ },
4916
+ "onError": {
4917
+ "type": "string",
4918
+ "enum": [
4919
+ "STOP",
4920
+ "SKIP",
4921
+ "RETRY"
4922
+ ]
4923
+ },
4924
+ "stopOnSuccess": {
4925
+ "type": "boolean"
4909
4926
  }
4910
4927
  },
4911
4928
  "additionalProperties": true,
@@ -15636,6 +15653,186 @@
15636
15653
  ]
15637
15654
  }
15638
15655
  },
15656
+ {
15657
+ "name": "besales_broadcast_campaign_list",
15658
+ "description": "Список кампаний рассылок с поиском, статусом и курсором. Scope: read:campaigns.",
15659
+ "inputSchema": {
15660
+ "type": "object",
15661
+ "properties": {
15662
+ "workspace_id": {
15663
+ "type": "string",
15664
+ "format": "uuid"
15665
+ },
15666
+ "status": {
15667
+ "type": "string",
15668
+ "enum": [
15669
+ "DRAFT",
15670
+ "SCHEDULED",
15671
+ "RUNNING",
15672
+ "PAUSED",
15673
+ "COMPLETED",
15674
+ "ARCHIVED"
15675
+ ]
15676
+ },
15677
+ "search": {
15678
+ "type": "string"
15679
+ },
15680
+ "cursor": {
15681
+ "type": "string",
15682
+ "format": "uuid"
15683
+ },
15684
+ "limit": {
15685
+ "type": "integer",
15686
+ "minimum": 1,
15687
+ "maximum": 100
15688
+ }
15689
+ },
15690
+ "required": [],
15691
+ "additionalProperties": false
15692
+ }
15693
+ },
15694
+ {
15695
+ "name": "besales_broadcast_campaign_get",
15696
+ "description": "Карточка кампании по ID: настройки, статус, расписание запуска и части кампании. Scope: read:campaigns.",
15697
+ "inputSchema": {
15698
+ "type": "object",
15699
+ "properties": {
15700
+ "workspace_id": {
15701
+ "type": "string",
15702
+ "format": "uuid"
15703
+ },
15704
+ "campaign_id": {
15705
+ "type": "string",
15706
+ "format": "uuid"
15707
+ }
15708
+ },
15709
+ "required": [
15710
+ "campaign_id"
15711
+ ],
15712
+ "additionalProperties": false
15713
+ }
15714
+ },
15715
+ {
15716
+ "name": "besales_broadcast_campaign_create",
15717
+ "description": "Создать черновик кампании с существующим шаблоном и аудиторией. Для повтора того же создания используй прежний idempotency_key. Scope: manage:campaigns.",
15718
+ "inputSchema": {
15719
+ "type": "object",
15720
+ "properties": {
15721
+ "workspace_id": {
15722
+ "type": "string",
15723
+ "format": "uuid"
15724
+ },
15725
+ "name": {
15726
+ "type": "string",
15727
+ "minLength": 1,
15728
+ "maxLength": 160
15729
+ },
15730
+ "description": {
15731
+ "type": [
15732
+ "string",
15733
+ "null"
15734
+ ]
15735
+ },
15736
+ "template_id": {
15737
+ "type": "string",
15738
+ "format": "uuid"
15739
+ },
15740
+ "audience_id": {
15741
+ "type": "string",
15742
+ "format": "uuid"
15743
+ },
15744
+ "idempotency_key": {
15745
+ "type": "string",
15746
+ "minLength": 1,
15747
+ "maxLength": 128,
15748
+ "pattern": "^[!-~]+$"
15749
+ }
15750
+ },
15751
+ "required": [
15752
+ "name",
15753
+ "template_id",
15754
+ "audience_id",
15755
+ "idempotency_key"
15756
+ ],
15757
+ "additionalProperties": false
15758
+ }
15759
+ },
15760
+ {
15761
+ "name": "besales_broadcast_campaign_update",
15762
+ "description": "Изменить имя, описание, шаблон или аудиторию кампании до запуска. Прочитай текущую карточку. Сервер проверяет права и состояние кампании. Scope: manage:campaigns.",
15763
+ "inputSchema": {
15764
+ "type": "object",
15765
+ "properties": {
15766
+ "workspace_id": {
15767
+ "type": "string",
15768
+ "format": "uuid"
15769
+ },
15770
+ "campaign_id": {
15771
+ "type": "string",
15772
+ "format": "uuid"
15773
+ },
15774
+ "name": {
15775
+ "type": "string",
15776
+ "minLength": 1,
15777
+ "maxLength": 160
15778
+ },
15779
+ "description": {
15780
+ "type": [
15781
+ "string",
15782
+ "null"
15783
+ ]
15784
+ },
15785
+ "template_id": {
15786
+ "type": "string",
15787
+ "format": "uuid"
15788
+ },
15789
+ "audience_id": {
15790
+ "type": "string",
15791
+ "format": "uuid"
15792
+ }
15793
+ },
15794
+ "required": [
15795
+ "campaign_id"
15796
+ ],
15797
+ "additionalProperties": false
15798
+ }
15799
+ },
15800
+ {
15801
+ "name": "besales_broadcast_campaign_schedule",
15802
+ "description": "Установить время автоматического запуска кампании в очереди BeSales или снять его. В указанное время могут уйти сообщения реальным получателям. Согласуй время и аудиторию перед включением. Scopes: manage:campaigns, launch:campaigns для включения.",
15803
+ "inputSchema": {
15804
+ "type": "object",
15805
+ "properties": {
15806
+ "workspace_id": {
15807
+ "type": "string",
15808
+ "format": "uuid"
15809
+ },
15810
+ "campaign_id": {
15811
+ "type": "string",
15812
+ "format": "uuid"
15813
+ },
15814
+ "scheduled_at": {
15815
+ "type": [
15816
+ "string",
15817
+ "null"
15818
+ ],
15819
+ "format": "date-time",
15820
+ "description": "Момент запуска с UTC-смещением или null для снятия расписания."
15821
+ },
15822
+ "explicit_confirmation": {
15823
+ "type": "boolean",
15824
+ "const": true,
15825
+ "description": "Передай true после явного подтверждения пользователем момента запуска или его отмены."
15826
+ }
15827
+ },
15828
+ "required": [
15829
+ "campaign_id",
15830
+ "scheduled_at",
15831
+ "explicit_confirmation"
15832
+ ],
15833
+ "additionalProperties": false
15834
+ }
15835
+ },
15639
15836
  {
15640
15837
  "name": "besales_ai_costs_get",
15641
15838
  "description": "Фактический расход моделей рабочей области: summary, tasks и breakdown. group_by/page/limit есть только у breakdown, и там group_by обязателен. Период разбирается строго: параметр не своего режима, mode=days без days и диапазон без одной границы — отказ с именем параметра, а не молчаливый ответ за всё время; days при mode=range принимается и не действует — окно задают границы. Границы диапазона — дата-время С часовым поясом. unpricedEvents остаются неизвестной стоимостью, а не нулём. Видят владелец и администраторы. Scope: read:ai-costs.",
@@ -18536,12 +18733,12 @@
18536
18733
  "minLength": 1,
18537
18734
  "maxLength": 500,
18538
18735
  "pattern": "\\S",
18539
- "description": "Необязательный текст: 1–500 знаков после удаления пробелов по краям. Без text система подбирает разные английские апелляции для каждого номера."
18736
+ "description": "Необязательный текст. По умолчанию система подбирает разные английские апелляции для каждого номера."
18540
18737
  },
18541
18738
  "explicit_confirmation": {
18542
18739
  "type": "boolean",
18543
18740
  "const": true,
18544
- "description": "Явное согласие человека на необратимую отправку апелляции от номера."
18741
+ "description": "Только после явного согласия человека: номер отправит апелляцию @SpamBot от своего имени; отменить отправку нельзя."
18545
18742
  }
18546
18743
  },
18547
18744
  "oneOf": [
@@ -18778,7 +18975,7 @@
18778
18975
  },
18779
18976
  {
18780
18977
  "name": "besales_platform_telegram_personal_profile_bulk",
18781
- "description": "Изменить профили своих личных номеров Telegram пачкой. Меняются СВОИ номера канала, не клиенты: имя first_name, фамилия last_name, описание bio, дата рождения birthday (null снимает) и ники. Фото через этот инструмент не меняется — только в приложении. Требует manage:channels. Поля профиля одинаковы для всех выбранных номеров; пропуск поля сохраняет прежнее значение. Номера выбираются account_ids (1–100 уникальных UUID v4) либо all:true — ровно одно. Ники — один из двух режимов либо ни одного: usernames (по номерам: account_id и новый username; account_ids и all не передаются) или username_base (основа ника; номера выбираются account_ids или all). Оба режима ников сразу отвергаются до запроса. Ники необратимо освобождают прежние ники у Telegram: перед вызовом покажи человеку список номеров и новые значения и получи ответ «делать?»; явное explicit_confirmation не требуется. Операция идёт заданием фермы: ответ — принятие (job_id, state, total), а не итог; итог по каждому номеру смотри в besales_platform_telegram_personal_profile_job. Обязателен стабильный idempotency_key (1–200 видимых ASCII-символов без пробелов): повтор того же намерения — с тем же ключом и аргументами; при неизвестном исходе новый ключ автоматически не создавай.",
18978
+ "description": "Изменить профили своих личных номеров Telegram пачкой. Меняются СВОИ номера канала, не клиенты: имя first_name, фамилия last_name, описание bio, дата рождения birthday (null снимает) и ники. Фото: передай stored_file_id из besales_file_upload_request → besales_file_upload_status (дождись READY) — одно фото для всех выбранных номеров. Статичный JPEG, PNG или WebP до 5 МиБ из библиотеки этой рабочей области; пропуск сохраняет фото. При загрузке укажи file_type:IMAGE и source:USER_UPLOAD, без owner_kind/owner_id. FILE_NOT_FOUND (404) — загрузи файл в рабочую область канала; TELEGRAM_AVATAR_INVALID (400) или TELEGRAM_AVATAR_TOO_LARGE (413) — выбери корректное фото до 5 МиБ; TELEGRAM_AVATAR_CHANGED (409) — выбери файл заново. Для изменённого намерения нужен новый ключ. Требует manage:channels. Поля профиля одинаковы для всех выбранных номеров; пропуск поля сохраняет прежнее значение. Номера выбираются account_ids (1–100 уникальных UUID v4) либо all:true — ровно одно. Ники — один из двух режимов либо ни одного: usernames (по номерам: account_id и новый username; account_ids и all не передаются) или username_base (основа ника; номера выбираются account_ids или all). Оба режима ников сразу отвергаются до запроса. Ники необратимо освобождают прежние ники у Telegram: перед вызовом покажи человеку список номеров и новые значения и получи ответ «делать?»; явное explicit_confirmation не требуется. Операция идёт заданием фермы: ответ — принятие (job_id, state, total), а не итог; итог по каждому номеру смотри в besales_platform_telegram_personal_profile_job. Обязателен стабильный idempotency_key (1–200 видимых ASCII-символов без пробелов): повтор того же намерения — с тем же ключом и аргументами; при неизвестном исходе новый ключ автоматически не создавай.",
18782
18979
  "inputSchema": {
18783
18980
  "type": "object",
18784
18981
  "additionalProperties": false,
@@ -18899,6 +19096,12 @@
18899
19096
  "minLength": 1,
18900
19097
  "maxLength": 200,
18901
19098
  "pattern": "^[!-~]+$"
19099
+ },
19100
+ "stored_file_id": {
19101
+ "type": "string",
19102
+ "format": "uuid",
19103
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
19104
+ "description": "Одно фото для выбранных номеров: stored_file_id из besales_file_upload_request → besales_file_upload_status. Статичный JPEG, PNG или WebP до 5 МиБ из библиотеки этой рабочей области. Пропуск сохраняет фото."
18902
19105
  }
18903
19106
  },
18904
19107
  "allOf": [
@@ -18988,6 +19191,11 @@
18988
19191
  "required": [
18989
19192
  "username_base"
18990
19193
  ]
19194
+ },
19195
+ {
19196
+ "required": [
19197
+ "stored_file_id"
19198
+ ]
18991
19199
  }
18992
19200
  ]
18993
19201
  }
@@ -19095,7 +19303,7 @@
19095
19303
  "explicit_confirmation": {
19096
19304
  "type": "boolean",
19097
19305
  "const": true,
19098
- "description": "Только после явного согласия человека."
19306
+ "description": "Явное согласие человека на удаление прокси."
19099
19307
  }
19100
19308
  }
19101
19309
  }
@@ -19143,7 +19351,7 @@
19143
19351
  "explicit_confirmation": {
19144
19352
  "type": "boolean",
19145
19353
  "const": true,
19146
- "description": "Только после явного согласия человека."
19354
+ "description": "Явное согласие человека: номер переподключится."
19147
19355
  }
19148
19356
  }
19149
19357
  }
@@ -19247,7 +19455,7 @@
19247
19455
  "explicit_confirmation": {
19248
19456
  "type": "boolean",
19249
19457
  "const": true,
19250
- "description": "Только после явного согласия человека."
19458
+ "description": "Явное согласие человека на удаление прокси из запаса."
19251
19459
  }
19252
19460
  }
19253
19461
  }
@@ -19514,6 +19722,146 @@
19514
19722
  }
19515
19723
  }
19516
19724
  }
19725
+ },
19726
+ {
19727
+ "name": "besales_platform_telegram_personal_session_import_link",
19728
+ "description": "Выдать ссылку для загрузки до 50 файлов сессий Telegram в существующий канал. Требует manage:channels; профиль platform. Человек открывает ссылку, входит в приложение и выбирает импорт файлов, прокси на файл или автоназначение в браузере. MCP файлы, манифест, api_hash и пароли не принимает. Используется существующая страница подключения, TTL 15 минут. В ответе setup_page_url и expires_at; operation_id=null и import_status_available=false: ядро пока не выдаёт безопасный id операции и пофайловый статус для MCP. Итог сверить в браузере и через besales_platform_telegram_personal_accounts. Выдача ссылки не означает импорт. После обрыва автоматически новую ссылку не создавай.",
19729
+ "inputSchema": {
19730
+ "type": "object",
19731
+ "properties": {
19732
+ "workspace_id": {
19733
+ "type": "string",
19734
+ "format": "uuid",
19735
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
19736
+ },
19737
+ "channel_id": {
19738
+ "type": "string",
19739
+ "format": "uuid",
19740
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
19741
+ }
19742
+ },
19743
+ "required": [
19744
+ "channel_id"
19745
+ ],
19746
+ "additionalProperties": false
19747
+ }
19748
+ },
19749
+ {
19750
+ "name": "besales_platform_telegram_personal_outreach_calendar_get",
19751
+ "description": "Прочитать календарь рассылок личного Telegram-канала. Scope manage:channels. Вернёт переключатель, часы отправки, часовой пояс канала, рабочие дни с лимитами первых сообщений на номер и дату паузы.",
19752
+ "inputSchema": {
19753
+ "type": "object",
19754
+ "properties": {
19755
+ "workspace_id": {
19756
+ "type": "string",
19757
+ "format": "uuid",
19758
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
19759
+ },
19760
+ "platform_id": {
19761
+ "type": "string",
19762
+ "format": "uuid",
19763
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
19764
+ }
19765
+ },
19766
+ "required": [
19767
+ "platform_id"
19768
+ ],
19769
+ "additionalProperties": false
19770
+ }
19771
+ },
19772
+ {
19773
+ "name": "besales_platform_telegram_personal_outreach_calendar_set",
19774
+ "description": "Заменить календарь рассылок личного Telegram-канала. Scope manage:channels. Сначала прочитай календарь и сохрани нужные значения. enabled=false возвращает стандартный режим. Часы внутри 10:00–19:00 в поясе канала. weekday от 1 (понедельник) до 7 (воскресенье); пропущенные дни закрыты, max_per_number=null оставляет день без дополнительного лимита. pause_until — абсолютная дата ISO 8601 с часовым поясом либо null.",
19775
+ "inputSchema": {
19776
+ "type": "object",
19777
+ "properties": {
19778
+ "workspace_id": {
19779
+ "type": "string",
19780
+ "format": "uuid",
19781
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
19782
+ },
19783
+ "platform_id": {
19784
+ "type": "string",
19785
+ "format": "uuid",
19786
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
19787
+ },
19788
+ "calendar": {
19789
+ "type": "object",
19790
+ "properties": {
19791
+ "enabled": {
19792
+ "type": "boolean"
19793
+ },
19794
+ "start_hour": {
19795
+ "type": "integer",
19796
+ "minimum": 10,
19797
+ "maximum": 18
19798
+ },
19799
+ "end_hour": {
19800
+ "type": "integer",
19801
+ "minimum": 11,
19802
+ "maximum": 19
19803
+ },
19804
+ "days": {
19805
+ "minItems": 1,
19806
+ "maxItems": 7,
19807
+ "type": "array",
19808
+ "items": {
19809
+ "type": "object",
19810
+ "properties": {
19811
+ "weekday": {
19812
+ "type": "integer",
19813
+ "minimum": 1,
19814
+ "maximum": 7
19815
+ },
19816
+ "max_per_number": {
19817
+ "anyOf": [
19818
+ {
19819
+ "type": "integer",
19820
+ "minimum": 1,
19821
+ "maximum": 1000
19822
+ },
19823
+ {
19824
+ "type": "null"
19825
+ }
19826
+ ]
19827
+ }
19828
+ },
19829
+ "required": [
19830
+ "weekday",
19831
+ "max_per_number"
19832
+ ],
19833
+ "additionalProperties": false
19834
+ }
19835
+ },
19836
+ "pause_until": {
19837
+ "anyOf": [
19838
+ {
19839
+ "type": "string",
19840
+ "format": "date-time",
19841
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
19842
+ },
19843
+ {
19844
+ "type": "null"
19845
+ }
19846
+ ]
19847
+ }
19848
+ },
19849
+ "required": [
19850
+ "enabled",
19851
+ "start_hour",
19852
+ "end_hour",
19853
+ "days",
19854
+ "pause_until"
19855
+ ],
19856
+ "additionalProperties": false
19857
+ }
19858
+ },
19859
+ "required": [
19860
+ "platform_id",
19861
+ "calendar"
19862
+ ],
19863
+ "additionalProperties": false
19864
+ }
19517
19865
  }
19518
19866
  ],
19519
19867
  "resources": [
@@ -19753,7 +20101,7 @@
19753
20101
  }
19754
20102
  ],
19755
20103
  "summary": {
19756
- "total_tools": 320,
20104
+ "total_tools": 328,
19757
20105
  "tools_by_category": {
19758
20106
  "workspace_and_help": 18,
19759
20107
  "agent_configuration": 15,
@@ -19761,10 +20109,10 @@
19761
20109
  "icp": 11,
19762
20110
  "knowledge_and_content": 52,
19763
20111
  "crm_and_data_sources": 32,
19764
- "channels_and_credentials": 40,
20112
+ "channels_and_credentials": 43,
19765
20113
  "dialogues_and_contacts": 35,
19766
20114
  "automation": 5,
19767
- "outbound_and_analytics": 72
20115
+ "outbound_and_analytics": 77
19768
20116
  },
19769
20117
  "external_execution_pairs": [
19770
20118
  "besales_icp_analysis_get_instructions / submit",
@@ -170,7 +170,7 @@ export declare const agentDesignTools: (import("./shared.js").ToolDefinition<{
170
170
  changelog_note?: string | undefined;
171
171
  }> | import("./shared.js").ToolDefinition<{
172
172
  agent_id: string;
173
- request_key?: string | undefined;
173
+ request_key: string;
174
174
  icp_profile_id?: string | null | undefined;
175
175
  candidate_prompt?: string | undefined;
176
176
  scenario_ids?: string[] | undefined;
@@ -1,5 +1,5 @@
1
- import { icpImportSourceSchema, legacyIcpImportConfigSchema } from './icp-import-source.js';
2
1
  import { randomUUID } from 'node:crypto';
2
+ import { icpImportSourceSchema, legacyIcpImportConfigSchema } from './icp-import-source.js';
3
3
  import { z } from 'zod';
4
4
  import { assertCompleteList } from '../incomplete-list.js';
5
5
  import { PROMPT_LANGUAGE_CODE_MAX_LENGTH } from './prompt-authoring.constants.js';
@@ -582,7 +582,8 @@ export const agentDesignTools = [
582
582
  requiredFields: ['agent_id'],
583
583
  schema: z.object({
584
584
  agent_id: uuidSchema,
585
- request_key: uuidSchema.optional(),
585
+ // Генерация при разборе сохраняет ОДИН ключ и для запроса, и для ответа/сбоя.
586
+ request_key: uuidSchema.optional().transform((key) => key ?? randomUUID()),
586
587
  icp_profile_id: uuidSchema.nullable().optional(),
587
588
  // Прогон по ещё не активированному тексту промпта: проверка кандидата ДО того, как он
588
589
  // станет промптом агента. Без поля кандидата проверить нечем — приходилось бы активировать
@@ -609,7 +610,7 @@ export const agentDesignTools = [
609
610
  createRequest: (input) => ({
610
611
  path: `/agents/${input.agent_id}/sandbox-runs`,
611
612
  body: compactObject({
612
- requestKey: input.request_key ?? randomUUID(),
613
+ requestKey: input.request_key,
613
614
  icpProfileId: input.icp_profile_id,
614
615
  candidatePrompt: input.candidate_prompt,
615
616
  scenarioIds: input.scenario_ids,
@@ -629,11 +630,16 @@ export const agentDesignTools = [
629
630
  : undefined,
630
631
  }),
631
632
  }),
633
+ // Чтение статуса требует run_id из успешного старта; при потерянном ответе повторяем ключ.
632
634
  verifyWithToolName: 'besales_sandbox_run_get',
633
- enhanceResponse: (response) => withInstructions(response, [
634
- 'Сохрани id прогона как run_id. Проверяй только этот прогон через besales_sandbox_run_get.',
635
- 'Первую проверку делай через 10–30 секунд; повторяй, пока status не станет COMPLETED, FAILED или CANCELLED.',
636
- ]),
635
+ enhanceResponse: (response, input) => ({
636
+ ...withInstructions(response, [
637
+ 'Сохрани id прогона как run_id. Проверяй только этот прогон через besales_sandbox_run_get.',
638
+ 'Сохрани request_key. При таймауте или 5xx повтори вызов с тем же request_key и тем же намерением: вернётся тот же прогон. Новый ключ — новый платный прогон; другое намерение с прежним ключом даёт START_KEY_CONFLICT.',
639
+ 'Первую проверку делай через 10–30 секунд; повторяй, пока status не станет COMPLETED, FAILED или CANCELLED.',
640
+ ]),
641
+ request_key: input.request_key,
642
+ }),
637
643
  }),
638
644
  defineTool({
639
645
  name: 'besales_sandbox_run_list',