@besales/mcp 0.47.1 → 0.48.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.
@@ -9,6 +9,10 @@ const DAILY_CAP_MAX = 5000;
9
9
  */
10
10
  const FRESHNESS_DAYS_MAX = 78;
11
11
  const COOLDOWN_DAYS_MAX = 365;
12
+ /** Потолок паузы повтора сегмента — серверный `SCHEDULE_RESEND_PAUSE_DAYS_MAX`. */
13
+ const RESEND_PAUSE_DAYS_MAX = 365;
14
+ /** Потолок списка «не писать после сегментов» — серверный `SCHEDULE_SKIP_AFTER_SEGMENTS_MAX`. */
15
+ const SKIP_AFTER_SEGMENTS_MAX = 20;
12
16
  /**
13
17
  * Окно свежести строк без расписания в «Пуле сегодня» — паритет с `POOL_TODAY_WINDOW_DAYS_MAX`
14
18
  * бэкенда: окно регистраций строки (окно + 14 суток запаса) обязано уложиться в общую выкачку
@@ -36,6 +40,10 @@ const orderSchema = z.enum(['FRESH_FIRST', 'OLD_FIRST']);
36
40
  const anchorSchema = z.enum([
37
41
  'SERIES_END',
38
42
  'SERIES_END_PLUS_WAIT',
43
+ // Конец ПЕРВОГО эфира серии плюс ожидание — для сегментов, которые пишут пропустившему первый
44
+ // эфир, ПОКА СЕРИЯ ИДЁТ. Требует фасета attendedFirstSession и перекрытия предохранителя серии
45
+ // на расписании (guard_active_series), иначе отправку остановит правило площадки.
46
+ 'FIRST_SESSION_END_PLUS_WAIT',
39
47
  'LAST_APPLICATION',
40
48
  'REGISTRATION',
41
49
  // ⚠️ Схема СТРОГАЯ: значение, объявленное на сервере и забытое здесь, отвергается ещё до
@@ -89,7 +97,9 @@ const scheduleShape = {
89
97
  daily_cap: z.number().int().min(1).max(DAILY_CAP_MAX),
90
98
  selection_order: orderSchema,
91
99
  cooldown_days: z.number().int().min(0).max(COOLDOWN_DAYS_MAX),
92
- handoff_from_school_platforms: z.boolean().optional().describe('ПЕРЕДАЧА: забирать людей с ДРУГИХ площадок GetCourse той же школы. Включённый флаг меняет смысл отбора: берутся ТОЛЬКО люди, чья карточка живёт на других площадках школы (и те, кого прошлая попытка уже перевезла, но сообщение не ушло), а перед отправкой карточка переносится сюда — с перепином на заказ сегмента и остановкой цепочек прежней площадки. Площадки-источники считает сам отбор («вся школа минус своя»), поэтому новая площадка школы подхватывается без правки расписания. Требует сегмента-ПРОДОЛЖЕНИЯ (снят «только нетронутым», без правила повтора): у человека с соседней площадки право первого сообщения уже сожжено. Ещё требует заполненного домена школы у площадки расписания и хотя бы одной другой площадки GetCourse в школе. Выключено — передачи нет.'),
100
+ handoff_from_school_platforms: z.boolean().optional().describe('ПЕРЕДАЧА: забирать людей с ДРУГИХ площадок GetCourse той же школы В ДОПОЛНЕНИЕ к своим. Своим людям площадки и людям без карточек расписание пишет как обычно, а людей, чья карточка живёт на других площадках школы (и тех, кого прошлая попытка уже перевезла, но сообщение не ушло), перед отправкой переносит сюда — с перепином на заказ сегмента и остановкой цепочек прежней площадки. Поэтому флаг включают прямо на основной авторассылке сегмента, второе расписание на тот же сегмент не нужно (так с 15.09.2026; раньше флаг заменял пул, и свои люди площадки текста не получали). Площадки-источники считает сам отбор («вся школа минус своя»), поэтому новая площадка школы подхватывается без правки расписания. Включайте на площадке, КУДА переносить людей (обычно квал-площадка): на площадке серии флаг заберёт к ней людей квал-площадки. Флаг нужен на ВСЕХ пересекающихся старших сегментах площадки: претензия старшего сегмента о флаге не знает, и человек с соседней площадки иначе не получит ничего. Требует сегмента-ПРОДОЛЖЕНИЯ (снят «только нетронутым», без правила повтора): у человека с соседней площадки право первого сообщения уже сожжено. Ещё требует заполненного домена школы у площадки расписания и хотя бы одной другой площадки GetCourse в школе. Выключено — передачи нет.'),
101
+ resend_segment_on_new_registration: z.boolean().optional().describe('ПОВТОР СЕГМЕНТА ПО НОВОЙ РЕГИСТРАЦИИ (с 16.09.2026). Включено — человеку, которому этим сегментом уже писали, расписание напишет снова, только если он зарегистрировался ПОСЛЕ нашей последней отправки этого сегмента и с неё прошла пауза resend_segment_pause_days; продукт регистрации может быть любым. Выключено — сегмент человеку не повторяется никогда (причина alreadySentSegment). Действует только у сегмента-ПРОДОЛЖЕНИЯ без правила повтора: у сегмента «только нетронутым» второе сообщение держит право первого касания (alreadyGreeted). Не передано — у нового расписания включено, у существующего остаётся как было.'),
102
+ resend_segment_pause_days: z.number().int().min(0).max(RESEND_PAUSE_DAYS_MAX).optional().describe('Пауза повтора сегмента: сутки по 24 часа от нашей последней отправки этого сегмента человеку. Пока не прошла — причина resendPause, человек вернётся в пул сам. Не передано — у нового расписания 3, у существующего остаётся как было. ⚠️ Меньше трёх суток повтор обычно не ускорит: разговор после нашей реплики закрывается тремя сутками тишины, и до тех пор человека держит причина dialogQuiet.'),
93
103
  channels: z
94
104
  // ⚠️ Канон транспортов, а не свободная строка: иначе про допустимые значения модель узнаёт
95
105
  // из 400-й ошибки. Ровно этот дефект уже закрыт parity-тестом контракта для соседних тулов.
@@ -101,6 +111,16 @@ const scheduleShape = {
101
111
  .enum(['RESTRICT', 'ADD'])
102
112
  .optional()
103
113
  .describe(`⚠️ УСТАРЕЛ и на поведение НЕ влияет (с 23.08.2026). Список channels значит «слать сюда», судьбу КАЖДОГО канала решает сервер: мессенджер уходит, только если школа подтвердила его наличие; SMS — только при известном телефоне; Email, WhatsApp, Viber, Сайт, Chatium — вслепую. Поле принимается ради обратной совместимости и игнорируется.`),
114
+ guard_active_series: z
115
+ .enum(['OFF', 'WARN', 'BLOCK'])
116
+ .nullable()
117
+ .optional()
118
+ .describe('Перекрытие предохранителя «идёт вебинарная серия» ДЛЯ ЭТОГО расписания. Не передано — у существующего остаётся как было; null — вернуть под настройку площадки. OFF — расписание пишет и во время серии человека; WARN — причина пишется в аудит, отправка идёт; BLOCK — отправка останавливается. Нужно сегментам, которые пишут внутрь серии ПО ЗАМЫСЛУ (например «пропустил первый эфир», якорь FIRST_SESSION_END_PLUS_WAIT): у них серия идёт по определению, а площадочный переключатель один на ВСЕ расписания площадки и ослабил бы защиту у postweb*, prelist, closed-app и cta разом. Перекрывается только правило серии: заявка и оплата остаются площадочными.'),
119
+ skip_after_segment_ids: z
120
+ .array(uuidSchema)
121
+ .max(SKIP_AFTER_SEGMENTS_MAX)
122
+ .optional()
123
+ .describe('НЕ ПИСАТЬ ПОСЛЕ СЕГМЕНТОВ (с 22.09.2026): id сегментов справочника (segment.id из besales_broadcast_schedule_list). Человеку, которому текст любого из них ушёл НЕ РАНЬШЕ его регистрации — той, по которой он попал в пул, — это расписание не пишет (причина skipAfterSegment); новая регистрация после того касания открывает человека снова. Сценарий: у расписания reg-no-show указать сегмент reg-no-show-day1 — получившему «пропустил первый эфир» обычное «не смогли прийти» по той же серии не уйдёт, остальным уйдёт. Не передано — у существующего остаётся как было; [] — снять правило. Сам сегмент расписания и чужие id сервер отвергает. Именно id, а не имена: имя сегмента переименовывают.'),
104
124
  is_enabled: z.boolean().optional(),
105
125
  };
106
126
  /** `all` — это «фильтра нет», то есть ПУСТОЙ список на стороне API. */
