@besales/mcp 0.1.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +272 -17
  2. package/dist/auth/connection-store.d.ts +58 -0
  3. package/dist/auth/connection-store.js +208 -0
  4. package/dist/auth/connection-store.js.map +1 -0
  5. package/dist/auth/oauth-client.d.ts +27 -2
  6. package/dist/auth/oauth-client.js +62 -11
  7. package/dist/auth/oauth-client.js.map +1 -1
  8. package/dist/auth/session-workspace.d.ts +2 -0
  9. package/dist/auth/session-workspace.js +20 -0
  10. package/dist/auth/session-workspace.js.map +1 -0
  11. package/dist/auth/token-storage.d.ts +19 -5
  12. package/dist/auth/token-storage.js +11 -6
  13. package/dist/auth/token-storage.js.map +1 -1
  14. package/dist/cli.d.ts +2 -7
  15. package/dist/cli.js +111 -33
  16. package/dist/cli.js.map +1 -1
  17. package/dist/http/api-client.d.ts +4 -13
  18. package/dist/http/api-client.js +18 -18
  19. package/dist/http/api-client.js.map +1 -1
  20. package/dist/index.d.ts +8 -6
  21. package/dist/index.js +3 -2
  22. package/dist/index.js.map +1 -1
  23. package/dist/instructions/server-instructions.d.ts +15 -0
  24. package/dist/instructions/server-instructions.js +245 -0
  25. package/dist/instructions/server-instructions.js.map +1 -0
  26. package/dist/package-metadata.js +7 -1
  27. package/dist/package-metadata.js.map +1 -1
  28. package/dist/resources/concepts/feedback-sheets.md +77 -0
  29. package/dist/resources/concepts/sandbox.md +13 -0
  30. package/dist/resources/concepts/workbook-classification.md +241 -0
  31. package/dist/resources/docs/agent-behavior.md +393 -0
  32. package/dist/resources/docs/crm-integration.md +535 -0
  33. package/dist/resources/docs/files-and-uploads.md +295 -0
  34. package/dist/resources/docs/knowledge-base.md +521 -0
  35. package/dist/resources/docs/pipeline-builder.md +221 -0
  36. package/dist/resources/docs/pipeline-settings-deep.md +221 -0
  37. package/dist/resources/docs/platforms.md +513 -0
  38. package/dist/resources/docs/prompt-anatomy.md +298 -0
  39. package/dist/resources/docs/prompt-principles.md +390 -0
  40. package/dist/resources/registry.js +34 -12
  41. package/dist/resources/registry.js.map +1 -1
  42. package/dist/resources/workflows/compare-models.md +46 -0
  43. package/dist/resources/workflows/connect-crm-from-scratch.md +89 -0
  44. package/dist/resources/workflows/connect-datasource-from-scratch.md +92 -0
  45. package/dist/resources/workflows/extract-from-document.md +36 -0
  46. package/dist/resources/workflows/iterate-with-sandbox.md +31 -0
  47. package/dist/resources/workflows/platform-setup-from-scratch.md +113 -0
  48. package/dist/resources/workflows/production-readiness-check.md +41 -0
  49. package/dist/schemas/mcp-tools.json +2638 -184
  50. package/dist/server.js +2 -0
  51. package/dist/server.js.map +1 -1
  52. package/dist/tools/definitions/agent-design.d.ts +215 -0
  53. package/dist/tools/definitions/agent-design.js +644 -0
  54. package/dist/tools/definitions/agent-design.js.map +1 -0
  55. package/dist/tools/definitions/crm-platform.d.ts +211 -0
  56. package/dist/tools/definitions/crm-platform.js +1070 -0
  57. package/dist/tools/definitions/crm-platform.js.map +1 -0
  58. package/dist/tools/definitions/datasource.d.ts +40 -0
  59. package/dist/tools/definitions/datasource.js +196 -0
  60. package/dist/tools/definitions/datasource.js.map +1 -0
  61. package/dist/tools/definitions/knowledge.d.ts +215 -0
  62. package/dist/tools/definitions/knowledge.js +782 -0
  63. package/dist/tools/definitions/knowledge.js.map +1 -0
  64. package/dist/tools/definitions/model-comparison.d.ts +25 -0
  65. package/dist/tools/definitions/model-comparison.js +101 -0
  66. package/dist/tools/definitions/model-comparison.js.map +1 -0
  67. package/dist/tools/definitions/platform-setup.d.ts +412 -0
  68. package/dist/tools/definitions/platform-setup.js +741 -0
  69. package/dist/tools/definitions/platform-setup.js.map +1 -0
  70. package/dist/tools/definitions/session.d.ts +11 -0
  71. package/dist/tools/definitions/session.js +86 -0
  72. package/dist/tools/definitions/session.js.map +1 -0
  73. package/dist/tools/definitions/shared.d.ts +742 -0
  74. package/dist/tools/definitions/shared.js +773 -0
  75. package/dist/tools/definitions/shared.js.map +1 -0
  76. package/dist/tools/definitions.d.ts +873 -88
  77. package/dist/tools/definitions.js +14 -856
  78. package/dist/tools/definitions.js.map +1 -1
  79. package/dist/tools/registry.d.ts +3 -1
  80. package/dist/tools/registry.js +90 -11
  81. package/dist/tools/registry.js.map +1 -1
  82. package/dist/tools/result.d.ts +1 -1
  83. package/dist/tools/result.js +12 -4
  84. package/dist/tools/result.js.map +1 -1
  85. package/dist/utils/logger.js +2 -1
  86. package/dist/utils/logger.js.map +1 -1
  87. package/docs/host-setup.md +34 -15
  88. package/package.json +2 -2
  89. package/scripts/install-claude-desktop.js +89 -11
  90. package/scripts/mock-api-server.js +1 -1
  91. package/scripts/mock-credentials.js +49 -6
  92. package/dist/types/api-contract.gen.d.ts +0 -6975
  93. package/dist/types/api-contract.gen.js +0 -6
  94. package/dist/types/api-contract.gen.js.map +0 -1
