@besales/mcp 0.46.0 → 0.47.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 (182) hide show
  1. package/README.md +96 -55
  2. package/dist/auth/connection-store.d.ts +21 -1
  3. package/dist/auth/connection-store.js +46 -2
  4. package/dist/auth/connection-store.js.map +1 -1
  5. package/dist/auth/oauth-client.d.ts +5 -1
  6. package/dist/auth/oauth-client.js +22 -12
  7. package/dist/auth/oauth-client.js.map +1 -1
  8. package/dist/cli.js +14 -5
  9. package/dist/cli.js.map +1 -1
  10. package/dist/http/api-client.d.ts +16 -1
  11. package/dist/http/api-client.js +50 -2
  12. package/dist/http/api-client.js.map +1 -1
  13. package/dist/instructions/server-instructions.d.ts +4 -13
  14. package/dist/instructions/server-instructions.js +68 -274
  15. package/dist/instructions/server-instructions.js.map +1 -1
  16. package/dist/prompts/registry.d.ts +15 -0
  17. package/dist/prompts/registry.js +83 -0
  18. package/dist/prompts/registry.js.map +1 -0
  19. package/dist/resources/concepts/feedback-sheets.md +7 -4
  20. package/dist/resources/concepts/handoff.md +4 -1
  21. package/dist/resources/concepts/sandbox.md +14 -5
  22. package/dist/resources/concepts/triggers.md +6 -2
  23. package/dist/resources/concepts/workbook-classification.md +26 -21
  24. package/dist/resources/docs/campaigns.md +20 -0
  25. package/dist/resources/docs/follow-up.md +19 -0
  26. package/dist/resources/docs/platforms.md +2 -2
  27. package/dist/resources/docs/routing.md +18 -0
  28. package/dist/resources/docs/task-state.md +30 -0
  29. package/dist/resources/docs/trigger-actions.md +28 -0
  30. package/dist/resources/docs/variables.md +18 -0
  31. package/dist/resources/registry.js +51 -2
  32. package/dist/resources/registry.js.map +1 -1
  33. package/dist/resources/workflows/extract-from-document.md +8 -1
  34. package/dist/resources/workflows/iterate-with-sandbox.md +5 -2
  35. package/dist/resources/workflows/platform-setup-from-scratch.md +90 -2
  36. package/dist/resources/workflows/production-readiness-check.md +22 -18
  37. package/dist/schemas/mcp-tools.json +1058 -99
  38. package/dist/server.d.ts +2 -0
  39. package/dist/server.js +8 -2
  40. package/dist/server.js.map +1 -1
  41. package/dist/tasks/task-state-store.d.ts +68 -0
  42. package/dist/tasks/task-state-store.js +278 -0
  43. package/dist/tasks/task-state-store.js.map +1 -0
  44. package/dist/tools/annotations.d.ts +7 -0
  45. package/dist/tools/annotations.js +16 -0
  46. package/dist/tools/annotations.js.map +1 -0
  47. package/dist/tools/contracts.js +7 -1
  48. package/dist/tools/contracts.js.map +1 -1
  49. package/dist/tools/definitions/agent-design.d.ts +41 -20
  50. package/dist/tools/definitions/agent-design.js +189 -19
  51. package/dist/tools/definitions/agent-design.js.map +1 -1
  52. package/dist/tools/definitions/analytics.d.ts +40 -0
  53. package/dist/tools/definitions/analytics.js +233 -0
  54. package/dist/tools/definitions/analytics.js.map +1 -0
  55. package/dist/tools/definitions/broadcast-analytics.js +12 -0
  56. package/dist/tools/definitions/broadcast-analytics.js.map +1 -1
  57. package/dist/tools/definitions/broadcast-mailing-variants.d.ts +2 -0
  58. package/dist/tools/definitions/broadcast-mailing-variants.js +10 -0
  59. package/dist/tools/definitions/broadcast-mailing-variants.js.map +1 -1
  60. package/dist/tools/definitions/broadcast-scheduler.d.ts +7 -1
  61. package/dist/tools/definitions/broadcast-scheduler.js +71 -4
  62. package/dist/tools/definitions/broadcast-scheduler.js.map +1 -1
  63. package/dist/tools/definitions/contacts.d.ts +15 -0
  64. package/dist/tools/definitions/contacts.js +84 -0
  65. package/dist/tools/definitions/contacts.js.map +1 -0
  66. package/dist/tools/definitions/crm-platform.d.ts +2 -0
  67. package/dist/tools/definitions/crm-platform.js +75 -5
  68. package/dist/tools/definitions/crm-platform.js.map +1 -1
  69. package/dist/tools/definitions/datasource.d.ts +1 -0
  70. package/dist/tools/definitions/datasource.js +16 -1
  71. package/dist/tools/definitions/datasource.js.map +1 -1
  72. package/dist/tools/definitions/dialogue-audit.d.ts +2 -2
  73. package/dist/tools/definitions/dialogue-audit.js +54 -16
  74. package/dist/tools/definitions/dialogue-audit.js.map +1 -1
  75. package/dist/tools/definitions/dialogue-export.d.ts +1 -1
  76. package/dist/tools/definitions/dialogue-export.js +12 -0
  77. package/dist/tools/definitions/dialogue-export.js.map +1 -1
  78. package/dist/tools/definitions/external-api-channels.js +39 -12
  79. package/dist/tools/definitions/external-api-channels.js.map +1 -1
  80. package/dist/tools/definitions/follow-up-funnel-test.js +4 -0
  81. package/dist/tools/definitions/follow-up-funnel-test.js.map +1 -1
  82. package/dist/tools/definitions/follow-up-setup.js +3 -0
  83. package/dist/tools/definitions/follow-up-setup.js.map +1 -1
  84. package/dist/tools/definitions/follow-up.d.ts +1 -1
  85. package/dist/tools/definitions/follow-up.js +4 -0
  86. package/dist/tools/definitions/follow-up.js.map +1 -1
  87. package/dist/tools/definitions/getcourse-anchor-refresh.d.ts +3 -0
  88. package/dist/tools/definitions/getcourse-anchor-refresh.js +29 -2
  89. package/dist/tools/definitions/getcourse-anchor-refresh.js.map +1 -1
  90. package/dist/tools/definitions/getcourse-cold-welcome.d.ts +12 -2
  91. package/dist/tools/definitions/getcourse-cold-welcome.js +79 -4
  92. package/dist/tools/definitions/getcourse-cold-welcome.js.map +1 -1
  93. package/dist/tools/definitions/getcourse-wave.js +14 -0
  94. package/dist/tools/definitions/getcourse-wave.js.map +1 -1
  95. package/dist/tools/definitions/help.d.ts +8 -0
  96. package/dist/tools/definitions/help.js +219 -0
  97. package/dist/tools/definitions/help.js.map +1 -0
  98. package/dist/tools/definitions/knowledge.d.ts +27 -5
  99. package/dist/tools/definitions/knowledge.js +200 -33
  100. package/dist/tools/definitions/knowledge.js.map +1 -1
  101. package/dist/tools/definitions/link-tracking.js +9 -0
  102. package/dist/tools/definitions/link-tracking.js.map +1 -1
  103. package/dist/tools/definitions/model-comparison.js +6 -0
  104. package/dist/tools/definitions/model-comparison.js.map +1 -1
  105. package/dist/tools/definitions/operational-overview.d.ts +3 -0
  106. package/dist/tools/definitions/operational-overview.js +23 -0
  107. package/dist/tools/definitions/operational-overview.js.map +1 -0
  108. package/dist/tools/definitions/operator-workflow.d.ts +20 -0
  109. package/dist/tools/definitions/operator-workflow.js +114 -0
  110. package/dist/tools/definitions/operator-workflow.js.map +1 -0
  111. package/dist/tools/definitions/platform-setup.d.ts +25 -3
  112. package/dist/tools/definitions/platform-setup.js +198 -5
  113. package/dist/tools/definitions/platform-setup.js.map +1 -1
  114. package/dist/tools/definitions/scheduled-tasks.js +2 -0
  115. package/dist/tools/definitions/scheduled-tasks.js.map +1 -1
  116. package/dist/tools/definitions/session.js +103 -5
  117. package/dist/tools/definitions/session.js.map +1 -1
  118. package/dist/tools/definitions/shared.d.ts +153 -11
  119. package/dist/tools/definitions/shared.js +59 -9
  120. package/dist/tools/definitions/shared.js.map +1 -1
  121. package/dist/tools/definitions/task-state.d.ts +76 -0
  122. package/dist/tools/definitions/task-state.js +301 -0
  123. package/dist/tools/definitions/task-state.js.map +1 -0
  124. package/dist/tools/definitions/trigger-contact-claims.js +2 -0
  125. package/dist/tools/definitions/trigger-contact-claims.js.map +1 -1
  126. package/dist/tools/definitions.d.ts +265 -31
  127. package/dist/tools/definitions.js +12 -0
  128. package/dist/tools/definitions.js.map +1 -1
  129. package/dist/tools/description-localization.d.ts +2 -0
  130. package/dist/tools/description-localization.js +46 -0
  131. package/dist/tools/description-localization.js.map +1 -0
  132. package/dist/tools/incomplete-list.d.ts +23 -0
  133. package/dist/tools/incomplete-list.js +39 -0
  134. package/dist/tools/incomplete-list.js.map +1 -0
  135. package/dist/tools/inventory.d.ts +10 -0
  136. package/dist/tools/inventory.js +49 -0
  137. package/dist/tools/inventory.js.map +1 -0
  138. package/dist/tools/registry-mapping-cases-core.js +111 -2
  139. package/dist/tools/registry-mapping-cases-core.js.map +1 -1
  140. package/dist/tools/registry-mapping-cases-platform.js +69 -0
  141. package/dist/tools/registry-mapping-cases-platform.js.map +1 -1
  142. package/dist/tools/registry.d.ts +2 -0
  143. package/dist/tools/registry.js +60 -8
  144. package/dist/tools/registry.js.map +1 -1
  145. package/dist/tools/result-envelope.d.ts +46 -0
  146. package/dist/tools/result-envelope.js +184 -0
  147. package/dist/tools/result-envelope.js.map +1 -0
  148. package/dist/tools/result.d.ts +41 -3
  149. package/dist/tools/result.js +229 -27
  150. package/dist/tools/result.js.map +1 -1
  151. package/dist/tools/tool-title.d.ts +2 -0
  152. package/dist/tools/tool-title.js +12 -0
  153. package/dist/tools/tool-title.js.map +1 -0
  154. package/dist/tools/toolsets.d.ts +37 -0
  155. package/dist/tools/toolsets.js +64 -0
  156. package/dist/tools/toolsets.js.map +1 -0
  157. package/dist/tools/verify-with.d.ts +5 -0
  158. package/dist/tools/verify-with.js +36 -0
  159. package/dist/tools/verify-with.js.map +1 -0
  160. package/dist/types/api-contract.gen.d.ts +1421 -80
  161. package/dist/utils/logger.d.ts +11 -0
  162. package/dist/utils/logger.js +64 -8
  163. package/dist/utils/logger.js.map +1 -1
  164. package/docs/agent-usage-guide.full.ru.md +20 -15
  165. package/docs/agent-usage-guide.ru.md +24 -16
  166. package/docs/async-operation-lifecycle.md +46 -0
  167. package/docs/connect.ru.md +120 -0
  168. package/docs/evals/model-behavior-scorecard.md +80 -0
  169. package/docs/failure-semantics.md +56 -0
  170. package/docs/help-navigation.md +48 -0
  171. package/docs/host-compatibility-matrix.md +153 -0
  172. package/docs/host-setup.md +22 -6
  173. package/docs/operation-coverage.md +114 -0
  174. package/docs/pii-policy.md +46 -0
  175. package/docs/response-size-budget.md +150 -0
  176. package/docs/task-state.md +58 -0
  177. package/docs/tool-effects.md +46 -0
  178. package/docs/tool-surface.md +91 -0
  179. package/package.json +6 -2
  180. package/scripts/model-eval-server.js +213 -0
  181. package/scripts/probe-mcp-protocol.js +134 -0
  182. package/scripts/run-model-eval.js +447 -0