@@ -127,11 +147,17 @@ const toScheduleBody = (input) => compactObject({
127
147
  selectionOrder: input.selection_order,
128
148
  cooldownDays: input.cooldown_days,
129
149
  handoffFromSchoolPlatforms: input.handoff_from_school_platforms,
150
+ resendSegmentOnNewRegistration: input.resend_segment_on_new_registration,
151
+ resendSegmentPauseDays: input.resend_segment_pause_days,
130
152
  channels: input.channels,
131
153
  // ⚠️ Режим передаётся ТОЛЬКО если его задал вызывающий: сам он на поведение не влияет, но
132
154
  // подставлять сюда `RESTRICT` значит записать в строку расписания решение, которого никто
133
155
  // не принимал, — а прочитано оно будет как действующая настройка.
134
156
  channelsMode: input.channels_mode,
157
+ // ⚠️ `null` проходит намеренно (`compactObject` режет только `undefined`): им снимают
158
+ // перекрытие, и «не передал» обязано отличаться от «верни под площадку».
159
+ guardActiveSeries: input.guard_active_series,
160
+ skipAfterSegmentIds: input.skip_after_segment_ids,
135
161
  isEnabled: input.is_enabled,
136
162
  });
137
163
  /**
@@ -180,17 +206,24 @@ export const broadcastSchedulerTools = [
180
206
  }),
181
207
  enhanceResponse: (response) => withInstructions(response, [
182
208
  'Ничего не отправляет и не пишет: считает ТЕМ ЖЕ путём, что и крон — тот же источник фактов, тот же компилятор правила, те же исключения.',
183
- '⚠️ Показывай пользователю excludedBy числами. alreadySentSegment — этим сегментом уже слали; alreadyGreeted — человек уже получал «Первое сообщение» (одно на контакт навсегда, любым сегментом; прежнее имя ключа coldWelcomeClaimed приходит от старого бэкенда в окне выкатки); activeEpisode — человека уже ведёт автоприём регистраций (приветствие должны и не отдали, либо подготовлен повторный вход на новый эфир); touchClaimed — это касание уже занято в журнале; journal — контакт подавался этим расписанием и ждёт паузы; cooldown — получал любую нашу рассылку в окне.',
209
+ '⚠️ Показывай пользователю excludedBy числами. alreadySentSegment — этим сегментом уже слали (при включённом resend_segment_on_new_registration — и регистрации новее нашей отправки нет); alreadyGreeted — человек уже получал «Первое сообщение» (одно на контакт навсегда, любым сегментом; прежнее имя ключа coldWelcomeClaimed приходит от старого бэкенда в окне выкатки); activeEpisode — человека уже ведёт автоприём регистраций (приветствие должны и не отдали, либо подготовлен повторный вход на новый эфир); touchClaimed — касание этого сегмента уже занято в журнале, либо тот же текст ушёл человеку другим сегментом меньше трёх суток назад (с 16.09.2026 другой сегмент тем же шаблоном можно, но после трёх суток тишины); журнал подач этого расписания (с 16.09.2026 тремя причинами вместо journal): journalSubmitted — подача ушла, ещё идёт или касание занято, journalNoMessenger — прошлая подача закончилась «карточку не завели» или «каналами не достать» (пауза 7 суток), journalRetryPause — прошлая попытка не удалась, и пауза после неё ещё идёт; contactBlocked — бан, удалённая карточка или действующий мьют; contactWithManager — с человеком работает менеджер (операторский статус или передача диалога в отдел моложе трёх суток); прежние ключи journal и contactHeld приходят только от старого бэкенда в окне выкатки; cooldown — получал любую нашу рассылку в окне.',
184
210
  '⚠️⚠️ productNotInList — у расписания задан список продуктов, а у этих людей продукт другой или не указан вовсе. Прежде этот отсев шёл МОЛЧА: строка выбрасывалась без счётчика, и часть пула исчезала без причины. Чинится списком продуктов в расписании.',
185
211
  '⚠️⚠️ notReachable — ни один из ВЫБРАННЫХ каналов до человека не доходит, и это подтвердил ответ школы. Про невыбранные каналы число не говорит ничего. Чинится составом каналов расписания или рассылки, а не правилом сегмента: вердикт записывается вместе с набором каналов и перестаёт держать паузу, как только набор изменили.',
186
212
  '⚠️⚠️ factsUnknown — НЕ отсев: эти люди в пуле. Число значит «школу про них ещё не спрашивали», и без него ноль в notReachable читается как «все достижимы». Доставки оно НЕ обещает: тот же прогон опрашивает школу перед подачей (по 300 за раз) и часть из них тогда отсеет — в отчёте прогона эти числа уже пересчитаны.',
187
213
  '⚠️ Если notReachable равен размеру пула, сперва проверь площадку: когда НИ ОДИН выбранный канал ею не обслуживается, недостижимы будут все до единого, и чинится это в настройках площадки, а не в расписании. Предпросмотр в этом случае показывает отдельное предупреждение, а прогон закрывается своей причиной.', '⚠️ unverifiable — «нечем проверить», а НЕ «не подходит»: нет назначения серии, серия ещё идёт, нет длительности просмотра. Эти люди в рассылку не идут, и это правильно: отсутствие данных о явке не равно отсутствию человека на эфире.',
188
214
  '⚠️⚠️ truncatedSeriesSkipped — ЕДИНСТВЕННАЯ источниковая причина, которую чинит сам оператор: выборка упёрлась в потолок строк, и запись о явке серии могла остаться за его границей, поэтому судить о ней нечем. Чинится окном расписания за минуту — сузить свежесть, список воронок или продуктов. До 10.09.2026 это число складывалось с unverifiable и читалось как жалоба на данные школы: не путай их снова.',
189
- '⚠️⚠️ claimedByHigherPriority — НЕ отсев по данным, а приоритет: человек подходит и под сегмент с БОЛЬШИМ приоритетом, у которого на этой площадке включено расписание ТОГО ЖЕ механизма, он в его окне и фильтрах, и то расписание его возьмёт — или уже отправило ему свой текст, в том числе волной школы. Исключение одно: старшее пишет только нетронутым, а этому человеку мы уже писали ДРУГИМ сегментом — тогда он остаётся младшему. Большое число — не поломка, а мера пересечения; меняется приоритетами сегментов. ⚠️ Число НЕ обещает, что человеку вообще что-то уйдёт: (1) потолок и день запуска старшего не проверяются — упрётся старшее в потолок, излишек ждёт следующего запуска, а при FRESH_FIRST самые старые из него выходят из окна ни с чем; (2) если текст старшего уже ушёл волной школы, подхватить человека может только расписание ПОВТОРА старшего сегмента, и его надо завести отдельно; (3) человек без живой карточки на этой площадке не получит ничего ни от кого — повтор старшего отсечёт его причиной repeatNoCard; (4) если у расписаний РАЗНЫЕ списки воронок, разведение неполно: воронки отсекаются на стороне источника фактов, и строк человека из чужой воронки в снимке нет вовсе — ставь пересекающимся сегментам одинаковые воронки.',
215
+ '⚠️⚠️ claimedByHigherPriority — НЕ отсев по данным, а приоритет: человек подходит и под сегмент с БОЛЬШИМ приоритетом, у которого на этой площадке включено расписание ТОГО ЖЕ механизма, он в его окне и фильтрах, и то расписание его возьмёт — или уже отправило ему свой текст, в том числе волной школы. Исключение одно: старшее пишет только нетронутым, а этому человеку мы уже писали ДРУГИМ сегментом — тогда он остаётся младшему. Если старшее этому человеку уже писало (с 16.09.2026): без регистрации новее той отправки он остаётся за старшим; при новой регистрации его забирает старшее, если само повторит сегмент (resend_segment_on_new_registration у сегмента-продолжения), а иначе он уходит младшему — только когда продукт младшего не совпадает ни с одной отправкой старшего (неизвестный продукт держит). Большое число — не поломка, а мера пересечения; меняется приоритетами сегментов. ⚠️ Число НЕ обещает, что человеку вообще что-то уйдёт: (1) потолок и день запуска старшего не проверяются — упрётся старшее в потолок, излишек ждёт следующего запуска, а при FRESH_FIRST самые старые из него выходят из окна ни с чем; (2) если текст старшего уже ушёл волной школы, подхватить человека может только расписание ПОВТОРА старшего сегмента, и его надо завести отдельно; (3) человек без живой карточки на этой площадке не получит ничего ни от кого — повтор старшего отсечёт его причиной repeatNoCard; (4) если у расписаний РАЗНЫЕ списки воронок, разведение неполно: воронки отсекаются на стороне источника фактов, и строк человека из чужой воронки в снимке нет вовсе — ставь пересекающимся сегментам одинаковые воронки.',
190
216
  '⚠️⚠️ repeatNoCard — кандидат на ПОВТОР (прошлое касание годится), но живой карточки на ЭТОЙ площадке у человека нет: чаще всего волну школы записали на эту площадку, а карточка у него на соседней. Без карточки не проверить ответы и дожимы, а импорт карточку здесь не заведёт (обновит соседнюю), поэтому такие люди исключаются. Расписанием это не чинится.',
191
- '⚠️⚠️ cardOnSiblingPlatform — человек живёт на СОСЕДНЕЙ площадке той же школы GetCourse, а на площадке расписания карточки у него нет. Импорт её сюда не перенесёт: он ищет человека по школе и обновляет ту карточку, что уже есть, — поэтому такие люди исключаются, а не уезжают в импорт (иначе каждый месяц они занимали бы слот дневного потолка и закрывались исходом NOT_IMPORTED). Расписанием не чинится: рассылать надо с той площадки, где человек живёт. Большое число у расписания на новой площадке — норма: люди школы живут на старой.',
192
- '⚠️⚠️ noMessengerVerdict — школа УЖЕ отвечала, что привязанных мессенджеров у человека нет, и ответ ещё в силе. Карточки в базе у него нет, импорт её не заведёт, поэтому подача сожгла бы слот дневного потолка и слот импортов воркспейса и закрылась бы исходом NOT_IMPORTED на 30 суток. Срок доверия ответу задаётся у ПЛОЩАДКИ (getcourse_settings.reachability_ttl_days, по умолчанию 7 суток; 0 — спрашивать школу каждый раз); когда он истечёт, человек снова уедет в импорт и школу спросят заново. Чинится почтой, но включать её надо В ДВУХ местах: в allowlist ПЛОЩАДКИ (getcourse_settings.available_transports) и в каналах рассылки/расписания. Гейт сужает каналы по allowlist площадки, поэтому Email только в рассылке ничего не меняет — и это верно: канал вне allowlist школа не отправит никогда.',
193
- '⚠️⚠️ notHandoffCandidate — расписание ПЕРЕДАЧИ (у него включён handoff_from_school_platforms) берёт только людей, чья карточка живёт на ДРУГИХ площадках той же школы и чья серия там уже закончилась (последний шаг календарной цепочки источника позади). Остальные — свои люди площадки, люди без карточек и те, у кого серия ещё идёт, — уходят в это число. У обычного расписания оно всегда ноль.',
217
+ '⚠️⚠️ cardOnSiblingPlatform — человек живёт на СОСЕДНЕЙ площадке той же школы GetCourse, а на площадке расписания карточки у него нет. Импорт её сюда не перенесёт: он ищет человека по школе и обновляет ту карточку, что уже есть, — поэтому такие люди исключаются, а не уезжают в импорт (иначе каждую неделю они занимали бы слот дневного потолка и закрывались исходом NOT_IMPORTED). Расписанием не чинится: рассылать надо с той площадки, где человек живёт. Большое число у расписания на новой площадке — норма: люди школы живут на старой.',
218
+ '⚠️⚠️ noMessengerVerdict — школа УЖЕ отвечала, что привязанных мессенджеров у человека нет, и ответ ещё в силе. Карточки в базе у него нет, импорт её не заведёт, поэтому подача сожгла бы слот дневного потолка и слот импортов воркспейса и закрылась бы исходом NOT_IMPORTED на 7 суток. Срок доверия ответу задаётся у ПЛОЩАДКИ (getcourse_settings.reachability_ttl_days, по умолчанию 7 суток; 0 — спрашивать школу каждый раз). Срок считается СУТКАМИ площадки: ответ в силе, пока он новее полуночи дня запуска минус срок — поэтому «Пул сегодня» и любой запуск того же дня отвечают одинаково, как бы ни задержался отбор (с 17.09.2026); когда срок истечёт, человек снова уедет в импорт и школу спросят заново. Чинится почтой, но включать её надо В ДВУХ местах: в allowlist ПЛОЩАДКИ (getcourse_settings.available_transports) и в каналах рассылки/расписания. Гейт сужает каналы по allowlist площадки, поэтому Email только в рассылке ничего не меняет — и это верно: канал вне allowlist школа не отправит никогда.',
219
+ '⚠️⚠️ alreadyInDialog — с человеком идёт ЖИВОЙ разговор: он написал нам после нашей последней реплики (агента, оператора, дожима или процесса школы из импортированной истории). Сам такой разговор не закроется, пока ему не ответят. Это ЗЕРКАЛО отказа доставки SKIPPED_ALREADY_IN_DIALOG, поэтому место в дневном лимите он не занимает. С 16.09.2026 одинаково у сегмента «только нетронутым» и у продолжения. Расписанием не чинится.',
220
+ '⚠️⚠️ dialogQuiet — пауза тишины разговора, а не отсев навсегда: наша последняя реплика в чате моложе трёх суток (по 24 часа), человек после неё не писал. После трёх суток тишины разговор закрыт, и человек вернётся в пул сам — в том числе тот, кто когда-то нам отвечал (решение 16.09.2026). Доставка отказывает таким тем же SKIPPED_ALREADY_IN_DIALOG. «Пул сегодня» считает эту причину на момент запуска авторассылки.',
221
+ '⚠️⚠️ skipAfterSegment — человеку уже ушёл текст одного из сегментов списка skip_after_segment_ids расписания, и он не регистрировался после того касания (например, получил «пропустил первый эфир», и «не смогли прийти» по той же серии ему не уходит). Новая регистрация открывает его снова. У расписания без списка число всегда 0.',
222
+ '⚠️⚠️ resendPause — этим сегментом человеку уже писали, после нашей отправки он зарегистрировался снова, и расписание повторит ему сегмент (resend_segment_on_new_registration), но пауза resend_segment_pause_days ещё идёт. Вернётся в пул сам. При выключенном флаге такие люди стоят в alreadySentSegment.',
223
+ 'resendOpened — НЕ отсев: сколько из selectedCount пустил повтор сегмента по новой регистрации (этим сегментом им уже писали, они зарегистрировались снова, и пауза прошла). Это мера самого правила: при выключенном флаге всегда 0.',
224
+ '⚠️⚠️ guardActiveSeries / guardPaid / guardActiveApplication / guardUnverified — ЗЕРКАЛО предохранителя школы (идёт вебинарная серия; guardPaid — купил продукт после регистрации, по которой человек попал в сегмент; guardActiveApplication — после этой регистрации есть действующая заявка на продукт, с человеком работает менеджер; заявки и оплаты до этой регистрации не держат; оплата и заявка сразу — guardPaid; прежний ключ guardActiveDeal приходит только от старого бэкенда; не смог проверить — нет в данных школы или продукт оплаты не определён). Отбор спрашивает те же правила площадки, что и отправка, поэтому остановленные не занимают дневной лимит, и его добирают следующие по очереди. ⚠️ Числа считаются только до набора дневного лимита: кто после — в overCap, их предохранитель не судил. Серия проходит сама: человек вернётся в отбор, как только она закончится. Режимы правил — в настройках площадки (getcourse_settings.guard_*).',
225
+ '⚠️⚠️ guardUnchecked — НЕ отсев: предохранитель не проверил столько отобранных (cause=SOURCE_UNAVAILABLE — источник фактов не ответил, error — текст отказа; OUT_OF_TIME — проверка не уложилась в время запроса). Они стоят в selectedCount без проверки серии, заявки и оплаты; перед отправкой их проверит сама отправка, и часть отсеется. Скажи пользователю, что число «уйдёт» в этот раз завышено. На крупной площадке предпросмотр почти всегда отвечает OUT_OF_TIME (выкачка кандидатов съедает почти весь предел ответа) — полная картина с проверкой в besales_broadcast_pool_today. После отказа источника проверка минуту не повторяется: повторный вызов сразу вернёт SOURCE_UNAVAILABLE.',
226
+ '⚠️⚠️ notHandoffCandidate — у расписания с передачей (включён handoff_from_school_platforms) человек живёт на ДРУГОЙ площадке той же школы, но переносить его нельзя: его серия там ещё идёт (последний шаг календарной цепочки источника впереди или у контакта нет даты эфира) либо у него карточки сразу на нескольких других площадках. Свои люди площадки и люди без карточек сюда НЕ попадают: с 15.09.2026 расписание берёт их как обычно. У обычного расписания число всегда ноль.',
194
227
  '⚠️⚠️ handoffReturn — этого человека передача уже увозила С ЭТОЙ площадки, и в рамках текущего входа в сегмент он сюда не вернётся: иначе два расписания-продолжения возили бы его по кругу, а каждый переезд необратим. Новый вход спустя время запрету не подлежит. Ненулевое число означает, что у вас кольцо из двух расписаний передачи — это настройка, а не сбой данных.',
195
228
  '⚠️⚠️ handoffBlocked — карточку не перенесли: предохранитель школы (идёт серия, действующая заявка, оплата), контактом занят человек (бан, оператор, мьют), личность занята другим процессом либо на площадке-адресате уже есть карточка с этим внешним id (последнее — навсегда). Такие люди в подачу не идут и получают исход HANDOFF_BLOCKED в журнале подач.',
196
229
  'factsAsOf — момент, на который источник считает данные полными. Сильно устаревшее значение означает, что аналитика отстаёт и «не пришедшие» могут быть ложными.',
@@ -280,9 +313,12 @@ export const broadcastSchedulerTools = [
280
313
  }),
281
314
  enhanceResponse: (response) => withInstructions(response, [
282
315
  'periodBucket — локальная ДАТА площадки: один прогон на сутки, повтор в тот же день невозможен.',
283
- '⚠️ Статусы различают ПРИЧИНЫ, и чинятся они разным: DONE — пакет завершился; WAITING_RESOURCE — воркспейс был занят другим импортом, период НЕ сгорел и повторится следующим тиком; SKIPPED — правило отбора не дало кандидатов (смотри excludedBy); FAILED — упал запуск пакета; RUNNING — пакет ещё идёт.',
316
+ '⚠️ Статусы различают ПРИЧИНЫ, и чинятся они разным: DONE — пакет завершился; WAITING_RESOURCE — прогон отложен, период НЕ сгорел: воркспейс был занят другим импортом или пакетом (ручным или соседнего расписания), не ответил источник фактов («Источник фактов: …») или не прочитались старшие сегменты («Старшие сегменты не прочитаны: …») — причина в error; прогон повторится ближайшим тиком, когда расписание созреет (в тот же день и не раньше его времени, поэтому «Запустить сейчас» до времени расписания сам не повторится); SKIPPED — правило отбора не дало кандидатов (смотри excludedBy); FAILED — упал запуск пакета; RUNNING — пакет ещё идёт.',
284
317
  '⚠️ selectedCount — сколько ОТОБРАНО, launchedCount — сколько фактически доставлено. Расхождение нормально: часть отсеивают гейты отправки внутри пакета. Не называй selectedCount «отправлено».',
285
- 'attempts растёт на каждом WAITING_RESOURCE: большое число означает, что воркспейс постоянно занят и расписание стоит передвинуть по времени.',
318
+ '⚠️ snapshot.guardUnchecked у прогона — в этот день предохранитель не проверил часть отобранных (источник фактов не ответил или кончилось время), и отсев доставки по серии, заявке и оплате был выше обычного. Отсеянных ОТБОРОМ по предохранителю можно найти в аудите предохранителя: строки с details.stage=SCHEDULE_SELECTION и runId прогона.',
319
+ 'attempts растёт на каждом WAITING_RESOURCE: большое число при error «Воркспейс занят …» означает, что воркспейс постоянно занят и расписание стоит передвинуть по времени; при «Источник фактов: …» чинится источник, а не время.',
320
+ '⚠️ Все блоки «продукт × воронка» прогона уходят ОДНИМ пакетом, без потолка (прежде — не больше 10). excludedBy.droppedOverBlockLimit бывает только у старых прогонов — люди блоков сверх 10, которые ничего не получили.',
321
+ '⚠️ excludedBy.blockPlaceholdersUnresolved — люди блоков, снятых проверкой плана: в тексте блока не подставились переменные (обычно у агента нет перекрытия переменной). Остальные блоки ушли; эти люди вернутся к следующему запуску (исход SKIPPED_UNRESOLVED_VARS, пауза 6 ч), и, пока агента не поправят, блок снимается на каждом запуске, занимая место в потолке прогона (dailyCap); имена переменных — в причине их строк журнала подач. Чинится значениями переменных или перекрытиями у агента — скажи об этом пользователю.',
286
322
  ]),
287
323
  }),
288
324
  /**
@@ -362,13 +398,16 @@ export const broadcastSchedulerTools = [
362
398
  enhanceResponse: (response) => withInstructions(response, [
363
399
  '⚠️⚠️ activeRun не пуст — идёт расчёт этих настроек: вызови инструмент ЕЩЁ РАЗ через минуту с теми же параметрами. Повторный вызов — опрос, новый расчёт он не заказывает. run — последний ПОСЧИТАННЫЙ расчёт этих настроек (run.finishedAt — когда); run=null — ещё не считали.',
364
400
  '⚠️⚠️ Строка с расписанием (scheduleId не null) считается ТЕМ ЖЕ путём, что его тик: окно, воронки, продукты, каналы и тихий период — самого расписания; параметры вызова на неё не действуют. У выключенного расписания selectedCount значит «уйдёт, если включить». Строка без расписания считается по параметрам вызова (окно window_days, по умолчанию 3 суток; воронки, продукты, каналы, кулдаун), без рассылки и с потолком одного запуска — это верхняя граница того, что дало бы расписание.',
365
- 'Числа строки: poolSize — кандидаты после гейтов источника; selectedCount — отобрано на момент расчёта (не «уедет сегодня»); отсеяно = poolSize − selectedCount, причины — preview.excludedBy тем же реестром, что у besales_broadcast_schedule_preview; preview.unverifiable — «нечем проверить», отсев источника ДО пула, а не причина отбора.',
401
+ 'Числа строки: poolSize — кандидаты после гейтов источника; selectedCount — отобрано на момент запуска авторассылки строки (у строки без расписания — запуска дня) по тому, что известно сейчас, а не «уже уехало»; отсеяно = poolSize − selectedCount, причины — preview.excludedBy тем же реестром, что у besales_broadcast_schedule_preview; preview.unverifiable — «нечем проверить», отсев источника ДО пула, а не причина отбора.',
366
402
  '⚠️ status: COMPUTED — посчитана; FAILED — не смогли (причина в error, числа null, а не 0); SKIPPED — не считается по правилу, код в skip.reason: REPEAT_NEEDS_SCHEDULE (повторному касанию нужно окно не короче skip.minDays — считается только расписанием), WINDOW_NOT_SHARED (окно регистраций шире общей выборки — только расписанием), PLATFORM_SERVES_NO_CHANNELS (площадка не обслуживает ни одного канала), DEADLINE (расчёт упёрся в потолок skip.deadlineMinutes раньше, чем дошёл до строки).',
367
403
  '⚠️ preview.truncated=true — «не весь пул»: выборка источника не дошла до начала окна строки, самые давние регистрации не рассмотрены. Совет «сузить свежесть» здесь не годится: выборку обрезал общий расчёт площадки.',
368
404
  'failedRun — отказ (status=FAILED, причина в error) или замена новым заказом того же заказчика (CANCELLED), случившиеся ПОСЛЕ показанного расчёта. factsSource ≠ READY — источник фактов не настроен или выключен: расчёта не будет вовсе.',
369
- 'force=true — только после своей правки расписания, правила сегмента или запуска: без него свежий (до 5 минут) расчёт тех же настроек переиспользуется. Опрашивая идущий расчёт, force НЕ передавай — он заказал бы ещё один расчёт следом. local_day — утренний расчёт того дня (история «сегмент × день»), всегда с настройками по умолчанию.',
405
+ 'force=true — только после своей правки расписания, правила сегмента или запуска: без него свежий (до 5 минут) расчёт тех же настроек переиспользуется (запуск дня, отобравший людей или завершившийся после расчёта, переиспользование сбрасывает сам). Опрашивая идущий расчёт, force НЕ передавай — он заказал бы ещё один расчёт следом. local_day — утренний расчёт того дня (история «сегмент × день»), всегда с настройками по умолчанию.',
370
406
  '⚠️ Вызов с ДРУГИМИ параметрами снимает твой прежний неначатый заказ (расчёт идёт по одному на всю систему). Сравнивая площадки или окна, дождись готовности одной комбинации и только потом заказывай следующую — иначе ни одна не досчитается.',
371
407
  'Суммы по строкам не называй «людьми»: человек в двух сегментах посчитан дважды. Поимённых списков в ответе нет — людей смотрят в интерфейсе, под правом на контакты.',
408
+ '⚠️⚠️ «Сколько уйдёт сегодня» — это run.dayBreakdown, а не суммы poolSize/selectedCount: runDay (ГГГГ-ММ-ДД) — сегодня, пока хоть один запуск дня не завершился, потом — день ближайшего запуска; с local_day — сам этот день со всеми его запусками; scheduleIds — авторассылки этого дня; notComputedScheduleIds — авторассылки дня, которые не посчитались: числа дня без них неполные, так и скажи; ⚠️ план дня (registrations, people, excluded, selected, carriedOver, matured) — только по запускам, которые людей ещё не отбирали: ranScheduleIds — авторассылки дня, чей запуск уже прошёл: их итог — только facts.bySchedule, а у их сегментов run.rows[].dayBreakdown = null (списки после запуска планом не являются); с local_day непустой ranScheduleIds значит, что утренний расчёт досчитался уже после этих запусков, — так и скажи; allRan=true — все запуски дня уже прошли, плана нет: числа плана нулевые, не называй их, итог дня — facts; ranDuringComputation=true — запуск прошёл во время расчёта, числа неточны: без local_day повтори вызов с теми же параметрами (прошедший запуск сам сбрасывает переиспользование расчёта), с local_day утро не пересчитывается — оговори неточность; runTimes — время запусков дня по часам площадки (прошедший — когда прогон отобрал людей, предстоящий — по правилу); ⚠️⚠️ план считается на момент ЗАПУСКА, а не расчёта: кто созреет к запуску по эфиру, который уже закончился, — уже в числах; явка эфира, который ещё идёт, не известна, и таких людей в числах нет, пока эфир не кончится; matured — registrations плюс outsideSegments (null — не посчитано), outsideSegments — созреют к запуску в окне авторассылок дня, которые их рассматривают (их воронки и продукты, не раньше их свежести, по закончившимся эфирам), но не попали в пул ни одной; outsideSegmentsBy — они же по причинам (одна на регистрацию, сумма равна outsideSegments): paid — оплатил в этой воронке, application — живая заявка, attendanceNoMinutes — был на эфире, минут не записано, paidElsewhere — покупал в ДРУГОЙ воронке, seriesRunning — серия ещё идёт (их возьмут авторассылки по концу эфира, когда она закончится), other — прочее; у расчётов до 01.10.2026 paidElsewhere и seriesRunning нет — эти люди там в other; registrations — регистраций, вошедших в сегменты окнами своих авторассылок (от прошлого отбора до запуска; enteredFrom…enteredTo — общий охват этих окон); people — людей из них, КАЖДЫЙ ОДИН раз при любом числе сегментов; excluded — людей по причине отсева (noMessenger — нет мессенджера (в том числе прошлая подача этим расписанием закончилась «карточку не завели» или «каналами не достать»), inContact — на связи или писали недавно (этим сегментом уже писали, идёт разговор или трое суток тишины после нашей реплики, пауза повтора сегмента, пауза после любого нашего сообщения (поле расписания «Не писать, если писали за N дней»), подача этим расписанием ушла или ещё идёт), paid — купил продукт после регистрации, по которой попал в сегмент, withManager — с ним работает менеджер (действующая заявка на продукт после этой регистрации, операторский статус или передача диалога в отдел моложе трёх суток), blocked — бан, удалённая карточка или действующий мьют, activeSeries — идёт другая вебинарная серия, retryPause — прошлая попытка отправки этим расписанием не удалась, ждём паузу, overCap — не поместились в дневной потолок, higherPriority — уйдут в сегмент с большим приоритетом, otherPlatform — карточка на другой площадке школы, и эта авторассылка её не забирает (передача выключена, там ещё идёт серия эфиров или её дата неизвестна, карточек несколько, перенос не удался или уже увёз человека отсюда; у расчётов и прогонов до 22.09.2026 этой группы нет — эти люди в other), other — прочее (предохранитель не смог проверить заявки и оплаты, карточки на этой площадке нет, повтору не нашлось прошлого касания, непригодный номер человека); у расчётов до 16.09.2026 вместо новых приходят прежние группы alreadyWritten (уже писали), held (купил, менеджер, бан или мьют), pause (пауза); у запусков до 16.09.2026 (facts.scheduleRuns) к новым группам добавляются прежние held и pause, только ненулевые — называй их так и не складывай с новыми); people = selected + сумма excluded; carriedOver — уйдут этим запуском люди с прошлых дней. ⚠️⚠️ После запуска экран показывает «Уйдёт» числом «Взято запусками» (facts: sent + noMessenger + notSent + pending), когда все авторассылки плана (scheduleIds без ranScheduleIds и notComputedScheduleIds) уже отобрали людей и ни одна отобравшая не лежит вне плана; разница с selected + carriedOver показана как «добавились к запуску» / «отпали к запуску»: авторассылки отбирают людей по очереди, по приоритету, и за это время у части людей кончаются паузы. Называя «Уйдёт» дня, чьи запуски прошли, называй это число и разницу с планом. У каждого сегмента то же в run.rows[].dayBreakdown (без matured; null — сегмент не посчитан или запуск его авторассылки уже прошёл), и его runDay может быть другим днём — у авторассылки не на каждый день; у выключенной авторассылки selected — «уйдёт, если включить», в план дня она не входит.',
409
+ 'facts — исход запусков дня run.dayBreakdown.runDay по людям, по всем авторассылкам площадки: sent — отправлено, noMessenger — карточку не завели или ни один канал не доходит (школа ответила, что мессенджеров нет, каналы не подошли или сорвалась запись импорта), pending — подан в ещё идущий прогон, notSent — не ушло или доставка не подтвердилась (в том числе сорванная отправка); notSentByReason — те же notSent по причинам: один исход на человека, сумма равна notSent; ключ — исход отказа отправки (SKIPPED_BOT_SILENCED — бот выключен у контакта, SKIPPED_ALREADY_IN_DIALOG — разговор уже идёт, SKIPPED_UNRESOLVED_VARS — переменные текста без значения и соседи, как в outcomes у besales_broadcast_launches_list), без следа отправки — исход журнала подач (UNRESOLVED_AFTER_BATCH — причина не записана: прогоны до 16.09.2026, RELEASED_LAUNCH_FAILED — запуск сорвался); человеку называй причины словами, а не кодами; bySchedule — то же по авторассылкам; scheduleRuns — что увидел каждый запуск дня при отборе (без фильтров): poolSize — пул авторассылки на момент отбора (окно свежести, а не люди дня; null — ещё не отбирал), collapsed — свёрнутые дубли одного человека, excluded — отсев по тем же группам, taken — взято запуском (люди в журнале подач; с этого числа начинается отправка авторассылки в bySchedule, а люди, которых импорт не завёл, в нём есть), unrecorded — люди пула, которых не объясняют ни причины, ни взятые (должно быть 0; не ноль — счётчики прогона не сходятся с его журналом); суммы пулов разных авторассылок людьми дня не называй — человек в двух сегментах посчитан дважды; selectedScheduleIds — авторассылки, чей прогон дня уже отобрал людей или завершился (без фильтров): есть там, но нет в run.dayBreakdown.ranScheduleIds — запуск прошёл уже после расчёта, и без local_day план устарел: повтори вызов с теми же параметрами; ⚠️ под фильтром воронки или продукта план берёт человека с любой регистрацией в них, а факты — по регистрации, с которой ему написали: у людей с регистрациями в разных воронках план и факты расходятся; facts=null — прогонов авторассылок этого дня нет (запуска ещё не было). days — до 14 дней с утренним расчётом (в 8:00, до запусков дня и впереди заказов в очереди; опоздавший виден по непустому ranScheduleIds) и хотя бы одним запуском, а также дни с прошедшим запуском без утреннего расчёта, свежие первыми (для local_day); у такого дня run — null или без dayBreakdown, итог дня по людям — только facts, а отбор каждого запуска — facts.scheduleRuns. Человеку называй сегменты и авторассылки, а не «строки».',
410
+ '⚠️⚠️ «Сколько ушло СЕГОДНЯ» — это todayFacts, а не facts: today — сегодняшний день площадки (ГГГГ-ММ-ДД, по её часам), todayFacts — отправка сегодня в том же виде, что facts, какой бы день ни показывал расклад. После всех запусков дня run.dayBreakdown.runDay и facts уже про ЗАВТРА (facts=null — завтра запусков ещё не было), а сегодняшние итоги остаются в todayFacts. Отвечая, разделяй «Сегодня» (todayFacts) и план ближайшего дня (run.dayBreakdown). todayFacts=null — сегодня запусков не было; с local_day today и todayFacts всегда null — у дня истории итог только facts.',
372
411
  'Сводка выкачки у run: fetchedRows (строк источника), fetchTruncated (выборка упёрлась в бюджет — у строк она отзывается preview.truncated), registeredFrom/registeredTo (окно регистраций), trigger (MORNING — утренний расчёт истории, ON_DEMAND — заказанный), settings (настройки строк без расписания). Называй их, объясняя расхождение чисел между днями.',
373
412
  ]),
374
413
  }),
@@ -384,6 +423,12 @@ export const broadcastSchedulerTools = [
384
423
  facets: z
385
424
  .object({
386
425
  attended: z.enum(['YES', 'NO', 'ANY']).optional(),
426
+ /**
427
+ * Был на ПЕРВОМ эфире серии. `NO` — пропустил первый эфир; вопрос отвечается, пока
428
+ * серия ещё идёт, поэтому с `attended` они не взаимозаменяемы: та спрашивает про всю
429
+ * серию и до её конца равна «нечем проверить».
430
+ */
431
+ attendedFirstSession: z.enum(['YES', 'NO', 'ANY']).optional(),
387
432
  activeSecondsMin: z.number().int().min(0).optional(),