@@ -0,0 +1,77 @@
1
+ # Google Sheets Feedback Integration
2
+
3
+ Владелец платформы может привязать к промпту агента Google Sheets-таблицу, в которой
4
+ тестировщики оставляют замечания о работе агента. Ты читаешь эти замечания и предлагаешь
5
+ правки промпта.
6
+
7
+ ## Инструменты
8
+
9
+ - `besales_feedback_sheet_link` — привязать таблицу к промпту агента по ссылке.
10
+ - `besales_feedback_sheet_list` — список таблиц, привязанных к агенту.
11
+ - `besales_feedback_sheet_read` — прочитать строки замечаний.
12
+ - `besales_feedback_sheet_unlink` — отвязать таблицу от агента.
13
+ - `besales_feedback_sheet_row_update` — отметить статус строк в таблице (editable).
14
+
15
+ ## Когда привязывать
16
+
17
+ Если пользователь прислал ссылку на Google Sheet (`docs.google.com/spreadsheets/...`) с
18
+ замечаниями и хочет, чтобы они учитывались в промпте — вызови `besales_feedback_sheet_link`
19
+ с `agent_id` нужного агента и `source_url`. Один файл можно привязать к нескольким промптам:
20
+ повторный вызов с другим `agent_id` создаёт ещё одну привязку, дубликата файла не возникает.
21
+
22
+ В ответе придёт `serviceAccountEmail` — попроси пользователя расшарить таблицу на этот email
23
+ (Viewer достаточно для чтения). Без расшаривания чтение вернёт ошибку доступа.
24
+
25
+ Поддерживаются только нативные Google Sheets. Ссылка на `.xlsx`/`.csv` в Google Drive вернёт
26
+ ошибку — попроси пользователя открыть файл как Google Sheet.
27
+
28
+ ## Когда читать
29
+
30
+ Перед тем как улучшать промпт по замечаниям тестировщиков, вызови
31
+ `besales_feedback_sheet_list` для агента — узнать, есть ли привязанные таблицы. Затем для
32
+ каждой таблицы вызови `besales_feedback_sheet_read` по её `feedbackSheet.id`. Tool вернёт
33
+ распарсенные строки (`headers` + `rows` с `rowNumber`, `rowHash`, `cells`). Не проси
34
+ содержимое таблицы у пользователя вручную — оно уже доступно через эти tools.
35
+
36
+ ## Режимы — различай по `accessMode`
37
+
38
+ **`READ_ONLY`** — у тебя нет прав на запись в файл. Воркфлоу:
39
+ 1. `besales_feedback_sheet_read` → проанализируй замечания, сгруппируй по смыслу.
40
+ 2. Сформулируй конкретные правки промпта.
41
+ 3. `besales_prompt_iterate_get_instructions` — замечания тестировщиков положи в
42
+ `feedback.general_comments` и `feedback.selections`.
43
+ 4. Локально выполни stages → `besales_prompt_iterate_submit` → покажи пользователю preview.
44
+ 5. **Дождись подтверждения пользователя** → `besales_prompt_finalize`.
45
+
46
+ Никогда не финализируй промпт без явного согласия пользователя. В файл при `READ_ONLY`
47
+ ничего не пиши — доступа нет.
48
+
49
+ **`EDITABLE`** — у тебя есть права на запись. Воркфлоу тот же по части правки промпта, плюс
50
+ после обработки замечаний отметь их статус прямо в таблице через
51
+ `besales_feedback_sheet_row_update`:
52
+
53
+ 1. Для каждой обработанной строки передай `row_number`, `row_hash` (из последнего
54
+ `besales_feedback_sheet_read`), `status` (`done` / `in_progress` / `wont_fix` /
55
+ `needs_clarification`) и при необходимости `comment` («что сделано / что не хватает»).
56
+ 2. Backend запишет статус и комментарий в служебные колонки и подсветит строку светлой
57
+ заливкой (зелёная — done, жёлтая — needs_clarification, голубая — in_progress, серая —
58
+ wont_fix).
59
+ 3. Если строки таблицы сдвинулись между чтением и записью — придёт ошибка `409`. Перечитай
60
+ таблицу через `besales_feedback_sheet_read` и повтори с актуальными `row_hash`.
61
+
62
+ Если запись недоступна (service account не настроен) — `besales_feedback_sheet_row_update`
63
+ вернёт понятную ошибку «запись недоступна, доступно только чтение». В этом случае работай в
64
+ read-only режиме: читай замечания и предлагай правки промпта, статусы в файл не пиши.
65
+
66
+ ## Безопасность
67
+
68
+ - Не вписывай в комментарии к таблице секреты, токены или ключи.
69
+ - Не меняй ячейки с исходными замечаниями тестировщиков — пиши только в служебные колонки
70
+ статуса/комментария.
71
+ - Если `besales_feedback_sheet_read` вернул ошибку доступа — таблица не расшарена на service
72
+ account. Сообщи пользователю email из ответа `link` и попроси выдать доступ.
73
+
74
+ ## Отвязка
75
+
76
+ Если пользователь просит перестать учитывать таблицу для промпта — `besales_feedback_sheet_unlink`.
77
+ Это убирает только привязку к этому агенту; для других промптов таблица продолжит работать.
@@ -12,6 +12,19 @@ Sandbox в Besales — это контролируемый прогон аген
12
12
  4. Локально выполнить stages: сгруппировать проблемы, оценить severity, предложить улучшения.