@@ -1,29 +1,178 @@
1
1
  import { ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
2
2
  import { ZodError } from 'zod';
3
3
  import { WorkspaceResolutionError } from '../auth/connection-store.js';
4
- import { ApiClientError, ApiClientNetworkError } from '../http/api-client.js';
5
- export function jsonToolResult(value) {
4
+ import { ApiClientError, ApiClientNetworkError, } from '../http/api-client.js';
5
+ import { IncompleteListError } from './incomplete-list.js';
6
+ import { isEnvelopeEnabled, shapeErrorMessage, shapeToolResult, } from './result-envelope.js';
7
+ /**
8
+ * Единственный формат успешного ответа инструмента.
9
+ *
10
+ * ⚠️ Функция обязана быть ТОТАЛЬНОЙ. Она выполняется ПОСЛЕ успешной мутации: если она
11
+ * бросит, вызывающий увидит ошибку инструмента и повторит платный побочный эффект. Поэтому
12
+ * любой внутренний сбой форматирования отдаёт минимальную квитанцию — и БЕЗ `isError`,
13
+ * иначе получилось бы то же самое приглашение повторить.
14
+ */
15
+ export function jsonToolResult(value, policy, sideEffect = 'write') {
16
+ let shaped;
17
+ try {
18
+ shaped = shapeToolResult(value, policy, isEnvelopeEnabled());
19
+ }
20
+ catch {
21
+ const receipt = { ...identityOf(value), _mcpFormattingFailed: true };
22
+ return {
23
+ content: [
24
+ {
25
+ type: 'text',
26
+ text: JSON.stringify(receipt),
27
+ },
28
+ ],
29
+ ...(isEnvelopeEnabled() ? { structuredContent: receipt } : {}),
30
+ };
31
+ }
32
+ if (!shaped.refused) {
33
+ if (!isEnvelopeEnabled())
34
+ return { content: [{ type: 'text', text: shaped.text }] };
35
+ const structuredContent = structuredResult(shaped.text);
36
+ return {
37
+ content: [{ type: 'text', text: JSON.stringify(structuredContent) }],
38
+ structuredContent,
39
+ };
40
+ }
41
+ // ⚠️ Отказ по размеру — ошибка ТОЛЬКО у читающего инструмента: там он означает «сузьте
42
+ // запрос и позовите снова». У мутирующего к этому моменту побочный эффект УЖЕ состоялся,
43
+ // и признак ошибки был бы приглашением повторить его — второй клон агента, вторая рассылка.
44
+ // Поэтому наружу уходит неошибочная квитанция с идентификаторами и объяснением.
45
+ if (sideEffect !== 'none') {
46
+ const receipt = {
47
+ ...identityOf(value),
48
+ _mcpOversized: true,
49
+ _mcpNote: `Операция ВЫПОЛНЕНА, но её ответ не помещается в потолок и не показан целиком. Повторный вызов выполнит операцию ЗАНОВО. ${shaped.text}`,
50
+ };
51
+ return {
52
+ content: [
53
+ {
54
+ type: 'text',
55
+ text: JSON.stringify(receipt),
56
+ },
57
+ ],
58
+ structuredContent: receipt,
59
+ };
60
+ }
61
+ return { isError: true, content: [{ type: 'text', text: shaped.text }] };
62
+ }
63
+ /**
64
+ * Что вернуть, когда сериализовать ответ не удалось: идентификаторы созданной сущности, если
65
+ * они видны на верхнем уровне. Без них вызывающий не смог бы даже сослаться на результат
66
+ * уже состоявшейся мутации.
67
+ */
68
+ export function identityOf(value) {
69
+ const identity = {};
70
+ const identityKeys = new Set([
71
+ 'id',
72
+ 'operationId',
73
+ 'operation_id',
74
+ 'runId',
75
+ 'run_id',
76
+ 'jobId',
77
+ 'job_id',
78
+ 'draftId',
79
+ 'draft_id',
80
+ 'setupRef',
81
+ 'setup_ref',
82
+ ]);
83
+ const pending = [{ value, depth: 0 }];
84
+ const seen = new Set();
85
+ while (pending.length > 0) {
86
+ const current = pending.shift();
87
+ if (!current || current.depth > 4 || typeof current.value !== 'object' || current.value === null) {
88
+ continue;
89
+ }
90
+ if (seen.has(current.value))
91
+ continue;
92
+ seen.add(current.value);
93
+ const entries = Array.isArray(current.value)
94
+ ? current.value.map((item, index) => [String(index), item])
95
+ : Object.entries(current.value);
96
+ for (const [key, candidate] of entries) {
97
+ if (identityKeys.has(key) &&
98
+ identity[key] === undefined &&
99
+ (typeof candidate === 'string' || typeof candidate === 'number')) {
100
+ identity[key] = candidate;
101
+ }
102
+ if (typeof candidate === 'object' && candidate !== null) {
103
+ pending.push({ value: candidate, depth: current.depth + 1 });
104
+ }
105
+ }
106
+ }
107
+ return identity;
108
+ }
109
+ /** Безошибочная квитанция, когда API уже ответил, а локальная постобработка сломалась. */
110
+ export function acceptedResponseReceipt(value, _cause) {
111
+ const receipt = {
112
+ ...identityOf(value),
113
+ _mcpPostprocessingFailed: true,
114
+ _mcpNote: 'API принял операцию, но MCP не смог обработать полученный ответ. Не повторяйте мутацию; проверьте созданный объект по квитанции.',
115
+ _mcpCause: 'local_postprocessing_failed',
116
+ };
6
117
  return {
7
- content: [
8
- {
9
- type: 'text',
10
- text: JSON.stringify(value, null, 2),
11
- },
12
- ],
118
+ content: [{ type: 'text', text: JSON.stringify(receipt) }],
119
+ ...(isEnvelopeEnabled() ? { structuredContent: receipt } : {}),
13
120
  };
14
121
  }
15
- export function errorToolResult(message) {
122
+ function structuredResult(text) {
123
+ const value = JSON.parse(text);
124
+ if (Array.isArray(value))
125
+ return { items: value };
126
+ if (typeof value === 'object' && value !== null)
127
+ return value;
128
+ return { value };
129
+ }
130
+ export function errorToolResult(message, structuredError) {
16
131
  return {
17
132
  isError: true,
18
133
  content: [
19
134
  {
20
135
  type: 'text',
21
- text: message,
136
+ // Сообщение бэкенда ничем не ограничено и попадало наружу как есть. Обрезка — часть
137
+ // конверта, поэтому она под тем же флагом: пакет ставится без версии (`npx -y`), и
138
+ // изменение формы ответа не должно доезжать до пользователей само.
139
+ text: isEnvelopeEnabled() ? shapeErrorMessage(message) : message,
22
140
  },
23
141
  ],
142
+ ...(structuredError ? { structuredContent: { error: structuredError } } : {}),
24
143
  };
25
144
  }
26
- export function mapToolError(error, restartToolName, workspaceId) {
145
+ /**
146
+ * Мог ли вызов оставить след, которого мы не видим.
147
+ *
148
+ * Читающий инструмент — нет; идемпотентный — след есть, но повтор его не удвоит. Всё
149
+ * остальное: запрос ушёл, ответа нет, и отсутствие подтверждения НЕ доказывает, что операция
150
+ * не состоялась.
151
+ */
152
+ function outcomeIsAmbiguous(context) {
153
+ return context.sideEffect !== 'none' && context.idempotent !== true;
154
+ }
155
+ /**
156
+ * Ответ на неоднозначный исход: ни `isError`-совета «попробуйте позже», ни тишины.
157
+ *
158
+ * ⛔ Совет повторить здесь опаснее самой ошибки: повторное создание заведёт вторую сущность,
159
+ * повторный запуск волны отправит сообщения людям второй раз, повторный перевыпуск отзовёт
160
+ * ключ, который партнёр только что получил. Поэтому текст называет проверку, а не повтор.
161
+ */
162
+ function ambiguousOutcomeResult(cause, context) {
163
+ const verify = context.verifyWithToolName
164
+ ? `Сверьтесь через \`${context.verifyWithToolName}\`.`
165
+ : 'Сверьтесь состоянием на стороне Besales (списком или *_status-инструментом этой операции).';
166
+ const message = `OUTCOME_UNKNOWN: ${cause} Запрос ушёл, ответа нет — операция могла СОСТОЯТЬСЯ. ` +
167
+ `Не повторяйте вызов: повтор ${context.sideEffect === 'spend' ? 'заплатит второй раз' : 'заведёт второй экземпляр'}. ${verify}`;
168
+ return errorToolResult(message, {
169
+ code: 'OUTCOME_UNKNOWN',
170
+ message,
171
+ continuation: verify,
172
+ requestIdentity: context.requestIdentity,
173
+ });
174
+ }
175
+ export function mapToolError(error, context = { sideEffect: 'none' }, workspaceId) {
27
176
  if (error instanceof ZodError) {
28
177
  throw new McpError(ErrorCode.InvalidParams, formatZodError(error));
29
178
  }
@@ -32,11 +181,20 @@ export function mapToolError(error, restartToolName, workspaceId) {
32
181
  if (error instanceof WorkspaceResolutionError) {
33
182
  return errorToolResult(error.message);
34
183
  }
184
+ // Отказ отдать неполный список — это «позови снова, попросив страницу», а не внутренний
185
+ // сбой: ветка Error ниже превратила бы его в InternalError и спрятала бы объяснение.
186
+ if (error instanceof IncompleteListError) {
187
+ return errorToolResult(error.message);
188
+ }
35
189
  if (error instanceof ApiClientError) {
36
- return mapApiClientError(error, restartToolName, workspaceId);
190
+ return mapApiClientError(error, context, workspaceId);
37
191
  }
38
192
  if (error instanceof ApiClientNetworkError) {
39
- return errorToolResult(`Animaly API network error: ${error.message}`);
193
+ // Обрыв связи — самый неоднозначный из исходов: запрос мог дойти и выполниться целиком,
194
+ // а потерян только ответ.
195
+ return outcomeIsAmbiguous(context)
196
+ ? ambiguousOutcomeResult(`связь с Besales оборвалась (${error.message}).`, context)
197
+ : errorToolResult(`Besales API network error: ${error.message}`);
40
198
  }
41
199
  if (error instanceof McpError) {
42
200
  throw error;
@@ -46,42 +204,86 @@ export function mapToolError(error, restartToolName, workspaceId) {
46
204
  }
47
205
  throw new McpError(ErrorCode.InternalError, 'Unknown tool execution error');
48
206
  }
49
- function mapApiClientError(error, restartToolName, workspaceId) {
207
+ function mapApiClientError(error, context, workspaceId) {
50
208
  if (!error.status) {
51
209
  return errorToolResult('Not connected to Animaly. Run `besales-mcp connect` first.');
52
210
  }
53
211
  if (error.status >= 500) {
54
- return errorToolResult(`Animaly API is temporarily unavailable (${error.status}). Try again later.`);
212
+ // ⚠️ Пятисотый — это отказ ПОСЛЕ того, как запрос дошёл до сервера. Он мог упасть на
213
+ // ответе, на записи в очередь или на пути назад, уже совершив основную работу.
214
+ return outcomeIsAmbiguous(context)
215
+ ? ambiguousOutcomeResult(`Besales ответил ошибкой ${error.status}.`, context)
216
+ : apiErrorResult(error, `Besales API is temporarily unavailable (${error.status}). Try again later.`, 'Повтори читающий или доказанно идемпотентный вызов позже.');
55
217
  }
56
218
  if (error.status === 401) {
57
- return errorToolResult(workspaceId
219
+ const message = workspaceId
58
220
  ? `Animaly rejected stored credentials for workspace ${workspaceId}. Run \`besales-mcp connect\` again for it.`
59
- : 'Animaly rejected stored credentials. Run `besales-mcp connect` again.');
221
+ : 'Animaly rejected stored credentials. Run `besales-mcp connect` again.';
222
+ return apiErrorResult(error, message, 'Переподключи этот workspace и повтори только после успешного connect.');
60
223
  }
61
224
  if (error.status === 403) {
62
225
  // Сообщение бэкенда НАЗЫВАЕТ недостающий scope, и оно важнее нашей догадки: композит
63
226
  // `mcp:*` покрывает не все эндпоинты (например, cold-welcome требует `read:campaigns`),
64
227
  // и подсказка про `mcp:*`/`mcp:platform-setup` там уводит в ложный диагноз «ключ не тот».
65
- return errorToolResult(error.responseMessage
228
+ const message = error.responseMessage
66
229
  ? `Animaly rejected this request: ${error.responseMessage}`
67
- : 'Animaly rejected this request: the stored key lacks the scope this endpoint requires.');
230
+ : 'Animaly rejected this request: the stored key lacks the scope this endpoint requires.';
231
+ return apiErrorResult(error, message, 'Добавь недостающий scope через connect, не заменяя уже выданные права.');
68
232
  }
69
233
  if (error.status === 410) {
70
- return errorToolResult(restartToolName
71
- ? `Operation expired. Restart from \`${restartToolName}\` and submit the new operation.`
72
- : 'Operation expired. Restart from the matching get_instructions tool.');
234
+ const message = context.restartToolName
235
+ ? `Operation expired. Restart from \`${context.restartToolName}\` and submit the new operation.`
236
+ : 'Operation expired. Restart from the matching get_instructions tool.';
237
+ return apiErrorResult(error, message, context.restartToolName
238
+ ? `Начни новую operation через ${context.restartToolName}; старый operationId больше не используй.`
239
+ : 'Начни новую operation через соответствующий get_instructions.');
73
240
  }
74
241
  if (error.status === 422) {
75
- return errorToolResult(error.responseMessage
242
+ const message = error.responseMessage
76
243
  ? `Animaly rejected tool input: ${error.responseMessage}`
77
- : 'Animaly rejected tool input.');
244
+ : 'Animaly rejected tool input.';
245
+ return apiErrorResult(error, message, 'Исправь указанные поля и отправь тот же замысел снова.');
78
246
  }
79
247
  if (error.status === 429) {
80
- return errorToolResult('Animaly rate limit reached. Try again later.');
248
+ const retryAfter = error.details?.retryAfterSeconds;
249
+ return apiErrorResult(error, retryAfter === undefined
250
+ ? 'Animaly rate limit reached. Try again later.'
251
+ : `Animaly rate limit reached. Retry after ${retryAfter} seconds.`, retryAfter === undefined
252
+ ? 'Подожди и повтори после снятия ограничения.'
253
+ : `Повтори не раньше чем через ${retryAfter} секунд.`);
81
254
  }
82
- return errorToolResult(error.responseMessage
255
+ const message = error.responseMessage
83
256
  ? `Animaly rejected request (${error.status}): ${error.responseMessage}`
84
- : `Animaly rejected request (${error.status}).`);
257
+ : `Animaly rejected request (${error.status}).`;
258
+ return apiErrorResult(error, message, error.details?.remediation ? undefined : 'Исправь причину из сообщения и повтори вызов.');
259
+ }
260
+ function apiErrorResult(error, message, continuation) {
261
+ const detailsText = formatSafeDetails(error.details);
262
+ const visibleMessage = detailsText ? `${message} ${detailsText}` : message;
263
+ return errorToolResult(visibleMessage, {
264
+ code: error.details?.code ?? `HTTP_${error.status ?? 'UNKNOWN'}`,
265
+ message,
266
+ status: error.status,
267
+ details: error.details,
268
+ continuation: continuation ??
269
+ (typeof error.details?.remediation === 'string'
270
+ ? error.details.remediation
271
+ : error.details?.remediation?.join(' ')),
272
+ });
273
+ }
274
+ function formatSafeDetails(details) {
275
+ if (!details)
276
+ return undefined;
277
+ const parts = [];
278
+ if (details.serviceAccountEmail) {
279
+ parts.push(`Дай доступ Google Sheets сервисному аккаунту ${details.serviceAccountEmail}.`);
280
+ }
281
+ const remediation = details.remediation;
282
+ if (typeof remediation === 'string')
283
+ parts.push(remediation);
284
+ if (Array.isArray(remediation))
285
+ parts.push(...remediation);
286
+ return parts.length > 0 ? parts.join(' ') : undefined;
85
287
  }
86
288
  function formatZodError(error) {
87
289
  return error.issues
@@ -1 +1 @@
1
- {"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/tools/result.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/tools/result.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** Короткий человекочитаемый заголовок для MCP-хоста из уже локализованного описания. */
2
+ export declare function toolTitle(description: string): string;
@@ -0,0 +1,12 @@
1
+ const TITLE_MAX_LENGTH = 80;
2
+ /** Короткий человекочитаемый заголовок для MCP-хоста из уже локализованного описания. */
3
+ export function toolTitle(description) {
4
+ const sentences = description.split(/(?<=[.!?])\s+/u);
5
+ const source = sentences.find((sentence) => /[А-Яа-яЁё]/u.test(sentence)) ?? description;
6
+ const normalized = source.replace(/[.!?]+$/u, '').trim();
7
+ if (normalized.length <= TITLE_MAX_LENGTH) {
8
+ return normalized;
9
+ }
10
+ return `${normalized.slice(0, TITLE_MAX_LENGTH - 1).trimEnd()}…`;
11
+ }
12
+ //# sourceMappingURL=tool-title.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-title.js","sourceRoot":"","sources":["../../src/tools/tool-title.ts"],"names":[],"mappings":"AAAA,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAE5B,yFAAyF;AACzF,MAAM,UAAU,SAAS,CAAC,WAAmB;IAC3C,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,WAAW,CAAC;IACzF,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAEzD,IAAI,UAAU,CAAC,MAAM,IAAI,gBAAgB,EAAE,CAAC;QAC1C,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC;AACnE,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { ToolDefinition } from './definitions/shared.js';
2
+ export declare const TOOLSETS_ENV = "BESALES_MCP_TOOLSETS";
3
+ /**
4
+ * Профиль «только чтение»: пересекается с доменными группами, поэтому имя выделено.
5
+ * Состав выводится из уже объявленного `sideEffect`, а не из отдельного списка: список
6
+ * пришлось бы вести руками, и он бы отстал от первого же нового инструмента.
7
+ */
8
+ export declare const READ_ONLY_TOOLSET = "readonly";
9
+ /**
10
+ * Доменная группа инструмента — второй токен имени (`besales_<группа>_...`).
11
+ *
12
+ * ⚠️ Выводится, а не объявляется. Рукописный реестр «инструмент → группа» пришлось бы
13
+ * пополнять при каждом добавлении, и забытая строка тихо выкидывала бы новый инструмент
14
+ * из всех профилей: он переставал бы существовать для тех, кто выбрал группу.
15
+ */
16
+ export declare function toolsetOf(toolName: string): string;
17
+ /**
18
+ * Разбор объявления профилей. `null` — ограничения нет (значение по умолчанию и
19
+ * обязательное поведение при пустой переменной: молча урезать поверхность нельзя).
20
+ */
21
+ export declare function parseToolsets(raw: string | undefined): readonly string[] | null;
22
+ /**
23
+ * Пропускает ли выбранный набор профилей этот инструмент.
24
+ *
25
+ * ⛔ Фильтр применяется и к перечислению, и к вызову. Профиль, который только прячет, —
26
+ * декорация: хост, знающий имя, всё равно позовёт скрытое, а именно от такого вызова
27
+ * профиль и заводится. Аннотации этого не закрывают: они подсказка, а не запрет.
28
+ */
29
+ export declare function isToolAllowed(definition: Pick<ToolDefinition<unknown>, 'name' | 'sideEffect'>, toolsets: readonly string[] | null): boolean;
30
+ /**
31
+ * Проверяет, что каждое объявленное имя профиля кому-то соответствует.
32
+ *
33
+ * ⛔ Опечатка в объявлении не должна давать пустую или урезанную поверхность молча: хост
34
+ * покажет «инструментов нет», и это будет выглядеть поломкой моста, а не опечаткой в
35
+ * настройке. Поэтому отказ громкий и с перечнем доступных имён.
36
+ */
37
+ export declare function assertKnownToolsets(definitions: readonly Pick<ToolDefinition<unknown>, 'name' | 'sideEffect'>[], toolsets: readonly string[] | null): void;
@@ -0,0 +1,64 @@
1
+ export const TOOLSETS_ENV = 'BESALES_MCP_TOOLSETS';
2
+ /**
3
+ * Профиль «только чтение»: пересекается с доменными группами, поэтому имя выделено.
4
+ * Состав выводится из уже объявленного `sideEffect`, а не из отдельного списка: список
5
+ * пришлось бы вести руками, и он бы отстал от первого же нового инструмента.
6
+ */
7
+ export const READ_ONLY_TOOLSET = 'readonly';
8
+ /**
9
+ * Доменная группа инструмента — второй токен имени (`besales_<группа>_...`).
10
+ *
11
+ * ⚠️ Выводится, а не объявляется. Рукописный реестр «инструмент → группа» пришлось бы
12
+ * пополнять при каждом добавлении, и забытая строка тихо выкидывала бы новый инструмент
13
+ * из всех профилей: он переставал бы существовать для тех, кто выбрал группу.
14
+ */
15
+ export function toolsetOf(toolName) {
16
+ const parts = toolName.split('_');
17
+ return parts.length > 2 ? parts[1] : toolName;
18
+ }
19
+ /**
20
+ * Разбор объявления профилей. `null` — ограничения нет (значение по умолчанию и
21
+ * обязательное поведение при пустой переменной: молча урезать поверхность нельзя).
22
+ */
23
+ export function parseToolsets(raw) {
24
+ const requested = (raw ?? '')
25
+ .split(',')
26
+ .map((entry) => entry.trim().toLowerCase())
27
+ .filter((entry) => entry.length > 0);
28
+ return requested.length > 0 ? requested : null;
29
+ }
30
+ /**
31
+ * Пропускает ли выбранный набор профилей этот инструмент.
32
+ *
33
+ * ⛔ Фильтр применяется и к перечислению, и к вызову. Профиль, который только прячет, —
34
+ * декорация: хост, знающий имя, всё равно позовёт скрытое, а именно от такого вызова
35
+ * профиль и заводится. Аннотации этого не закрывают: они подсказка, а не запрет.
36
+ */
37
+ export function isToolAllowed(definition, toolsets) {
38
+ if (toolsets === null) {
39
+ return true;
40
+ }
41
+ if (toolsets.includes(READ_ONLY_TOOLSET) && definition.sideEffect === 'none') {
42
+ return true;
43
+ }
44
+ return toolsets.includes(toolsetOf(definition.name));
45
+ }
46
+ /**
47
+ * Проверяет, что каждое объявленное имя профиля кому-то соответствует.
48
+ *
49
+ * ⛔ Опечатка в объявлении не должна давать пустую или урезанную поверхность молча: хост
50
+ * покажет «инструментов нет», и это будет выглядеть поломкой моста, а не опечаткой в
51
+ * настройке. Поэтому отказ громкий и с перечнем доступных имён.
52
+ */
53
+ export function assertKnownToolsets(definitions, toolsets) {
54
+ if (toolsets === null) {
55
+ return;
56
+ }
57
+ const known = new Set([READ_ONLY_TOOLSET, ...definitions.map((one) => toolsetOf(one.name))]);
58
+ const unknown = toolsets.filter((name) => !known.has(name));
59
+ if (unknown.length === 0) {
60
+ return;
61
+ }
62
+ throw new Error(`${TOOLSETS_ENV}: неизвестные профили ${unknown.join(', ')}. Доступные: ${[...known].sort().join(', ')}`);
63
+ }
64
+ //# sourceMappingURL=toolsets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolsets.js","sourceRoot":"","sources":["../../src/tools/toolsets.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAEnD;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAElC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAE,KAAK,CAAC,CAAC,CAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC5D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAuB;IACnD,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC;SAC1B,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;SAC1C,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEvC,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAC3B,UAAgE,EAChE,QAAkC;IAElC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,UAAU,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC;QAC7E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,WAA4E,EAC5E,QAAkC;IAElC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO;IACT,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,iBAAiB,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7F,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO;IACT,CAAC;IAED,MAAM,IAAI,KAAK,CACb,GAAG,YAAY,yBAAyB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACzG,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function deriveVerifyToolName(toolName: string, knownToolNames: ReadonlySet<string>): string | undefined;
2
+ export declare function resolveVerifyToolName(definition: {
3
+ readonly name: string;
4
+ readonly verifyWithToolName?: string;
5
+ }, knownToolNames: ReadonlySet<string>): string | undefined;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Чем свериться после неоднозначного исхода: имя выводится из имени самого инструмента.
3
+ *
4
+ * ⚠️ Выводится, а не перечисляется. Рукописная таблица «операция → проверка» отстала бы от
5
+ * первого же нового асинхронного инструмента, и он молча остался бы без указания, чем
6
+ * проверить, — ровно там, где цена ошибки максимальна. Пара, которую вывести нельзя,
7
+ * объявляется полем `verifyWithToolName` у самого определения и имеет приоритет.
8
+ */
9
+ const ASYNC_STARTER_SUFFIXES = [
10
+ '_init',
11
+ '_start',
12
+ '_import',
13
+ '_execute',
14
+ '_request',
15
+ ];
16
+ export function deriveVerifyToolName(toolName, knownToolNames) {
17
+ for (const suffix of ASYNC_STARTER_SUFFIXES) {
18
+ if (!toolName.endsWith(suffix)) {
19
+ continue;
20
+ }
21
+ const candidate = `${toolName.slice(0, -suffix.length)}_status`;
22
+ if (knownToolNames.has(candidate)) {
23
+ return candidate;
24
+ }
25
+ }
26
+ return undefined;
27
+ }
28
+ export function resolveVerifyToolName(definition, knownToolNames) {
29
+ if (definition.verifyWithToolName) {
30
+ return knownToolNames.has(definition.verifyWithToolName)
31
+ ? definition.verifyWithToolName
32
+ : undefined;
33
+ }
34
+ return deriveVerifyToolName(definition.name, knownToolNames);
35
+ }
36
+ //# sourceMappingURL=verify-with.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-with.js","sourceRoot":"","sources":["../../src/tools/verify-with.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,sBAAsB,GAAG;IAC7B,OAAO;IACP,QAAQ;IACR,SAAS;IACT,UAAU;IACV,UAAU;CACF,CAAC;AAEX,MAAM,UAAU,oBAAoB,CAClC,QAAgB,EAChB,cAAmC;IAEnC,KAAK,MAAM,MAAM,IAAI,sBAAsB,EAAE,CAAC;QAC5C,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/B,SAAS;QACX,CAAC;QACD,MAAM,SAAS,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;QAChE,IAAI,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAClC,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,UAA2E,EAC3E,cAAmC;IAEnC,IAAI,UAAU,CAAC,kBAAkB,EAAE,CAAC;QAClC,OAAO,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,kBAAkB,CAAC;YACtD,CAAC,CAAC,UAAU,CAAC,kBAAkB;YAC/B,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IACD,OAAO,oBAAoB,CAAC,UAAU,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;AAC/D,CAAC"}