@besales/mcp 0.31.0 → 0.32.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.
- package/README.md +5 -2
- package/dist/instructions/server-instructions.d.ts +1 -1
- package/dist/instructions/server-instructions.js +8 -0
- package/dist/instructions/server-instructions.js.map +1 -1
- package/dist/resources/docs/crm-integration.md +2 -2
- package/dist/schemas/mcp-tools.json +735 -5
- package/dist/tools/definitions/follow-up.d.ts +84 -0
- package/dist/tools/definitions/follow-up.js +161 -0
- package/dist/tools/definitions/follow-up.js.map +1 -0
- package/dist/tools/definitions/knowledge.d.ts +2 -2
- package/dist/tools/definitions/platform-setup.d.ts +49 -0
- package/dist/tools/definitions/platform-setup.js +183 -1
- package/dist/tools/definitions/platform-setup.js.map +1 -1
- package/dist/tools/definitions/scheduled-tasks.d.ts +24 -0
- package/dist/tools/definitions/scheduled-tasks.js +124 -0
- package/dist/tools/definitions/scheduled-tasks.js.map +1 -0
- package/dist/tools/definitions/shared.d.ts +4 -0
- package/dist/tools/definitions/shared.js +14 -0
- package/dist/tools/definitions/shared.js.map +1 -1
- package/dist/tools/definitions.d.ts +81 -2
- package/dist/tools/definitions.js +4 -0
- package/dist/tools/definitions.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const reactivationConfigSchema: z.ZodObject<{
|
|
3
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
4
|
+
filterMode: z.ZodOptional<z.ZodEnum<{
|
|
5
|
+
status: "status";
|
|
6
|
+
variable: "variable";
|
|
7
|
+
eventType: "eventType";
|
|
8
|
+
}>>;
|
|
9
|
+
sequenceConditions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
10
|
+
variable: z.ZodString;
|
|
11
|
+
op: z.ZodEnum<{
|
|
12
|
+
in: "in";
|
|
13
|
+
eq: "eq";
|
|
14
|
+
neq: "neq";
|
|
15
|
+
}>;
|
|
16
|
+
value: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
|
|
17
|
+
}, z.core.$loose>>>;
|
|
18
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
19
|
+
stepType: z.ZodOptional<z.ZodEnum<{
|
|
20
|
+
message: "message";
|
|
21
|
+
webhook: "webhook";
|
|
22
|
+
}>>;
|
|
23
|
+
scheduleMode: z.ZodOptional<z.ZodEnum<{
|
|
24
|
+
offset: "offset";
|
|
25
|
+
clock: "clock";
|
|
26
|
+
}>>;
|
|
27
|
+
anchorMode: z.ZodOptional<z.ZodEnum<{
|
|
28
|
+
variable: "variable";
|
|
29
|
+
last_inbound: "last_inbound";
|
|
30
|
+
}>>;
|
|
31
|
+
anchorVariable: z.ZodOptional<z.ZodString>;
|
|
32
|
+
atTime: z.ZodOptional<z.ZodString>;
|
|
33
|
+
dayOffset: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
validityMinutes: z.ZodOptional<z.ZodNumber>;
|
|
35
|
+
slotGroup: z.ZodOptional<z.ZodString>;
|
|
36
|
+
conditions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
37
|
+
variable: z.ZodString;
|
|
38
|
+
op: z.ZodEnum<{
|
|
39
|
+
in: "in";
|
|
40
|
+
eq: "eq";
|
|
41
|
+
neq: "neq";
|
|
42
|
+
}>;
|
|
43
|
+
value: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
|
|
44
|
+
}, z.core.$loose>>>;
|
|
45
|
+
delayHours: z.ZodOptional<z.ZodNumber>;
|
|
46
|
+
delayMinutes: z.ZodOptional<z.ZodNumber>;
|
|
47
|
+
messageConfig: z.ZodOptional<z.ZodObject<{}, z.core.$loose>>;
|
|
48
|
+
}, z.core.$loose>>;
|
|
49
|
+
}, z.core.$loose>;
|
|
50
|
+
/**
|
|
51
|
+
* Применяет типизированную схему к `config` ТОЛЬКО для реактивационных цепочек.
|
|
52
|
+
*
|
|
53
|
+
* Через `z.union([reactivationConfigSchema, anyObjectSchema])` это делать нельзя: второй вариант
|
|
54
|
+
* принимает любой объект, поэтому union проходит всегда и ограничения (`steps.min(1)`,
|
|
55
|
+
* `filterMode` enum) не срабатывают ни разу — типизация выглядит рабочей, но её нет.
|
|
56
|
+
*
|
|
57
|
+
* @param input - Разобранный ввод тула
|
|
58
|
+
* @param ctx - Контекст zod для добавления ошибок
|
|
59
|
+
*/
|
|
60
|
+
export declare const refineFollowUpConfig: (input: {
|
|
61
|
+
type?: unknown;
|
|
62
|
+
config?: unknown;
|
|
63
|
+
}, ctx: z.RefinementCtx) => void;
|
|
64
|
+
export declare const followUpSequenceListSchema: z.ZodObject<{
|
|
65
|
+
platform_id: z.ZodString;
|
|
66
|
+
sequence_id: z.ZodOptional<z.ZodString>;
|
|
67
|
+
include_config: z.ZodOptional<z.ZodBoolean>;
|
|
68
|
+
}, z.core.$strip>;
|
|
69
|
+
export declare const followUpStepStatsSchema: z.ZodObject<{
|
|
70
|
+
platform_id: z.ZodString;
|
|
71
|
+
sequence_id: z.ZodString;
|
|
72
|
+
from: z.ZodOptional<z.ZodString>;
|
|
73
|
+
to: z.ZodOptional<z.ZodString>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
export declare const followUpTools: (import("./shared.js").ToolDefinition<{
|
|
76
|
+
platform_id: string;
|
|
77
|
+
sequence_id?: string | undefined;
|
|
78
|
+
include_config?: boolean | undefined;
|
|
79
|
+
}> | import("./shared.js").ToolDefinition<{
|
|
80
|
+
platform_id: string;
|
|
81
|
+
sequence_id: string;
|
|
82
|
+
from?: string | undefined;
|
|
83
|
+
to?: string | undefined;
|
|
84
|
+
}>)[];
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { anyObjectSchema, buildListQuery, defineTool, uuidSchema, withInstructions, } from './shared.js';
|
|
3
|
+
/**
|
|
4
|
+
* Схема конфига реактивационной цепочки.
|
|
5
|
+
*
|
|
6
|
+
* ⚠️ Ключи ВНУТРИ `config` — camelCase, в отличие от snake_case параметров тулов: `config`
|
|
7
|
+
* уходит в тело запроса БЕЗ преобразования, а рантайм читает `anchorMode`/`anchorVariable`/
|
|
8
|
+
* `slotGroup`. Назвать их в snake_case значило бы сохранить конфиг, который рантайм не
|
|
9
|
+
* прочитает: календарный шаг молча стал бы обычным offset-шагом.
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ `.passthrough()` на каждом уровне обязателен по двум причинам: legacy-конфиги несут поля
|
|
12
|
+
* вне этой схемы (`finalAction`, `maxCycleCount`, `webhookConfig`, …), и сама схема исполняется
|
|
13
|
+
* на машине оператора — она обновляется независимо от бэкенда и не должна отвергать конфиг,
|
|
14
|
+
* который бэкенд принял бы.
|
|
15
|
+
*/
|
|
16
|
+
const variableConditionSchema = z
|
|
17
|
+
.object({
|
|
18
|
+
variable: z.string().describe('Имя per-contact переменной'),
|
|
19
|
+
op: z.enum(['eq', 'neq', 'in']),
|
|
20
|
+
value: z
|
|
21
|
+
.union([z.string(), z.array(z.string())])
|
|
22
|
+
.describe("Строка для eq/neq, непустой массив непустых строк для 'in'"),
|
|
23
|
+
})
|
|
24
|
+
.passthrough();
|
|
25
|
+
const reactivationStepSchema = z
|
|
26
|
+
.object({
|
|
27
|
+
stepType: z.enum(['message', 'webhook']).optional(),
|
|
28
|
+
scheduleMode: z
|
|
29
|
+
.enum(['offset', 'clock'])
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("'clock' — время суток + сдвиг дней вместо задержки от последней активности"),
|
|
32
|
+
anchorMode: z
|
|
33
|
+
.enum(['last_inbound', 'variable'])
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("'variable' — расписание считается от даты из переменной контакта (календарная цепочка)"),
|
|
36
|
+
anchorVariable: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe('Имя переменной с якорной датой. Обязательно при anchorMode=variable; переменная должна ' +
|
|
40
|
+
'существовать у платформы и НЕ быть константой'),
|
|
41
|
+
atTime: z.string().optional().describe('Время суток "HH:MM" для scheduleMode=clock'),
|
|
42
|
+
dayOffset: z
|
|
43
|
+
.number()
|
|
44
|
+
.int()
|
|
45
|
+
.min(0)
|
|
46
|
+
.max(30)
|
|
47
|
+
.optional()
|
|
48
|
+
.describe('Сдвиг в днях от якоря для scheduleMode=clock'),
|
|
49
|
+
validityMinutes: z
|
|
50
|
+
.number()
|
|
51
|
+
.optional()
|
|
52
|
+
.describe('Окно валидности слота. Меньше 10 минут крон почти всегда промахнётся'),
|
|
53
|
+
slotGroup: z
|
|
54
|
+
.string()
|
|
55
|
+
.optional()
|
|
56
|
+
.describe('Метка взаимоисключающих вариантов одного момента (first-match-wins). Варианты ОБЯЗАНЫ ' +
|
|
57
|
+
'идти в steps подряд: разнесённые по цепочке перестают быть взаимоисключающими'),
|
|
58
|
+
conditions: z
|
|
59
|
+
.array(variableConditionSchema)
|
|
60
|
+
.max(3)
|
|
61
|
+
.optional()
|
|
62
|
+
.describe('Условия на переменные контакта; не прошли — шаг пропускается'),
|
|
63
|
+
delayHours: z.number().optional(),
|
|
64
|
+
delayMinutes: z.number().optional(),
|
|
65
|
+
messageConfig: anyObjectSchema.optional(),
|
|
66
|
+
})
|
|
67
|
+
.passthrough();
|
|
68
|
+
export const reactivationConfigSchema = z
|
|
69
|
+
.object({
|
|
70
|
+
enabled: z.boolean().optional(),
|
|
71
|
+
filterMode: z
|
|
72
|
+
.enum(['status', 'eventType', 'variable'])
|
|
73
|
+
.optional()
|
|
74
|
+
.describe('Режим отбора контактов. Неизвестное значение НЕ включает ни один фильтр — цепочка уйдёт ' +
|
|
75
|
+
'всем контактам канала, поэтому бэкенд отвергает такой конфиг'),
|
|
76
|
+
sequenceConditions: z
|
|
77
|
+
.array(variableConditionSchema)
|
|
78
|
+
.optional()
|
|
79
|
+
.describe("Обязателен и непуст при filterMode='variable'"),
|
|
80
|
+
steps: z.array(reactivationStepSchema).min(1),
|
|
81
|
+
})
|
|
82
|
+
.passthrough();
|
|
83
|
+
/**
|
|
84
|
+
* Применяет типизированную схему к `config` ТОЛЬКО для реактивационных цепочек.
|
|
85
|
+
*
|
|
86
|
+
* Через `z.union([reactivationConfigSchema, anyObjectSchema])` это делать нельзя: второй вариант
|
|
87
|
+
* принимает любой объект, поэтому union проходит всегда и ограничения (`steps.min(1)`,
|
|
88
|
+
* `filterMode` enum) не срабатывают ни разу — типизация выглядит рабочей, но её нет.
|
|
89
|
+
*
|
|
90
|
+
* @param input - Разобранный ввод тула
|
|
91
|
+
* @param ctx - Контекст zod для добавления ошибок
|
|
92
|
+
*/
|
|
93
|
+
export const refineFollowUpConfig = (input, ctx) => {
|
|
94
|
+
if (input.type !== 'INACTIVE_USER_REACTIVATION') {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const parsed = reactivationConfigSchema.safeParse(input.config);
|
|
98
|
+
if (parsed.success) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
for (const issue of parsed.error.issues) {
|
|
102
|
+
ctx.addIssue({
|
|
103
|
+
code: z.ZodIssueCode.custom,
|
|
104
|
+
path: ['config', ...issue.path],
|
|
105
|
+
message: issue.message,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
export const followUpSequenceListSchema = z.object({
|
|
110
|
+
platform_id: uuidSchema,
|
|
111
|
+
sequence_id: uuidSchema
|
|
112
|
+
.optional()
|
|
113
|
+
.describe('Вернуть одну цепочку вместе с полным конфигом'),
|
|
114
|
+
include_config: z
|
|
115
|
+
.boolean()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe('Отдать конфиги всех цепочек. По умолчанию не отдаются — они объёмные'),
|
|
118
|
+
});
|
|
119
|
+
export const followUpStepStatsSchema = z.object({
|
|
120
|
+
platform_id: uuidSchema,
|
|
121
|
+
sequence_id: uuidSchema,
|
|
122
|
+
from: z.string().optional().describe('Начало окна, ISO-дата. По умолчанию 30 дней назад'),
|
|
123
|
+
to: z.string().optional().describe('Конец окна, ISO-дата. По умолчанию сейчас'),
|
|
124
|
+
});
|
|
125
|
+
export const followUpTools = [
|
|
126
|
+
defineTool({
|
|
127
|
+
name: 'besales_followup_sequence_list',
|
|
128
|
+
requiredFields: ['platform_id'],
|
|
129
|
+
schema: followUpSequenceListSchema,
|
|
130
|
+
// Параметры клеим в путь: транспорт (`ApiToolRequest`) знает только method/path/body, и
|
|
131
|
+
// отдельное поле `query` было бы молча выброшено — тул вернул бы 200 без учёта фильтров.
|
|
132
|
+
createRequest: (input) => ({
|
|
133
|
+
method: 'GET',
|
|
134
|
+
path: `/platforms/${input.platform_id}/follow-up/sequences${buildListQuery({
|
|
135
|
+
sequence_id: input.sequence_id,
|
|
136
|
+
include_config: input.include_config,
|
|
137
|
+
})}`,
|
|
138
|
+
}),
|
|
139
|
+
enhanceResponse: (response) => withInstructions(response, [
|
|
140
|
+
'besales_followup_sequence_upsert заменяет config ЦЕЛИКОМ: прочитай конфиг здесь (sequence_id) и пришли ПОЛНЫЙ желаемый набор шагов, а не дельту.',
|
|
141
|
+
'Без sequence_id и include_config конфиги не отдаются — так список остаётся дешёвым по контексту.',
|
|
142
|
+
]),
|
|
143
|
+
}),
|
|
144
|
+
defineTool({
|
|
145
|
+
name: 'besales_followup_step_stats',
|
|
146
|
+
requiredFields: ['platform_id', 'sequence_id'],
|
|
147
|
+
schema: followUpStepStatsSchema,
|
|
148
|
+
createRequest: (input) => ({
|
|
149
|
+
method: 'GET',
|
|
150
|
+
path: `/platforms/${input.platform_id}/follow-up/sequences/${input.sequence_id}/step-stats${buildListQuery({ from: input.from, to: input.to })}`,
|
|
151
|
+
}),
|
|
152
|
+
enhanceResponse: (response) => withInstructions(response, [
|
|
153
|
+
'wasSent=false НЕ означает «отправка не удалась»: SEND_FAILED пишется только если до fence не дошло (мьют, стадия CRM, тихий канал).',
|
|
154
|
+
'SHADOWED — вариант слота, который не оценивался, потому что слот уже закрыт отправкой другого варианта. Это не ошибка.',
|
|
155
|
+
'SENT_UNVERIFIED — отправка зависла после fence: исходом владеет recovery, повтор запрещён.',
|
|
156
|
+
'waitingUpperBound — ВЕРХНЯЯ оценка ожидающих: прогресс создаётся всем включённым цепочкам платформы без проверки sequenceConditions.',
|
|
157
|
+
'Окно по умолчанию — 30 дней; для более раннего периода передай from/to.',
|
|
158
|
+
]),
|
|
159
|
+
}),
|
|
160
|
+
];
|
|
161
|
+
//# sourceMappingURL=follow-up.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"follow-up.js","sourceRoot":"","sources":["../../../src/tools/definitions/follow-up.ts"],"names":[],"mappings":"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"}
|
|
@@ -65,7 +65,7 @@ export declare const knowledgeTools: (import("./shared.js").ToolDefinition<{
|
|
|
65
65
|
}> | import("./shared.js").ToolDefinition<{
|
|
66
66
|
knowledge_space_id: string;
|
|
67
67
|
workspace_id?: string | undefined;
|
|
68
|
-
status?: "LOADED" | "SPLIT" | "EMBEDDINGS_GENERATED" | "VECTOR_DB_UPLOADED" | "COMPLETED" | "
|
|
68
|
+
status?: "FAILED" | "LOADED" | "SPLIT" | "EMBEDDINGS_GENERATED" | "VECTOR_DB_UPLOADED" | "COMPLETED" | "TEXT_EXTRACTED" | "CHUNKS_SAVED" | undefined;
|
|
69
69
|
page?: number | undefined;
|
|
70
70
|
limit?: number | undefined;
|
|
71
71
|
}> | import("./shared.js").ToolDefinition<{
|
|
@@ -149,7 +149,7 @@ export declare const knowledgeTools: (import("./shared.js").ToolDefinition<{
|
|
|
149
149
|
}> | import("./shared.js").ToolDefinition<{
|
|
150
150
|
knowledge_space_id: string;
|
|
151
151
|
workspace_id?: string | undefined;
|
|
152
|
-
status?: "
|
|
152
|
+
status?: "PENDING" | "FAILED" | "COMPLETED" | "CRAWLING" | "PROCESSING" | undefined;
|
|
153
153
|
page?: number | undefined;
|
|
154
154
|
limit?: number | undefined;
|
|
155
155
|
}> | import("./shared.js").ToolDefinition<{
|
|
@@ -44,6 +44,51 @@ export declare const platformSetupTools: (import("./shared.js").ToolDefinition<{
|
|
|
44
44
|
}> | import("./shared.js").ToolDefinition<{
|
|
45
45
|
job_id: string;
|
|
46
46
|
workspace_id?: string | undefined;
|
|
47
|
+
}> | import("./shared.js").ToolDefinition<{
|
|
48
|
+
platform_id: string;
|
|
49
|
+
crm_id: string;
|
|
50
|
+
channels: string[];
|
|
51
|
+
contacts: {
|
|
52
|
+
contact_id: string;
|
|
53
|
+
deal_id?: string | undefined;
|
|
54
|
+
transport?: string | undefined;
|
|
55
|
+
dialog_id?: string | undefined;
|
|
56
|
+
lead_last_active_at?: string | undefined;
|
|
57
|
+
segment_entered_at?: string | undefined;
|
|
58
|
+
}[];
|
|
59
|
+
workspace_id?: string | undefined;
|
|
60
|
+
launch_type?: "status" | undefined;
|
|
61
|
+
funnel?: string | undefined;
|
|
62
|
+
segment?: string | undefined;
|
|
63
|
+
cohort_label?: string | undefined;
|
|
64
|
+
message_variant?: string | undefined;
|
|
65
|
+
found_count?: number | undefined;
|
|
66
|
+
product_code?: string | undefined;
|
|
67
|
+
product_name?: string | undefined;
|
|
68
|
+
deal_fields?: Record<string, string | number | boolean | null> | undefined;
|
|
69
|
+
confirm?: boolean | undefined;
|
|
70
|
+
check_messenger_presence?: boolean | undefined;
|
|
71
|
+
dedup_window_days?: number | undefined;
|
|
72
|
+
dedup_scope?: "any" | "same_funnel" | undefined;
|
|
73
|
+
preflight?: {
|
|
74
|
+
enabled?: boolean | undefined;
|
|
75
|
+
product_title?: string | undefined;
|
|
76
|
+
product_match_key?: string | undefined;
|
|
77
|
+
offer_id?: number | undefined;
|
|
78
|
+
other_product_active_deal_mode?: "warn" | "block" | "ignore" | undefined;
|
|
79
|
+
} | undefined;
|
|
80
|
+
chunk_size?: number | undefined;
|
|
81
|
+
explicit_confirmation?: true | undefined;
|
|
82
|
+
confirmation_reason?: string | undefined;
|
|
83
|
+
}> | import("./shared.js").ToolDefinition<{
|
|
84
|
+
run_id: string;
|
|
85
|
+
workspace_id?: string | undefined;
|
|
86
|
+
}> | import("./shared.js").ToolDefinition<{
|
|
87
|
+
run_id: string;
|
|
88
|
+
workspace_id?: string | undefined;
|
|
89
|
+
status?: "PENDING" | "CLAIMED" | "SENT" | "SKIPPED" | "FAILED" | "UNKNOWN" | undefined;
|
|
90
|
+
cursor?: string | undefined;
|
|
91
|
+
limit?: number | undefined;
|
|
47
92
|
}> | import("./shared.js").ToolDefinition<{
|
|
48
93
|
platform_id: string;
|
|
49
94
|
workspace_id?: string | undefined;
|
|
@@ -472,6 +517,10 @@ export declare const platformSetupTools: (import("./shared.js").ToolDefinition<{
|
|
|
472
517
|
manual_mute_field_id?: string | null | undefined;
|
|
473
518
|
manual_mute_value?: string | null | undefined;
|
|
474
519
|
manual_mute_active_value?: string | null | undefined;
|
|
520
|
+
create_missing_deal_enabled?: boolean | undefined;
|
|
521
|
+
create_missing_deal_offer_id?: number | null | undefined;
|
|
522
|
+
create_missing_deal_funnel_id?: number | null | undefined;
|
|
523
|
+
create_missing_deal_stage_id?: number | null | undefined;
|
|
475
524
|
} | undefined;
|
|
476
525
|
}> | import("./shared.js").ToolDefinition<{
|
|
477
526
|
audit_log_id: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { refineFollowUpConfig } from './follow-up.js';
|
|
2
3
|
import { agentOutputConfigSchema, agentRuntimeConfigSchema, agentScopeSchema, agentToolPatchSchema, anyObjectSchema, behaviorErrorHandlingSchema, behaviorGreetingSchema, behaviorMediaHandlingSchema, behaviorMessageFilterSchema, behaviorMessageSplittingSchema, behaviorOperatorScheduleSchema, behaviorPrivacySchema, behaviorTypingBehaviorSchema, behaviorUrlHandlingSchema, compactObject, defineTool, feedbackSheetRowSchema, followUpSequenceTypeSchema, followUpTriggerSchema, mapBehaviorErrorHandlingInput, mapBehaviorGreetingInput, mapBehaviorMediaHandlingInput, mapBehaviorOperatorScheduleInput, mapBehaviorTypingInput, mapBehaviorUrlHandlingInput, mapOutputConfigInput, mapPipelineAutoFinishInput, mapPipelineCrmBehaviorInput, mapPlatformAccessControlInput, mapPlatformBitrix24BotSettingsInput, mapPlatformCrmBehaviorInput, mapPlatformGeneralSettingsInput, mapPlatformGetcourseSettingsInput, mapPlatformInstagramCommentInput, mapPlatformSalebotSettingsInput, mapPlatformSmsgorodSettingsInput, mapPlatformVariablesConfigInput, mapPlatformWidgetMarketingInput, mapRuntimeConfigInput, modelLaneSchema, pipelineAutoFinishSchema, pipelineCrmBehaviorSchema, platformAccessControlSchema, platformBitrix24BotSettingsSchema, platformCrmBehaviorSchema, platformGeneralSettingsSchema, platformGetcourseSettingsSchema, platformInstagramCommentSchema, platformSalebotSettingsSchema, platformSetupConfirmationSchema, platformSmsgorodSettingsSchema, platformVariablesConfigSchema, platformWidgetMarketingSchema, routingRuleConditionSchema, routingRuleLeadStatusSchema, routingStrategySchema, setupConfirmation, triggerScopeSchema, uuidSchema, withInstructions, } from './shared.js';
|
|
3
4
|
export const platformSetupTools = [
|
|
4
5
|
defineTool({
|
|
@@ -204,6 +205,186 @@ export const platformSetupTools = [
|
|
|
204
205
|
'preflight.blocked/errors — контакты, которым НЕ отправляли; BroadcastRecipient для них не создаётся, поэтому received в аналитике не раздувается.',
|
|
205
206
|
]),
|
|
206
207
|
}),
|
|
208
|
+
defineTool({
|
|
209
|
+
name: 'besales_getcourse_wave_run_start',
|
|
210
|
+
requiredFields: ['platform_id', 'crm_id', 'channels', 'contacts'],
|
|
211
|
+
defaultWorkspaceId: true,
|
|
212
|
+
schema: z
|
|
213
|
+
.object({
|
|
214
|
+
workspace_id: uuidSchema.optional(),
|
|
215
|
+
platform_id: uuidSchema,
|
|
216
|
+
crm_id: uuidSchema,
|
|
217
|
+
launch_type: z.literal('status').optional(),
|
|
218
|
+
channels: z.array(z.string()).min(1),
|
|
219
|
+
funnel: z.string().max(200).optional(),
|
|
220
|
+
segment: z.string().max(200).optional(),
|
|
221
|
+
cohort_label: z.string().max(200).optional(),
|
|
222
|
+
message_variant: z.string().max(120).optional(),
|
|
223
|
+
found_count: z.number().int().min(0).max(10_000_000).optional(),
|
|
224
|
+
product_code: z
|
|
225
|
+
.string()
|
|
226
|
+
.trim()
|
|
227
|
+
.max(100)
|
|
228
|
+
.regex(/^[^\s/]+$/, 'product_code: без пробелов и «/»')
|
|
229
|
+
.optional(),
|
|
230
|
+
product_name: z.string().max(200).optional(),
|
|
231
|
+
deal_fields: z
|
|
232
|
+
.record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.null()]))
|
|
233
|
+
.optional(),
|
|
234
|
+
contacts: z
|
|
235
|
+
.array(z.object({
|
|
236
|
+
contact_id: z.string(),
|
|
237
|
+
deal_id: z.string().optional(),
|
|
238
|
+
transport: z.string().optional(),
|
|
239
|
+
dialog_id: z.string().optional(),
|
|
240
|
+
lead_last_active_at: z.string().datetime({ offset: true }).optional(),
|
|
241
|
+
segment_entered_at: z.string().datetime({ offset: true }).optional(),
|
|
242
|
+
}))
|
|
243
|
+
.min(1)
|
|
244
|
+
.max(5000),
|
|
245
|
+
confirm: z.boolean().optional(),
|
|
246
|
+
check_messenger_presence: z.boolean().optional(),
|
|
247
|
+
dedup_window_days: z.number().int().min(0).max(365).optional(),
|
|
248
|
+
dedup_scope: z.enum(['any', 'same_funnel']).optional(),
|
|
249
|
+
preflight: z
|
|
250
|
+
.object({
|
|
251
|
+
enabled: z.boolean().optional(),
|
|
252
|
+
product_title: z.string().max(500).optional(),
|
|
253
|
+
product_match_key: z.string().max(500).optional(),
|
|
254
|
+
offer_id: z.number().int().positive().optional(),
|
|
255
|
+
other_product_active_deal_mode: z.enum(['warn', 'block', 'ignore']).optional(),
|
|
256
|
+
})
|
|
257
|
+
.optional(),
|
|
258
|
+
chunk_size: z.number().int().min(1).max(500).optional(),
|
|
259
|
+
explicit_confirmation: z.literal(true).optional(),
|
|
260
|
+
confirmation_reason: z.string().optional(),
|
|
261
|
+
})
|
|
262
|
+
.refine((input) => !input.confirm || input.explicit_confirmation === true, {
|
|
263
|
+
message: 'Реальный запуск требует explicit_confirmation=true: отправка волны необратима',
|
|
264
|
+
path: ['explicit_confirmation'],
|
|
265
|
+
}),
|
|
266
|
+
createRequest: (input) => ({
|
|
267
|
+
method: 'POST',
|
|
268
|
+
path: `/workspaces/${input.workspace_id}/getcourse-wave-runs`,
|
|
269
|
+
body: compactObject({
|
|
270
|
+
platformId: input.platform_id,
|
|
271
|
+
crmId: input.crm_id,
|
|
272
|
+
launchType: input.launch_type,
|
|
273
|
+
channels: input.channels,
|
|
274
|
+
funnel: input.funnel,
|
|
275
|
+
segment: input.segment,
|
|
276
|
+
cohortLabel: input.cohort_label,
|
|
277
|
+
messageVariant: input.message_variant,
|
|
278
|
+
foundCount: input.found_count,
|
|
279
|
+
productCode: input.product_code,
|
|
280
|
+
productName: input.product_name,
|
|
281
|
+
dealFields: input.deal_fields,
|
|
282
|
+
contacts: input.contacts?.map((contact) => compactObject({
|
|
283
|
+
contactId: contact.contact_id,
|
|
284
|
+
dealId: contact.deal_id,
|
|
285
|
+
transport: contact.transport,
|
|
286
|
+
dialogId: contact.dialog_id,
|
|
287
|
+
leadLastActiveAt: contact.lead_last_active_at,
|
|
288
|
+
segmentEnteredAt: contact.segment_entered_at,
|
|
289
|
+
})),
|
|
290
|
+
confirm: input.confirm,
|
|
291
|
+
checkMessengerPresence: input.check_messenger_presence,
|
|
292
|
+
dedupWindowDays: input.dedup_window_days,
|
|
293
|
+
dedupScope: input.dedup_scope,
|
|
294
|
+
preflight: input.preflight
|
|
295
|
+
? compactObject({
|
|
296
|
+
enabled: input.preflight.enabled,
|
|
297
|
+
productTitle: input.preflight.product_title,
|
|
298
|
+
productMatchKey: input.preflight.product_match_key,
|
|
299
|
+
offerId: input.preflight.offer_id,
|
|
300
|
+
otherProductActiveDealMode: input.preflight.other_product_active_deal_mode,
|
|
301
|
+
})
|
|
302
|
+
: undefined,
|
|
303
|
+
chunkSize: input.chunk_size,
|
|
304
|
+
}),
|
|
305
|
+
}),
|
|
306
|
+
enhanceResponse: (response) => withInstructions(response, [
|
|
307
|
+
'Durable-прогон сам режет когорту на куски и отправляет их последовательно, сам ждёт освобождения лока импорта и переживает рестарт сервиса. Опрашивай ОДИН прогон через besales_getcourse_wave_run_status, не собирай волну вручную.',
|
|
308
|
+
'БЕЗ confirm=true — DRY-RUN: возвращается проверка, но прогон НЕ создаётся и ничего не отправляется.',
|
|
309
|
+
'Реальный запуск требует ОДНОВРЕМЕННО confirm=true и explicit_confirmation=true. explicit_confirmation — MCP-гейт явного согласия оператора и в HTTP-запрос не передаётся.',
|
|
310
|
+
'Поддерживается ТОЛЬКО launch_type=status. Для board/group используй старый besales_getcourse_wave_import.',
|
|
311
|
+
'HTTP 409 означает, что на платформе уже идёт активный прогон: в ответе есть его runId — не создавай новую волну, опрашивай этот runId.',
|
|
312
|
+
'Статус прогона отдаёт только агрегаты. Полный построчный разбор получай через besales_getcourse_wave_run_contacts с курсорной пагинацией.',
|
|
313
|
+
'Исходы контактов: SENT — отправлено; SKIPPED — дедуп, нет мессенджера или preflight заблокировал; FAILED — построчная ошибка; UNKNOWN — исход НЕИЗВЕСТЕН: кусок был прерван, но отправка могла состояться.',
|
|
314
|
+
'UNKNOWN и FAILED НИКОГДА не переотправляются автоматически. Повторная отправка таких контактов — только осознанное решение оператора отдельной волной: отсутствие строки получателя не доказывает отсутствие отправки.',
|
|
315
|
+
]),
|
|
316
|
+
}),
|
|
317
|
+
defineTool({
|
|
318
|
+
name: 'besales_getcourse_wave_run_status',
|
|
319
|
+
requiredFields: ['run_id'],
|
|
320
|
+
defaultWorkspaceId: true,
|
|
321
|
+
schema: z.object({
|
|
322
|
+
workspace_id: uuidSchema.optional(),
|
|
323
|
+
run_id: uuidSchema,
|
|
324
|
+
}),
|
|
325
|
+
createRequest: (input) => ({
|
|
326
|
+
method: 'GET',
|
|
327
|
+
path: `/workspaces/${input.workspace_id}/getcourse-wave-runs/${input.run_id}`,
|
|
328
|
+
}),
|
|
329
|
+
enhanceResponse: (response) => withInstructions(response, [
|
|
330
|
+
'Это единый агрегированный статус durable-прогона: он сам последовательно обрабатывает куски, ждёт лок импорта и продолжает после рестарта сервиса. Не собирай и не запускай куски вручную.',
|
|
331
|
+
'Статус содержит только агрегаты. Для полного построчного разбора используй besales_getcourse_wave_run_contacts с курсорной пагинацией.',
|
|
332
|
+
'SENT — отправлено; SKIPPED — дедуп, нет мессенджера или блокировка preflight; FAILED — построчная ошибка; UNKNOWN — исход НЕИЗВЕСТЕН после прерванного куска, отправка могла состояться.',
|
|
333
|
+
'UNKNOWN и FAILED НИКОГДА не переотправляются автоматически. Решение о повторе принимает оператор и запускает отдельную волну, потому что отсутствие строки получателя не доказывает отсутствие отправки.',
|
|
334
|
+
]),
|
|
335
|
+
}),
|
|
336
|
+
defineTool({
|
|
337
|
+
name: 'besales_getcourse_wave_run_contacts',
|
|
338
|
+
requiredFields: ['run_id'],
|
|
339
|
+
defaultWorkspaceId: true,
|
|
340
|
+
schema: z.object({
|
|
341
|
+
workspace_id: uuidSchema.optional(),
|
|
342
|
+
run_id: uuidSchema,
|
|
343
|
+
status: z
|
|
344
|
+
.enum(['PENDING', 'CLAIMED', 'SENT', 'SKIPPED', 'FAILED', 'UNKNOWN'])
|
|
345
|
+
.optional(),
|
|
346
|
+
cursor: uuidSchema.optional(),
|
|
347
|
+
limit: z.number().int().min(1).max(500).optional(),
|
|
348
|
+
}),
|
|
349
|
+
createRequest: (input) => {
|
|
350
|
+
const params = new URLSearchParams();
|
|
351
|
+
if (input.status)
|
|
352
|
+
params.set('status', input.status);
|
|
353
|
+
if (input.cursor)
|
|
354
|
+
params.set('cursor', input.cursor);
|
|
355
|
+
if (input.limit !== undefined)
|
|
356
|
+
params.set('limit', String(input.limit));
|
|
357
|
+
const query = params.toString();
|
|
358
|
+
return {
|
|
359
|
+
method: 'GET',
|
|
360
|
+
path: `/workspaces/${input.workspace_id}/getcourse-wave-runs/${input.run_id}/contacts${query ? `?${query}` : ''}`,
|
|
361
|
+
};
|
|
362
|
+
},
|
|
363
|
+
enhanceResponse: (response) => withInstructions(response, [
|
|
364
|
+
'Полный построчный разбор durable-прогона. Продолжай курсорную пагинацию по nextCursor до конца; агрегированный besales_getcourse_wave_run_status строк контактов не возвращает.',
|
|
365
|
+
'Фильтр status: PENDING | CLAIMED | SENT | SKIPPED | FAILED | UNKNOWN. SKIPPED означает дедуп, отсутствие мессенджера или блокировку preflight; FAILED — построчную ошибку.',
|
|
366
|
+
'UNKNOWN означает, что исход НЕИЗВЕСТЕН: кусок был прерван, но отправка могла состояться. UNKNOWN и FAILED НИКОГДА не переотправляются автоматически.',
|
|
367
|
+
'Повтор UNKNOWN/FAILED допустим только осознанным решением оператора отдельной волной: отсутствие строки получателя не доказывает отсутствие отправки.',
|
|
368
|
+
]),
|
|
369
|
+
}),
|
|
370
|
+
defineTool({
|
|
371
|
+
name: 'besales_getcourse_wave_run_cancel',
|
|
372
|
+
requiredFields: ['run_id'],
|
|
373
|
+
defaultWorkspaceId: true,
|
|
374
|
+
schema: z.object({
|
|
375
|
+
workspace_id: uuidSchema.optional(),
|
|
376
|
+
run_id: uuidSchema,
|
|
377
|
+
}),
|
|
378
|
+
createRequest: (input) => ({
|
|
379
|
+
method: 'POST',
|
|
380
|
+
path: `/workspaces/${input.workspace_id}/getcourse-wave-runs/${input.run_id}/cancel`,
|
|
381
|
+
}),
|
|
382
|
+
enhanceResponse: (response) => withInstructions(response, [
|
|
383
|
+
'Отмена запрещает прогону заявлять новые куски. Уже заявленный кусок может завершиться; после отмены опроси besales_getcourse_wave_run_status.',
|
|
384
|
+
'Для полного построчного результата используй besales_getcourse_wave_run_contacts с курсорной пагинацией; статус прогона отдаёт только агрегаты.',
|
|
385
|
+
'UNKNOWN — исход НЕИЗВЕСТЕН после прерванного куска, отправка могла состояться. UNKNOWN и FAILED автоматически не переотправляются; повтор возможен только отдельной волной по осознанному решению оператора.',
|
|
386
|
+
]),
|
|
387
|
+
}),
|
|
207
388
|
defineTool({
|
|
208
389
|
name: 'besales_wazzup_templates_list',
|
|
209
390
|
requiredFields: ['platform_id'],
|
|
@@ -688,7 +869,8 @@ export const platformSetupTools = [
|
|
|
688
869
|
trigger: followUpTriggerSchema,
|
|
689
870
|
config: anyObjectSchema,
|
|
690
871
|
...platformSetupConfirmationSchema,
|
|
691
|
-
})
|
|
872
|
+
})
|
|
873
|
+
.superRefine(refineFollowUpConfig),
|
|
692
874
|
createRequest: (input) => ({
|
|
693
875
|
method: input.sequence_id ? 'PATCH' : 'POST',
|
|
694
876
|
path: input.sequence_id
|