13
13
  5. Отправить результат через `besales_sandbox_findings_submit`.
14
14
 
15
+ ## Режимы клиента: scripted и simulated
16
+
17
+ Прогон поддерживает два режима клиента (`options.client_mode`):
18
+
19
+ - **`scripted`** (по умолчанию) — реплики клиента берутся из заранее записанных `situations` сценария и проигрываются дословно. Детерминировано — годится для regression-проверок «не сломал ли промпт известный кейс».
20
+ - **`simulated`** — backend-LLM отыгрывает персону из ICP: видит ответ агента и генерит следующую реплику клиента вживую. Диалог адаптивный и реалистичный, но **недетерминированный** — для regression-diff не подходит, годится для охвата и проверки отработки возражений.
21
+
22
+ Один прогон = один режим. «Прогнать оба режима» = два вызова `besales_sandbox_run_start`.
23
+
24
+ **Правило для Claude:** когда пользователь просит «запусти sandbox / прогон», сначала **уточни режим** — scripted, simulated или оба (по умолчанию предлагай оба). Молча режим не выбирай. Заодно уместно уточнить охват сценариев (все или часть).
25
+
26
+ В findings: если симулированный клиент ушёл с `outcome: refused` или `endReason: gave_up` — это не автоматически провал агента; оценивай по тексту диалога.
27
+
15
28
  Sandbox не должен обращаться к реальным channel adapters и не должен создавать внешние side effects. Если сценарий требует проверки CRM или отправки сообщений, backend должен использовать sandbox adapters/ports или mock behavior.
