@besales/mcp 0.1.0 → 0.12.0

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 (94) hide show
  1. package/README.md +272 -17
  2. package/dist/auth/connection-store.d.ts +58 -0
  3. package/dist/auth/connection-store.js +208 -0
  4. package/dist/auth/connection-store.js.map +1 -0
  5. package/dist/auth/oauth-client.d.ts +27 -2
  6. package/dist/auth/oauth-client.js +62 -11
  7. package/dist/auth/oauth-client.js.map +1 -1
  8. package/dist/auth/session-workspace.d.ts +2 -0
  9. package/dist/auth/session-workspace.js +20 -0
  10. package/dist/auth/session-workspace.js.map +1 -0
  11. package/dist/auth/token-storage.d.ts +19 -5
  12. package/dist/auth/token-storage.js +11 -6
  13. package/dist/auth/token-storage.js.map +1 -1
  14. package/dist/cli.d.ts +2 -7
  15. package/dist/cli.js +111 -33
  16. package/dist/cli.js.map +1 -1
  17. package/dist/http/api-client.d.ts +4 -13
  18. package/dist/http/api-client.js +18 -18
  19. package/dist/http/api-client.js.map +1 -1
  20. package/dist/index.d.ts +8 -6
  21. package/dist/index.js +3 -2
  22. package/dist/index.js.map +1 -1
  23. package/dist/instructions/server-instructions.d.ts +15 -0
  24. package/dist/instructions/server-instructions.js +245 -0
  25. package/dist/instructions/server-instructions.js.map +1 -0
  26. package/dist/package-metadata.js +7 -1
  27. package/dist/package-metadata.js.map +1 -1
  28. package/dist/resources/concepts/feedback-sheets.md +77 -0
  29. package/dist/resources/concepts/sandbox.md +13 -0
  30. package/dist/resources/concepts/workbook-classification.md +241 -0
  31. package/dist/resources/docs/agent-behavior.md +393 -0
  32. package/dist/resources/docs/crm-integration.md +535 -0
  33. package/dist/resources/docs/files-and-uploads.md +295 -0
  34. package/dist/resources/docs/knowledge-base.md +521 -0
  35. package/dist/resources/docs/pipeline-builder.md +221 -0
  36. package/dist/resources/docs/pipeline-settings-deep.md +221 -0
  37. package/dist/resources/docs/platforms.md +513 -0
  38. package/dist/resources/docs/prompt-anatomy.md +298 -0
  39. package/dist/resources/docs/prompt-principles.md +390 -0
  40. package/dist/resources/registry.js +34 -12
  41. package/dist/resources/registry.js.map +1 -1
  42. package/dist/resources/workflows/compare-models.md +46 -0
  43. package/dist/resources/workflows/connect-crm-from-scratch.md +89 -0
  44. package/dist/resources/workflows/connect-datasource-from-scratch.md +92 -0
  45. package/dist/resources/workflows/extract-from-document.md +36 -0
  46. package/dist/resources/workflows/iterate-with-sandbox.md +31 -0
  47. package/dist/resources/workflows/platform-setup-from-scratch.md +113 -0
  48. package/dist/resources/workflows/production-readiness-check.md +41 -0
  49. package/dist/schemas/mcp-tools.json +2638 -184
  50. package/dist/server.js +2 -0
  51. package/dist/server.js.map +1 -1
  52. package/dist/tools/definitions/agent-design.d.ts +215 -0
  53. package/dist/tools/definitions/agent-design.js +644 -0
  54. package/dist/tools/definitions/agent-design.js.map +1 -0
  55. package/dist/tools/definitions/crm-platform.d.ts +211 -0
  56. package/dist/tools/definitions/crm-platform.js +1070 -0
  57. package/dist/tools/definitions/crm-platform.js.map +1 -0
  58. package/dist/tools/definitions/datasource.d.ts +40 -0
  59. package/dist/tools/definitions/datasource.js +196 -0
  60. package/dist/tools/definitions/datasource.js.map +1 -0
  61. package/dist/tools/definitions/knowledge.d.ts +215 -0
  62. package/dist/tools/definitions/knowledge.js +782 -0
  63. package/dist/tools/definitions/knowledge.js.map +1 -0
  64. package/dist/tools/definitions/model-comparison.d.ts +25 -0
  65. package/dist/tools/definitions/model-comparison.js +101 -0
  66. package/dist/tools/definitions/model-comparison.js.map +1 -0
  67. package/dist/tools/definitions/platform-setup.d.ts +412 -0
  68. package/dist/tools/definitions/platform-setup.js +741 -0
  69. package/dist/tools/definitions/platform-setup.js.map +1 -0
  70. package/dist/tools/definitions/session.d.ts +11 -0
  71. package/dist/tools/definitions/session.js +86 -0
  72. package/dist/tools/definitions/session.js.map +1 -0
  73. package/dist/tools/definitions/shared.d.ts +742 -0
  74. package/dist/tools/definitions/shared.js +773 -0
  75. package/dist/tools/definitions/shared.js.map +1 -0
  76. package/dist/tools/definitions.d.ts +873 -88
  77. package/dist/tools/definitions.js +14 -856
  78. package/dist/tools/definitions.js.map +1 -1
  79. package/dist/tools/registry.d.ts +3 -1
  80. package/dist/tools/registry.js +90 -11
  81. package/dist/tools/registry.js.map +1 -1
  82. package/dist/tools/result.d.ts +1 -1
  83. package/dist/tools/result.js +12 -4
  84. package/dist/tools/result.js.map +1 -1
  85. package/dist/utils/logger.js +2 -1
  86. package/dist/utils/logger.js.map +1 -1
  87. package/docs/host-setup.md +34 -15
  88. package/package.json +2 -2
  89. package/scripts/install-claude-desktop.js +89 -11
  90. package/scripts/mock-api-server.js +1 -1
  91. package/scripts/mock-credentials.js +49 -6
  92. package/dist/types/api-contract.gen.d.ts +0 -6975
  93. package/dist/types/api-contract.gen.js +0 -6
  94. package/dist/types/api-contract.gen.js.map +0 -1