388
433
  activeSecondsMax: z.number().int().min(0).optional(),
389
434
  webinarDayMin: z.number().int().min(0).optional(),
@@ -413,7 +458,8 @@ export const broadcastSchedulerTools = [
413
458
  * ⚠️⚠️ Молчание значит `true` — это сегодняшнее поведение платформы. Выключение
414
459
  * осознанное и снимает ровно одну защиту: человеку, уже получившему от нас холодное
415
460
  * приветствие, уйдёт ВТОРОЕ первое сообщение. Остальные гейты (ответ, оператор,
416
- * тихий период, «этим сегментом уже слали») продолжают работать.
461
+ * тихий период, «этим сегментом уже слали») продолжают работать. Единственный фасет,
462
+ * который меняется и у замороженного сегмента (решение владельца 15.09.2026).
417
463
  */
418
464
  untouchedOnly: z.boolean().optional(),
419
465
  // ⚠️⚠️ ОБЯЗАТЕЛЬНЫ на сервере (`SEGMENT_FACETS_REQUIRED_GUARDS`): необязательное
@@ -440,7 +486,8 @@ export const broadcastSchedulerTools = [
440
486
  }),
441
487
  }),
442
488
  enhanceResponse: (response) => withInstructions(response, [
443
- '⚠️⚠️ 409 означает, что сегментом УЖЕ отправляли и правило заморожено. Это не ошибка доступа: строки отчётов уже несут это имя, и правка правила задним числом сделала бы разрез несопоставимым сам с собой. Заведи НОВЫЙ сегмент.',
489
+ '⚠️⚠️ 409 означает, что сегментом УЖЕ отправляли и правило заморожено. Это не ошибка доступа: строки отчётов уже несут это имя, и правка правила задним числом сделала бы разрез несопоставимым сам с собой. Заведи НОВЫЙ сегмент. Исключения — priority и facets.untouchedOnly: их меняют и у замороженного сегмента, передав остальное правило (фасеты, freshness_anchor, wait_after_series_end_hours) ТЕМ ЖЕ, что у сегмента сейчас; с даты переключения отчёт сегмента смешивает первые и повторные сообщения — скажи это человеку.',
490
+ 'attendedFirstSession=NO — «пропустил ПЕРВЫЙ эфир», и это единственный способ написать человеку, пока его серия идёт. Требует: freshness_anchor=FIRST_SESSION_END_PLUS_WAIT (иначе вход в сегмент считался бы от конца серии — на 4–5 суток позже) и guard_active_series=OFF у РАСПИСАНИЯ (иначе предохранитель площадки остановит отправку: серия у человека идёт по определению). Источник фактов обязан отдавать явку по первому эфиру; пока не отдаёт, строки приходят непроверяемыми и никому ничего не уйдёт.',
444
491
  'attended=NO проходит только достоверный «не пришёл». Человек, про которого данных нет (серия ещё идёт, назначения нет), в сегмент НЕ попадает — и это защита: отсутствие данных о явке не равно отсутствию человека на эфире.',
445
492
  'Секунды, а не минуты: «от 120 минут» — это activeSecondsMin=7200. Контакт без известной длительности порог не проходит.',
446
493
  'wait_after_series_end_hours — сколько ждать после эфира, прежде чем считать отсутствие явки доказанным. Дефолт 1 час: касание свежее, но явка к этому моменту досчитана у меньшинства (6 ч → 56 %, 24 ч → 74 %, 48 ч → 81 %), и недосчитанный контакт в отбор не попадает. Поэтому при коротком ожидании ставьте freshness_days от 3: при 1 человека смотрят ровно один раз.',
@@ -1 +1 @@
1
- {"version":3,"file":"broadcast-scheduler.js","sourceRoot":"","sources":["../../../src/tools/definitions/broadcast-scheduler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"broadcast-scheduler.js","sourceRoot":"","sources":["../../../src/tools/definitions/broadcast-scheduler.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,7 @@ export declare const crmPlatformTools: (import("./shared.js").ToolDefinition<{
15
15
  platform_id?: string | undefined;
16
16
  is_constant?: boolean | undefined;
17
17
  constant_value?: string | undefined;
18
+ repeat_constant_value?: string | undefined;
18
19
  }> | import("./shared.js").ToolDefinition<{
19
20
  variable_id: string;
20
21
  scope: "WORKSPACE" | "CHANNEL";
@@ -29,6 +30,7 @@ export declare const crmPlatformTools: (import("./shared.js").ToolDefinition<{
29
30
  type?: "TEXT" | "NUMBER" | "FLOAT" | "BOOLEAN" | undefined;
30
31
  value?: string | null | undefined;
31
32
  constant_value?: string | null | undefined;
33
+ repeat_constant_value?: string | null | undefined;
32
34
  }> | import("./shared.js").ToolDefinition<{
33
35
  variable_id: string;
34
36
  scope: "WORKSPACE" | "CHANNEL";
@@ -1,6 +1,8 @@
1
1
  import { z } from 'zod';
2
2
  import { assertCompleteList } from '../incomplete-list.js';
3
3
  import { MAX_FILE_UPLOAD_BYTES, VARIABLES_MAX_PAGE_SIZE, apiKeyPlatformTypeSchema, buildFileListQuery, buildVariableListQuery, buildVariableScopeQuery, compactObject, crmFieldMappingItemSchema, defineTool, mcpFileSourceSchema, oauthPlatformTypeSchema, optionalAnyObjectSchema, provisionableCrmTypeSchema, storedFileTypeSchema, uuidSchema, withInstructions, } from './shared.js';
4
+ /** Подсказка про повторное значение константы — одна для создания и правки. */
5
+ const REPEAT_CONSTANT_VALUE_INSTRUCTION = 'repeat_constant_value подставляется вместо constant_value человеку, которому мы уже писали, — только в холодных рассылках (например, {intro}: «это снова Светлана.» вместо полного представления). Только константы CHANNEL; фигурные скобки запрещены; пустая строка или null очищает — тогда повтору уходит constant_value.';
4
6
  export const crmPlatformTools = [
5
7
  // ============================================================
6
8
  // v1.5 Increment 4a — Unified Variables API (5 tools, v2-shaped scope discriminator)
@@ -81,6 +83,7 @@ export const crmPlatformTools = [
81
83
  platform_id: uuidSchema.optional(),
82
84
  is_constant: z.boolean().optional(),
83
85
  constant_value: z.string().optional(),
86
+ repeat_constant_value: z.string().optional(),
84
87
  })
85
88
  .strict()
86
89
  .superRefine((input, ctx) => {
@@ -92,10 +95,12 @@ export const crmPlatformTools = [
92
95
  path: ['platform_id'],
93
96
  });
94
97
  }
95
- if (input.is_constant !== undefined || input.constant_value !== undefined) {
98
+ if (input.is_constant !== undefined ||
99
+ input.constant_value !== undefined ||
100
+ input.repeat_constant_value !== undefined) {
96
101
  ctx.addIssue({
97
102
  code: z.ZodIssueCode.custom,
98
- message: 'is_constant and constant_value are forbidden when scope=WORKSPACE',
103
+ message: 'is_constant, constant_value and repeat_constant_value are forbidden when scope=WORKSPACE',
99
104
  path: ['is_constant'],
100
105
  });
101
106
  }
@@ -123,6 +128,13 @@ export const crmPlatformTools = [
123
128
  path: ['constant_value'],
124
129
  });
125
130
  }
131
+ if (input.is_constant !== true && input.repeat_constant_value !== undefined) {
132
+ ctx.addIssue({
133
+ code: z.ZodIssueCode.custom,
134
+ message: 'repeat_constant_value is allowed only when scope=CHANNEL and is_constant=true',
135
+ path: ['repeat_constant_value'],
136
+ });
137
+ }
126
138
  }
127
139
  }),
128
140
  createRequest: (input) => ({
@@ -137,11 +149,13 @@ export const crmPlatformTools = [
137
149
  platformId: input.platform_id,
138
150
  isConstant: input.is_constant,
139
151
  constantValue: input.constant_value,
152
+ repeatConstantValue: input.repeat_constant_value,
140
153
  }),
141
154
  }),
142
155
  enhanceResponse: (response) => withInstructions(response, [
143
156
  'name, scope, is_constant — immutable post-create (используй delete + create для смены).',
144
157
  'WORKSPACE variables референсятся в шаблонах как {{{name}}} (triple braces), CHANNEL constants — {{name}} (double).',
158
+ REPEAT_CONSTANT_VALUE_INSTRUCTION,
145
159
  ]),
146
160
  }),
147
161
  defineTool({
@@ -190,6 +204,7 @@ export const crmPlatformTools = [
190
204
  value: z.string().nullable().optional(),
191
205
  // CHANNEL-only (nullable для clear)
192
206
  constant_value: z.string().nullable().optional(),
207
+ repeat_constant_value: z.string().nullable().optional(),
193
208
  })
194
209
  .strict()
195
210
  .superRefine((input, ctx) => {
@@ -207,6 +222,13 @@ export const crmPlatformTools = [
207
222
  path: ['constant_value'],
208
223
  });
209
224
  }
225
+ if (input.scope === 'WORKSPACE' && input.repeat_constant_value !== undefined) {
226
+ ctx.addIssue({
227
+ code: z.ZodIssueCode.custom,
228
+ message: 'repeat_constant_value is forbidden when scope=WORKSPACE',
229
+ path: ['repeat_constant_value'],
230
+ });
231
+ }
210
232
  if (input.scope === 'CHANNEL' && input.value !== undefined) {
211
233
  ctx.addIssue({
212
234
  code: z.ZodIssueCode.custom,
@@ -225,8 +247,10 @@ export const crmPlatformTools = [
225
247
  type: input.type,
226
248
  value: input.value,
227
249
  constantValue: input.constant_value,
250
+ repeatConstantValue: input.repeat_constant_value,
228
251
  }),
229
252
  }),
253
+ enhanceResponse: (response) => withInstructions(response, [REPEAT_CONSTANT_VALUE_INSTRUCTION]),
230
254
  }),
231
255
  defineTool({
232
256
  name: 'besales_variable_delete',