16
29
 
17
30
  Практическое правило: sandbox — это безопасная проверка качества агента. Claude должен использовать его перед финализацией рискованных prompt changes, особенно если ICP содержит несколько сегментов или есть новые handoff/routing правила.
@@ -0,0 +1,241 @@
1
+ # Workbook Ingestion & Classification (v1.5)
2
+
3
+ Заказчик присылает многотабличный xlsx или Google Sheets — например, файл
4
+ «Сухбатлар тахлили 100+100» от компании ASLZAR с 7 вкладками: индекс диалогов
5
+ с гиперссылками на amoCRM, выборка «Хорошие/Плохие разговоры» с оценками,
6
+ вкладка «Критерии общения» с правилами для оператора, толстая вкладка
7
+ «Регламенты продаж» с описанием товаров, и т.д.
8
+
9
+ Твоя задача — открыть источник, классифицировать **каждую вкладку** по типу
10
+ содержимого и разложить её в правильный слой системы (промпт / facts /
11
+ KnowledgeDocument / ICP samples). Структура файла у разных заказчиков
12
+ **разная** — не предполагай фиксированный schema, классификируй по содержимому.
13
+
14
+ ## Архитектурные слои
15
+
16
+ | Слой | Где хранится | Что туда кладётся | Когда применяется |
17
+ |---|---|---|---|
18
+ | **A. Поведение** | `AgentChat.baseSystemPrompt` | компактные правила (1–5k chars) | каждый запрос |
19
+ | **B. Активные факты** | `AgentChat.factualContext` (≤2K токенов) | компактное продуктовое знание | каждый запрос |
20
+ | **C. Сырое знание** | `KnowledgeDocument` + chunks + Pinecone | бульк-знание (>8k) | через RAG, когда namespace привязан к агенту |
21
+ | **D. Provenance** | `SourceWorkbook` | исходный xlsx/GS + классификация | metadata, audit |
22
+
23
+ Цель: **A и B** — компактные, разумные по размеру; **C** — куда уезжает всё
24
+ большое, чтобы не раздувать каждый запрос. **D** хранит исходник чтобы
25
+ можно было пересмотреть классификацию без повторной загрузки от пользователя.
26
+
27
+ ## Шаг 1 — Загрузка файла (только для xlsx)
28
+
29
+ Для Google Sheets — сразу шаг 2 с URL.
30
+
31
+ Для xlsx:
32
+ 1. Залей файл через **существующий files endpoint** (`POST /api/v2/files` с
33
+ multipart) — это **не** workbook MCP tool, это общий files upload.
34
+ 2. В ответе получишь `storedFileId`.
35
+
36
+ Сам workbook MCP **не** загружает файлы — он только инспектирует уже
37
+ загруженные. Это разделение позволяет переиспользовать SourceWorkbook для
38
+ повторных inspect'ов того же файла.
39
+
40
+ ## Шаг 2 — Inspect
41
+
42
+ ```
43
+ besales_workbook_inspect({
44
+ stored_file_id?: <uuid>,
45
+ google_sheets_url?: <url>,
46
+ sample_rows_per_sheet?: 10,
47
+ max_cells_total?: 500,
48
+ })
49
+ ```
50
+
51
+ В ответе:
52
+ - `workbook` — создан `SourceWorkbook` record;
53
+ - `sheets[]` — для каждой вкладки: `sheetTitle`, `rowCount`, `columnCount`,
54
+ `sampleRows[][]` (per-cell `value` + `hyperlink` + `formula`),
55
+ `hyperlinkStats[]` (per-column число amoCRM lead/contact ссылок),
56
+ `truncated` (применён ли лимит).
57
+
58
+ **Если Google Sheets вернул 403 (`error: google_sheets_not_shared`)** — покажи
59
+ пользователю `serviceAccountEmail` из response и попроси расшарить таблицу
60
+ на этот email (Viewer достаточно для чтения). Без этого никакие операции не
61
+ будут работать.
62
+
63
+ ## Шаг 3 — Классификация (твоя голова)
64
+
65
+ Для каждой вкладки определи `detectedKind` по содержимому. Известные типы и
66
+ куда направлять:
67
+
68
+ | `detectedKind` | Когда подходит | → Назначение |
69
+ |---|---|---|
70
+ | `dialogue_corpus_with_amocrm_links` | колонка содержит много amoCRM URL'ов (см. `hyperlinkStats`), есть метки оператора/статуса/оценки | regex'ом извлеки `leadId`'ы → `besales_icp_import_dialogues mode=audio audio_source_type=amocrm_leads` |
71
+ | `dialogue_corpus_text_only` | список диалогов без аудио-ссылок (например, готовые транскрипты) | `besales_icp_import_dialogues mode=text` (если CRM подключён) или ручная подготовка IcpDialogueSample'ов |
72
+ | `behavior_rules` | правила, критерии общения, скрипты, чек-листы | секция системного промпта через `besales_prompt_generate_get_instructions` (передай содержимое в `businessContext`) |
73
+ | `product_knowledge_compact` | компактное (≤8k chars) знание о продукте, политике | **ты сам делаешь LLM-выжимку в markdown** → `besales_agent_facts_set` (существующий tool, НЕ workbook-tool) |
74
+ | `product_knowledge_bulk` | объёмное (>8k) знание (история, описания товаров, регламенты) | `besales_workbook_to_knowledge_document` |
75
+ | `qa_pairs` | строки в формате «Вопрос → Ответ» | `besales_workbook_to_knowledge_document` (heuristic сам выберет Q&A split) |
76
+ | `followup_sequence` | последовательность сообщений с тайм-задержками | `besales_followup_sequence_upsert` |
77
+ | `tester_feedback` | построчные замечания тестировщиков к промпту | `besales_feedback_sheet_link` (привязка конкретной вкладки) |
78
+ | `metadata_summary` | сводка/dashboard со статистикой | игнор, пометить в `classification` |
79
+ | `tasks_log` | мета-вкладка типа «что нужно подготовить» | игнор |
80
+ | `unknown` | не подходит ни под одну категорию | спроси у пользователя через `AskUserQuestion` с 2-3 вариантами |
81
+
82
+ **Одна вкладка может попасть в несколько kind'ов одновременно.** Пример:
83
+ «Хорошие разговоры» = `dialogue_corpus_with_amocrm_links` (для audio import) +
84
+ `tester_feedback` (Изох-колонка с комментариями рецензента). Делай обе вещи.
85
+
86
+ ## Шаг 4 — Распознавай параллельные колонки
87
+
88
+ Если в `behavior_rules` вкладке видишь **2 структурно-параллельные колонки**
89
+ (например, в ASLZAR-файле «Sotuv mezonlari» / «Qayta qo'ng'iroq mezonlari» —
90
+ правила первого звонка vs правила повторного), это **сильный сигнал** что
91
+ нужно сделать:
92
+
93
+ - 2 агента — по одному на каждую колонку;
94
+ - роутер на trigger:
95
+ - агент A (Sotuv) → срабатывает на новый лид / inbound;
96
+ - агент B (Qayta qo'ng'iroq) → срабатывает на noresponse > N дней / outbound.
97
+
98
+ Перед тем как создавать — спроси пользователя через `AskUserQuestion`:
99
+ «Я вижу 2 параллельных набора правил. Хочешь 1 универсального агента или
100
+ 2 + router?». По его ответу — либо `besales_agent_create` + `besales_router_update`
101
+ + `besales_trigger_upsert`, либо склей в один промпт.
102
+
103
+ ## Шаг 5 — Извлечение lead_ids из диалог-индекса (regex локально)
104
+
105
+ Для `dialogue_corpus_with_amocrm_links` — **не зови отдельный MCP tool**. Данные
106
+ уже в `inspect` response (`sampleRows[][]`). Прогони regex по `cell.value`,
107
+ `cell.hyperlink`, `cell.formula`:
108
+
109
+ ```
110
+ /https?:\/\/[\w-]+\.amocrm\.ru\/leads\/detail\/(\d+)/ → leadId
111
+ /https?:\/\/[\w-]+\.amocrm\.ru\/contacts\/detail\/(\d+)/ → contactId
112
+ ```
113
+
114
+ Поддерживается любой amoCRM поддомен (`aslzar`, `acme-crm`, и т.д.). Если в
115
+ inspect-sample слишком мало строк — попроси `inspect` повторно с большим
116
+ `sample_rows_per_sheet` (до 50). Если и этого мало — обрати внимание что для
117
+ больших таблиц извлечение в полном объёме сейчас не покрыто отдельным
118
+ helper-tool'ом; в Phase 1 это покрывается доступным sample'ом.
119
+
120
+ ## Шаг 6 — `besales_workbook_to_knowledge_document` (bulk knowledge)
121
+
122
+ ```
123
+ besales_workbook_to_knowledge_document({
124
+ workbook_id: <uuid>,
125
+ sheet_title?: "Регламенты продаж",
126
+ // или sheet_gid (для GS), или sheet_index (для xlsx)
127
+ namespace?: "aslzar-product-knowledge",
128
+ split_override?: { ... }, // опционально, иначе heuristic
129
+ replace_existing?: true, // по умолчанию true (idempotency)
130
+ })
131
+ ```
132
+
133
+ Sheet identifier (`sheet_title` / `sheet_gid` / `sheet_index`) — **в body, не в
134
+ path** (потому что названия вкладок содержат кириллицу и пробелы).
135
+
136
+ Сервер сам выбирает `splitMode` через эвристику:
137
+ 1. Q&A структура (≥3 пар Q:/A:) → separator `\n\n`, maxChunkSize 800
138
+ 2. Markdown headers (≥2 строк `^## `) → separator `\n## `, maxChunkSize 1500
139
+ 3. `===` / `---` разделители → separator, maxChunkSize 1500
140
+ 4. Параграфы (≥3 блоков `\n\n` avg ≥200 chars) → separator `\n\n`, maxChunkSize 1200
141
+ 5. Пронумерованные секции (≥3 строк `^\d+[.)]`) → separator `\n\n`, maxChunkSize 1200
142
+ 6. Fallback → fixed_size, chunkSize 1000, overlap 200
143
+
144
+ В ответе `splitDecision.reason` — почему выбран этот режим (для отладки).
145
+ Если знаешь лучше — передай `split_override`.
146
+
147
+ **Idempotency**: повторный вызов для того же `(workbook, sheet)` заменяет
148
+ существующий AI_INGESTED документ (удаляет старые chunks + Pinecone vectors).
149
+ По умолчанию `replace_existing: true` — отключи только если знаешь зачем.
150
+
151
+ После создания документа — **привяжи knowledge_space к агенту** через
152
+ `besales_agent_update` (поле `knowledge_space_ids` — массив UUID, полученных из
153
+ `besales_knowledge_space_list` или ответа `besales_workbook_to_knowledge_document`),
154
+ иначе агент не увидит namespace даже когда RAG будет включён.
155
+
156
+ ## Шаг 7 — Compact knowledge → factualContext (твоя голова + facts_set)
157
+
158
+ Для `product_knowledge_compact` НЕ зови `besales_workbook_to_knowledge_document`.
159
+ Вместо этого:
160
+
161
+ 1. Прочитай sample вкладки из `inspect` response.
162
+ 2. Сам сделай LLM-выжимку: возьми ключевые факты, сожми в markdown ≤8k chars.
163
+ Формат:
164
+ ```
165
+ ## Active facts
166
+ - факт 1
167
+ - факт 2
168
+ - ...
169
+ ```
170
+ 3. Вызови существующий `besales_agent_facts_set` с этой выжимкой.
171
+
172
+ Это **другой** MCP tool, не workbook. Не путай.
173
+
174
+ ## Шаг 8 — Зафиксируй классификацию
175
+
176
+ После того как все вкладки разобраны:
177
+
178
+ ```
179
+ PATCH /api/v2/workspaces/:wsId/workbooks/:id/classification
180
+ body: {
181
+ classification: [
182
+ { sheetTitle: "Свод", detectedKind: "metadata_summary", destination: "ignored" },
183
+ { sheetTitle: "Все разговоры", detectedKind: "dialogue_corpus_with_amocrm_links",
184
+ destination: "icp_import", mappedEntityId: "<icp-run-id>", notes: "124 leadId извлечено" },
185
+ { sheetTitle: "Критерии общения", detectedKind: "behavior_rules",
186
+ destination: "prompt", notes: "2 параллельные колонки → 2 агента + router" },
187
+ { sheetTitle: "Регламенты продаж", detectedKind: "product_knowledge_bulk",
188
+ destination: "knowledge_document", mappedEntityId: "<kd-id>" },
189
+ { sheetTitle: "Задачи", detectedKind: "tasks_log", destination: "ignored" }
190
+ ]
191
+ }
192
+ ```
193
+
194
+ Это даёт audit trail («откуда взялся этот факт») и позволяет потом
195
+ переразложить при необходимости.
196
+
197
+ ## Шаг 9 — Архивация (когда больше не нужен)
198
+
199
+ `POST /api/v2/workspaces/:wsId/workbooks/:id/archive` — soft delete.
200
+ KnowledgeDocument'ы остаются (благодаря `onDelete: SetNull`), просто теряют
201
+ ссылку на workbook. Hard delete для SourceWorkbook не предусмотрен —
202
+ provenance не должна теряться.
203
+
204
+ ## Пример полного flow на файле ASLZAR
205
+
206
+ > Заказчик прислал `Сухбатлар тахлили 100+100-2.xlsx` (7 вкладок).
207
+
208
+ 1. User загружает xlsx через `/api/v2/files` → `storedFileId = abc123`.
209
+ 2. `besales_workbook_inspect({stored_file_id: "abc123"})` →
210
+ - `workbook.id = wb-1` создан
211
+ - 7 вкладок: Свод (6 строк), Все разговоры (435 строк), Плохие (101),
212
+ Хорошие (130), Критерии (68), Регламенты (420), Задачи (8)
213
+ - hyperlinkStats для «Все разговоры» колонка C: 124 amocrmLeads
214
+ 3. Локальная классификация в твоей голове:
215
+ - Свод → `metadata_summary` (ignore)
216
+ - Все разговоры → `dialogue_corpus_with_amocrm_links`
217
+ - Хорошие/Плохие → дополняют как `dialogue_corpus_*` с `defaultOutcome=won/lost`
218
+ - Критерии → `behavior_rules` (2 параллельные колонки!)
219
+ - Регламенты → `product_knowledge_bulk` (53k chars)
220
+ - Задачи → `tasks_log` (ignore)
221
+ 4. Regex по sampleRows[Все разговоры].column[2] → 124 leadId.
222
+ 5. `besales_icp_import_dialogues mode=audio audio_source_type=amocrm_leads` с
223
+ этими leadId.
224
+ 6. `AskUserQuestion`: «В Критериях вижу 2 параллельных набора правил (звонок 1
225
+ vs повторный звонок). Хочешь 1 агента или 2 + router?» → ждём ответ.
226
+ 7. По ответу: `besales_agent_create` (+роутер если 2), `besales_prompt_generate_*`
227
+ с `businessContext = текст Критериев`.
228
+ 8. `besales_workbook_to_knowledge_document({workbook_id: "wb-1",
229
+ sheet_title: "Регламенты продаж", namespace: "aslzar-product-knowledge"})`.
230
+ 9. `besales_agent_update` — добавить knowledge_space_id в `knowledge_space_ids` агента (UUID, не cleanNamespace).
231
+ 10. `PATCH /workbooks/wb-1/classification` — зафиксировать решения.
232
+
233
+ ## Что НЕ делать
234
+
235
+ - ❌ Не пытайся сам парсить xlsx — используй `besales_workbook_inspect`.
236
+ - ❌ Не запихивай **всё** в `factualContext` — 2K токенов лимит, иначе раздуешь
237
+ каждый запрос инференса. Большие материалы → в KnowledgeDocument.
238
+ - ❌ Не создавай агентов / промпты / документы без подтверждения user'а для
239
+ high-impact операций (новый агент, router rule).
240
+ - ❌ Не пытайся найти tool типа `besales_workbook_to_facts` — его нет. Compact
241
+ knowledge ты сам сжимаешь LLM-вызовом и кладёшь через `besales_agent_facts_set`.