@@ -0,0 +1,393 @@
1
+ # 10. Поведение агента (`AgentBehavior`)
2
+
3
+ > **Источник правды:** `ai-aniomaly/docs/ai-prompt-builder/10-agent-behavior.md` — копия для MCP doc-bridge (v1.5 Increment 6b). Синкать при изменении оригинала.
4
+ >
5
+ > ⚠️ **MCP-контекст:** это доменная справка, написанная для людей/админ-UI. В MCP-сессии ты выполняешь те же операции **через besales_* tools**, а не через UI (drag-n-drop, клики в админке). Где текст ниже говорит «клиент/админ делает X через UI» — это «что должно получиться»; механику бери из tool (напр. загрузка файла → `besales_file_upload_request`; документ в knowledge → `besales_knowledge_document_upload`; сайт → `besales_knowledge_website_add`) + из workflow-ресурсов. Внутренние ссылки `[NN-name.md]` — относительные пути исходной доки, через MCP НЕ резолвятся: ищи `besales://docs/<slug>` или concept-resource.
6
+
7
+ ## 1. Назначение
8
+
9
+ `AgentBehavior` — это контейнер настроек, которые применяются **на уровне платформы** и влияют на всех её агентов. Он управляет:
10
+ - Задержками перед ответом (имитация естественной коммуникации).
11
+ - Скоростью «набора» сообщения.
12
+ - Стратегией обработки медиа (картинки, видео, документы, аудио, ссылки).
13
+ - Расписанием доступности оператора.
14
+ - Фильтрами текста и приветственными кнопками.
15
+ - Поведением при ошибках LLM.
16
+
17
+ Один `AgentBehavior` на `(workspaceId, platformId)`. AI-сервис создаёт его при настройке платформы.
18
+
19
+ ## 2. JSON-схема (полная)
20
+
21
+ ```json
22
+ {
23
+ "id": "uuid",
24
+ "platformId": "<platformId>",
25
+ "workspaceId": "<workspaceId>",
26
+
27
+ "waitingAnswerTime": 10,
28
+ "messageOpenDelay": 0,
29
+ "fakeDelay": 0,
30
+ "typingSpeed": "fast",
31
+
32
+ "canInterrupt": false,
33
+ "messageDevide": false,
34
+ "messageChunkSeparator": "",
35
+
36
+ "botGreeting": "Привет! Чем могу помочь?",
37
+ "greetingFileId": null,
38
+ "greetingButtons": [],
39
+ "greetingButtonsKeyboardType": "INLINE",
40
+
41
+ "popupDelaySeconds": 0,
42
+
43
+ "messageFilters": [],
44
+
45
+ "operatorSchedule": null,
46
+ "operatorUnavailableMessage": null,
47
+ "botWaitingReturn": 3,
48
+ "followUpWaitingReturn": -1,
49
+
50
+ "imageHandlingBehavior": "SILENT",
51
+ "imageFixedResponseText": null,
52
+ "shouldCallOperatorWithImage": true,
53
+ "imageOperatorComment": null,
54
+
55
+ "videoHandlingBehavior": "SILENT",
56
+ "videoFixedResponseText": null,
57
+ "shouldCallOperatorWithVideo": true,
58
+ "videoOperatorComment": null,
59
+
60
+ "documentHandlingBehavior": "SILENT",
61
+ "documentFixedResponseText": null,
62
+ "shouldCallOperatorWithDocument": true,
63
+ "documentOperatorComment": null,
64
+
65
+ "audioHandlingBehavior": "SILENT",
66
+ "audioFixedResponseText": null,
67
+ "shouldCallOperatorWithAudio": true,
68
+ "audioOperatorComment": null,
69
+
70
+ "urlHandlingBehavior": "PASS_THROUGH",
71
+ "urlFixedResponseText": null,
72
+ "shouldCallOperatorWithUrl": false,
73
+ "urlOperatorComment": null,
74
+
75
+ "aiErrorHandlingBehavior": "SILENT",
76
+ "aiErrorCustomMessage": null,
77
+ "shouldCallOperatorWithError": false,
78
+ "aiErrorTargetStageId": null,
79
+
80
+ "skipTaskCreationOnCallOperator": false,
81
+ "anonymizationEnabled": false,
82
+ "anonymizationDisabledTypes": [],
83
+
84
+ "goOffline": "0"
85
+ }
86
+ ```
87
+
88
+ ## 3. Задержки и скорость
89
+
90
+ | Поле | Единицы | Дефолт | Описание |
91
+ |---|---|---|---|
92
+ | `waitingAnswerTime` | секунды | 10 | Сколько ждать перед запуском LLM. Помогает дождаться нескольких сообщений подряд (если пользователь пишет очередью). 0–300. |
93
+ | `messageOpenDelay` | секунды | 0 | Только для **Telegram Personal**: пауза после отметки «прочитано» до начала имитации набора. 0–60. |
94
+ | `fakeDelay` | секунды | 0 | Дополнительная задержка-обманка перед отправкой ответа. 0–60. |
95
+ | `typingSpeed` | enum | `fast` | Скорость имитации набора: `fast` / `middle` / `slow`. |
96
+ | `canInterrupt` | bool | false | Можно ли прерывать генерацию при новом сообщении пользователя. |
97
+
98
+ ### Эффективная задержка ответа
99
+
100
+ Для Telegram Personal: `waitingAnswerTime` + `messageOpenDelay` + (время LLM-генерации) + `fakeDelay` + (имитация набора по `typingSpeed`).
101
+
102
+ Для остальных платформ: `waitingAnswerTime` + (время LLM-генерации) + `fakeDelay`.
103
+
104
+ ## 4. Разделение и форматирование сообщения
105
+
106
+ | Поле | Дефолт | Описание |
107
+ |---|---|---|
108
+ | `messageDevide` | false | Если `true` — длинный ответ агента разделяется на чанки по `messageChunkSeparator`. |
109
+ | `messageChunkSeparator` | `""` | Разделитель чанков (например, `%%%`). LLM кладёт его в ответ, бэк разбивает по нему. |
110
+
111
+ ### Пример
112
+
113
+ `messageDevide=true`, `messageChunkSeparator="%%%"`. LLM сгенерировал:
114
+
115
+ ```
116
+ Здравствуйте, Иван!%%%Конечно, помогу с заказом.%%%Какой товар вас интересует?
117
+ ```
118
+
119
+ Будет отправлено 3 отдельных сообщения.
120
+
121
+ ## 5. Фильтры текста (`messageFilters`)
122
+
123
+ Замены, применяемые к **исходящим сообщениям** перед отправкой:
124
+
125
+ ```json
126
+ "messageFilters": [
127
+ {
128
+ "id": "uuid",
129
+ "source": "магазин",
130
+ "target": "наш магазин",
131
+ "enabled": true,
132
+ "order": 1
133
+ },
134
+ {
135
+ "id": "uuid",
136
+ "source": "https://(.+)\\.example\\.com",
137
+ "target": "https://$1.example.ru",
138
+ "enabled": true,
139
+ "order": 2
140
+ }
141
+ ]
142
+ ```
143
+
144
+ | Поле | Описание |
145
+ |---|---|
146
+ | `source` | Текст или регэксп для поиска. |
147
+ | `target` | На что заменить (можно использовать `$1`, `$2` для regex-групп). |
148
+ | `enabled` | Можно отключить без удаления. |
149
+ | `order` | Порядок применения. |
150
+
151
+ **Лимит:** до **20** правил.
152
+
153
+ **Зачем:** убрать упоминания внутренней терминологии, заменить домены, нормализовать тон.
154
+
155
+ ## 6. Приветственные кнопки (`greetingButtons`)
156
+
157
+ > **MCP-операторам:** по умолчанию приветствие — **без кнопок** (живой текст `botGreeting`). `greetingButtons` — opt-in: добавляй ТОЛЬКО по явному запросу пользователя (кнопки дают menu-feel, противоречат принципу «звучит как человек»). На создании агента ставится только `bot_greeting`; остальной behavior — позже.
158
+
159
+ Кнопки, которые отправляются **с приветственным сообщением** (`botGreeting` или `greetingFileId`):
160
+
161
+ ```json
162
+ "greetingButtons": [
163
+ { "id": "uuid", "label": "Каталог", "text": "Покажи каталог", "order": 1 },
164
+ { "id": "uuid", "label": "Доставка", "text": "Расскажи о доставке", "order": 2 },
165
+ { "id": "uuid", "label": "Оператор", "text": "Хочу оператора", "order": 3 }
166
+ ]
167
+ ```
168
+
169
+ | Поле | Описание |
170
+ |---|---|
171
+ | `label` | Текст на кнопке (≤20 символов). |
172
+ | `text` | Что отправляется при нажатии (для `REPLY` keyboard) или `callback_data` (для `INLINE`). |
173
+ | `order` | Порядок. |
174
+
175
+ **Лимит:** до **10** кнопок.
176
+
177
+ `greetingButtonsKeyboardType` — `INLINE` (под сообщением) или `REPLY` (вместо клавиатуры). Поддерживается на: Telegram Bot, VK, Salebot, Wazzup, Instagram, WebWidget.
178
+
179
+ `greetingFileId` — `StoredFile.id` для приветственного аудио/картинки/видео.
180
+
181
+ `popupDelaySeconds` — для **Web Widget**: задержка показа popup-сообщения в свёрнутом виджете (0 = отключено).
182
+
183
+ ## 7. Расписание оператора
184
+
185
+ ```json
186
+ "operatorSchedule": {
187
+ "enabled": true,
188
+ "availability": {
189
+ "monday": { "active": true, "startTime": "09:00", "endTime": "19:00" },
190
+ "tuesday": { "active": true, "startTime": "09:00", "endTime": "19:00" },
191
+ "wednesday": { "active": true, "startTime": "09:00", "endTime": "19:00" },
192
+ "thursday": { "active": true, "startTime": "09:00", "endTime": "19:00" },
193
+ "friday": { "active": true, "startTime": "09:00", "endTime": "19:00" },
194
+ "saturday": { "active": false, "startTime": null, "endTime": null },
195
+ "sunday": { "active": false, "startTime": null, "endTime": null }
196
+ }
197
+ },
198
+ "operatorUnavailableMessage": "Сейчас оператор недоступен. Мы работаем по будням с {startTime} до {endTime}."
199
+ ```
200
+
201
+ Если `enabled=true` и текущее время вне расписания — `call_operator` будет отвечать `operatorUnavailableMessage` (с подстановкой `{startTime}`/`{endTime}` из текущего дня).
202
+
203
+ ## 8. Возврат бота после оператора
204
+
205
+ | Поле | Дефолт | Описание |
206
+ |---|---|---|
207
+ | `botWaitingReturn` | 3 | Сколько часов бот молчит после сообщения оператора. Допустимые: `0`, `1`, `3`, `6`, `12`, `24`. `0` = до команды `/start`. |
208
+ | `followUpWaitingReturn` | -1 | На сколько часов отключить follow-up после оператора. `-1` = не отключать, `0` = навсегда, `1`–`24` — часы. |
209
+ | `skipTaskCreationOnCallOperator` | false | Если `true` — при `call_operator` система **только** меняет ответственного на оператора, без постановки задачи в CRM. Полезно, когда workflow в CRM ведётся через статусы воронки, а не через task'ы, и лишние «висящие» задачи на оператора засоряют его список дел. |
210
+ | `anonymizationEnabled` | false | Обратимая PII-анонимизация LLM-пайплайна (per-platform). Если `true` — реальные имя/телефон/email клиента вырезаются из сообщений перед отправкой в LLM (заменяются токенами) и подставляются обратно в ответе и в аргументах tool-call (например, поля CRM). Ставится через секцию `privacy: { anonymization_enabled }` в `besales_behavior_update`. |
211
+ | `anonymizationDisabledTypes` | `[]` | Типы PII, выключенные из анонимизации (при `anonymizationEnabled=true` отдаются в LLM **реальными**). OFF-список: пусто = скрывать всё. Имя дробится на части — исключив `FIRST_NAME`, отдаёшь реальное имя в LLM, и модель склоняет его в нужный падеж сама. Значения: `FIRST_NAME`/`LAST_NAME`/`PATRONYMIC`/`PERSON`/`PHONE`/`EMAIL`/`INN`/`PASSPORT`/`CARD`/`DATE_OF_BIRTH`/`ACCOUNT`/`SNILS`/`OGRN`/`OGRNIP`/`SOCIAL_ID` (СНИЛС/ОГРН/ОГРНИП — по контрольной сумме; SOCIAL_ID — VK/Telegram/Max @-хэндлы и ссылки на профиль). Ставится через `privacy: { anonymization_disabled_types }`. ⚠️ Выключение типа — осознанная передача данных провайдеру модели. |
212
+
213
+ ## 9. Обработка медиа от пользователя
214
+
215
+ Для каждого типа медиа задаётся:
216
+ - **`*HandlingBehavior`** — что делать с медиа.
217
+ - **`*FixedResponseText`** — текст для `FIXED_RESPONSE` режима.
218
+ - **`shouldCallOperatorWith*`** — вызывать ли оператора при получении.
219
+ - **`*OperatorComment`** — комментарий для оператора.
220
+
221
+ ### Изображения (`ImageHandlingBehavior`)
222
+
223
+ ```json
224
+ {
225
+ "imageHandlingBehavior": "PROCESS_WITH_LLM",
226
+ "imageFixedResponseText": null,
227
+ "shouldCallOperatorWithImage": false,
228
+ "imageOperatorComment": null
229
+ }
230
+ ```
231
+
232
+ | Значение | Что делает |
233
+ |---|---|
234
+ | `SILENT` | Промолчать (default). |
235
+ | `PROCESS_WITH_LLM` | Запустить vision-модель (gpt-4.1-mini) и интерпретировать изображение в текст для LLM. |
236
+ | `FIXED_RESPONSE` | Отправить фиксированный текст из `imageFixedResponseText`. |
237
+
238
+ `PROCESS_WITH_LLM` доступен **только** для изображений. Для видео/документов/аудио — только `SILENT` или `FIXED_RESPONSE`.
239
+
240
+ ### Видео / Документы / Аудио (`VideoHandlingBehavior`, `DocumentHandlingBehavior`, `AudioHandlingBehavior`)
241
+
242
+ Все три enum'а имеют одинаковый набор значений:
243
+
244
+ | Значение | Что делает |
245
+ |---|---|
246
+ | `SILENT` | Промолчать (default). |
247
+ | `FIXED_RESPONSE` | Отправить фиксированный текст из соответствующего `*FixedResponseText`. |
248
+
249
+ ```json
250
+ {
251
+ "videoHandlingBehavior": "FIXED_RESPONSE",
252
+ "videoFixedResponseText": "Извините, я пока не умею смотреть видео. Опишите, пожалуйста, словами.",
253
+ "shouldCallOperatorWithVideo": true,
254
+ "videoOperatorComment": "Клиент прислал видео — нужно посмотреть."
255
+ }
256
+ ```
257
+
258
+ ### Голосовые сообщения (Whisper-транскрипция)
259
+
260
+ ⚠️ **Голос ≠ аудиофайл.** `AudioHandlingBehavior` (выше) применяется только к **аудиофайлам** (`.mp3 / .m4a / .wav / .aac / ...`). **Голосовые сообщения** (Telegram `voice` / `video_note`; на остальных платформах — медиа с расширением `.opus / .oga / .ogg / .webm`) обрабатываются отдельно: они **автоматически транскрибируются** через OpenAI Whisper, и распознанный текст уходит в LLM как обычное сообщение.
261
+
262
+ - **Включено по умолчанию, без отдельного тумблера** в `AgentBehavior` — транскрипция голоса работает на всех **9 платформах** (Telegram, TelegramPersonal, Instagram, Avito, VKon, Wazzup, Salebot, Bitrix24Bot, GetCourse). Разделение voice/audio — по расширению файла (утилита `inferAudioKindFromUrl`).
263
+ - **Лимит размера — 20 MB** (`MAX_TRANSCRIBE_FILE_SIZE_BYTES`, с запасом ниже 25 MB-лимита Whisper). Файл больше → транскрипция не делается, в LLM уходит плейсхолдер `[Файл слишком большой для транскрибации (XMB > 20MB)]`.
264
+ - Если речь не распознана → `[Речь не распознана]`. Стоимость расшифровки пишется в AI-леджер как операция `WHISPER_TRANSCRIPTION` (модель `whisper-1`).
265
+ - Язык можно подсказать Whisper (ISO 639-1) — обычно совпадает с языком агента.
266
+
267
+ > То есть `audioHandlingBehavior: SILENT` заглушит только присланные **аудиофайлы**; голосовые всё равно будут расшифрованы и обработаны LLM. Полное описание пайплайна — в [`docs/modules/transcription.md`](../modules/transcription.md).
268
+
269
+ ### Ссылки
270
+
271
+ ```json
272
+ {
273
+ "urlHandlingBehavior": "PROCESS_WITH_CRAWLER",
274
+ "urlFixedResponseText": null,
275
+ "shouldCallOperatorWithUrl": false,
276
+ "urlOperatorComment": null
277
+ }
278
+ ```
279
+
280
+ | `urlHandlingBehavior` | Что делает |
281
+ |---|---|
282
+ | `PASS_THROUGH` | Передать ссылку как есть в LLM (default). |
283
+ | `SILENT` | Игнорировать. |
284
+ | `FIXED_RESPONSE` | Отправить фиксированный текст. |
285
+ | `PROCESS_WITH_CRAWLER` | Скачать страницу через web-crawler и положить контент в контекст LLM. |
286
+
287
+ ## 10. Обработка ошибок LLM
288
+
289
+ ```json
290
+ {
291
+ "aiErrorHandlingBehavior": "SEND_ERROR_MESSAGE",
292
+ "aiErrorCustomMessage": "Прошу прощения, у меня сейчас технические сложности. Передаю вас оператору.",
293
+ "shouldCallOperatorWithError": true,
294
+ "aiErrorTargetStageId": 999
295
+ }
296
+ ```
297
+
298
+ | Поле | Описание |
299
+ |---|---|
300
+ | `aiErrorHandlingBehavior` | `SILENT` (default) или `SEND_ERROR_MESSAGE`. |
301
+ | `aiErrorCustomMessage` | Текст для `SEND_ERROR_MESSAGE`. |
302
+ | `shouldCallOperatorWithError` | Если `true` — автоматически вызывать оператора. |
303
+ | `aiErrorTargetStageId` | Куда перевести лид при ошибке (`null` = на первый этап текущей воронки). |
304
+
305
+ ## 11. Inline-пример: типичная конфигурация для Telegram-бота
306
+
307
+ ```json
308
+ {
309
+ "platformId": "<platformId>",
310
+ "workspaceId": "<workspaceId>",
311
+
312
+ "waitingAnswerTime": 15,
313
+ "fakeDelay": 3,
314
+ "typingSpeed": "middle",
315
+
316
+ "messageDevide": true,
317
+ "messageChunkSeparator": "%%%",
318
+
319
+ "botGreeting": "Здравствуйте! Я Анна, помогу с выбором цветов и оформлением заказа.",
320
+ "greetingButtons": [
321
+ { "label": "Каталог", "text": "Покажи каталог букетов", "order": 1 },
322
+ { "label": "Доставка", "text": "Расскажи про доставку", "order": 2 },
323
+ { "label": "Связаться с менеджером", "text": "Хочу с менеджером", "order": 3 }
324
+ ],
325
+ "greetingButtonsKeyboardType": "INLINE",
326
+
327
+ "messageFilters": [
328
+ { "source": "ChatGPT", "target": "наш ассистент", "enabled": true, "order": 1 }
329
+ ],
330
+
331
+ "operatorSchedule": {
332
+ "enabled": true,
333
+ "availability": {
334
+ "monday": { "active": true, "startTime": "09:00", "endTime": "19:00" },
335
+ "tuesday": { "active": true, "startTime": "09:00", "endTime": "19:00" },
336
+ "wednesday": { "active": true, "startTime": "09:00", "endTime": "19:00" },
337
+ "thursday": { "active": true, "startTime": "09:00", "endTime": "19:00" },
338
+ "friday": { "active": true, "startTime": "09:00", "endTime": "19:00" },
339
+ "saturday": { "active": true, "startTime": "10:00", "endTime": "18:00" },
340
+ "sunday": { "active": false, "startTime": null, "endTime": null }
341
+ }
342
+ },
343
+ "operatorUnavailableMessage": "Сейчас оператор отдыхает 🌙. Я отвечу или передам ему сообщение, как только он подключится.",
344
+
345
+ "botWaitingReturn": 3,
346
+ "followUpWaitingReturn": 12,
347
+
348
+ "imageHandlingBehavior": "PROCESS_WITH_LLM",
349
+ "shouldCallOperatorWithImage": false,
350
+
351
+ "videoHandlingBehavior": "FIXED_RESPONSE",
352
+ "videoFixedResponseText": "К сожалению, я пока не работаю с видео. Опишите словами или пришлите фото.",
353
+ "shouldCallOperatorWithVideo": true,
354
+
355
+ "documentHandlingBehavior": "FIXED_RESPONSE",
356
+ "documentFixedResponseText": "Спасибо за документ! Передаю менеджеру для проверки.",
357
+ "shouldCallOperatorWithDocument": true,
358
+
359
+ "urlHandlingBehavior": "PROCESS_WITH_CRAWLER",
360
+
361
+ "aiErrorHandlingBehavior": "SEND_ERROR_MESSAGE",
362
+ "aiErrorCustomMessage": "Прошу прощения, минутка технических сложностей. Сейчас приглашу менеджера.",
363
+ "shouldCallOperatorWithError": true
364
+ }
365
+ ```
366
+
367
+ ## 12. Граничные случаи и валидация
368
+
369
+ | Правило | Что AI-сервису помнить |
370
+ |---|---|
371
+ | Один `AgentBehavior` на платформу | Не пытаться создать два — конфликт по `(workspaceId, platformId)`. |
372
+ | `waitingAnswerTime` 0–300 сек | Большее значение = пользователь дольше ждёт ответа. |
373
+ | `messageOpenDelay` только для Telegram Personal | На обычных Telegram Bot ничего не даёт. |
374
+ | `messageDevide=true` без `messageChunkSeparator` | Не работает — нужен явный разделитель. |
375
+ | LLM должен знать про `messageChunkSeparator` | Если включаете `messageDevide`, добавьте в `baseSystemPrompt` инструкцию: «Когда нужно разделить ответ на части, ставь между частями `%%%`». |
376
+ | `imageHandlingBehavior=PROCESS_WITH_LLM` | Только для изображений (vision). Для видео/доков/аудио — `SILENT` или `FIXED_RESPONSE`. |
377
+ | `urlHandlingBehavior=PROCESS_WITH_CRAWLER` | Может тормозить (внешний запрос). Не включать массово. |
378
+ | `messageFilters` — до 20 правил | Применяются по `order`. |
379
+ | `greetingButtons` — до 10 кнопок | Платформенный лимит. |
380
+ | `botWaitingReturn=0` | Бот не вернётся автоматически — нужно явное `/start` от оператора. |
381
+ | `operatorSchedule.enabled=false` | Оператор «всегда доступен» — не блокировать `call_operator`. |
382
+ | `aiErrorTargetStageId=null` | Не критично — система переведёт на первый этап. |
383
+ | `skipTaskCreationOnCallOperator=true` | Только смена ответственного, без постановки задачи в CRM (для AmoCRM/Bitrix24). |
384
+
385
+ ## 13. Связь с другими подсистемами
386
+
387
+ | Подсистема | Связь |
388
+ |---|---|
389
+ | **Агенты** ([`01-agents.md`](01-agents.md)) | `AgentBehavior` влияет на всех агентов платформы. |
390
+ | **Платформа** ([`11-platforms.md`](11-platforms.md)) | Один `AgentBehavior` на платформу. |
391
+ | **Триггеры** ([`04-triggers-and-actions.md`](04-triggers-and-actions.md)) | `CALL_OPERATOR` использует `operatorSchedule`. |
392
+ | **Follow-up** ([`08-follow-up.md`](08-follow-up.md)) | `followUpWaitingReturn` отключает follow-up после оператора. |
393
+ | **Файлы** | `greetingFileId` — `StoredFile`. |