@lionchat/mcp-server 1.5.0 → 1.7.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/dist/docs/instructions.md +2 -1
- package/dist/docs/resources/best-practices.md +61 -2
- package/dist/docs/resources/data-model.md +16 -0
- package/dist/docs/resources/filtros-e-relatorios.md +147 -0
- package/dist/docs/resources/reports-guide.md +32 -3
- package/dist/docs/resources/troubleshooting.md +33 -0
- package/dist/resources.js +6 -0
- package/dist/resources.js.map +1 -1
- package/dist/sanitize.d.ts +9 -0
- package/dist/sanitize.js +136 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/tools.js +27 -3
- package/dist/tools.js.map +1 -1
- package/dist/utils.d.ts +5 -1
- package/dist/utils.js +78 -10
- package/dist/utils.js.map +1 -1
- package/endpoints.json +428 -68
- package/package.json +1 -1
|
@@ -285,7 +285,7 @@ Antes de QUALQUER ação que escreve, modifica, apaga ou envia, pare e avalie se
|
|
|
285
285
|
|
|
286
286
|
**Sempre confirme em linguagem natural (resumindo o efeito) antes de executar quando:**
|
|
287
287
|
|
|
288
|
-
- **(a) A ação é destrutiva/irreversível** — qualquer `*_destroy`, `*_bulk_actions`, apagar contato (cascateia para as conversas dele), mudar status em massa.
|
|
288
|
+
- **(a) A ação é destrutiva/irreversível** — qualquer `*_destroy`, `*_bulk_actions`, apagar contato (cascateia para as conversas dele), mudar status em massa, cancelar reenvio de mensagem falhada (`*_cancel_retry`, `*_bulk_cancel` — a mensagem sai de todo reenvio pra sempre).
|
|
289
289
|
- **(b) Envia mensagem ao cliente final** — `lionchat_conversations_messages_create` com `message_type` outgoing, `*_scheduled_messages_*`, templates WhatsApp, campanhas/disparos.
|
|
290
290
|
- **(c) Altera config** — conta, inbox, funil, automação, IA Agente (`captain_assistants_update`).
|
|
291
291
|
- **(d) O pedido é ambíguo/incompleto** — falta ID, período, canal, destinatário, ou há mais de uma interpretação possível.
|
|
@@ -322,6 +322,7 @@ Antes de escolher a ferramenta, cheque se a intenção bate com a coluna da dire
|
|
|
322
322
|
| **Origem dos leads** (de onde vieram, por plataforma/campanha/conjunto) | `lionchat_lead_origin_reports` | Relatório de leitura; filtros `platform`/`campaign`/`adset`; `won` = cards em Ganho; leads únicos por telefone |
|
|
323
323
|
| **Bloquear/desbloquear** contato | `lionchat_conversations_toggle_block` (`blocked: true|false`) | Gera pílula de atividade e descarta mensagens futuras do contato; NÃO resolve a conversa |
|
|
324
324
|
| **Importar histórico** de caixa WhatsApp Cloud (QR) | `lionchat_inboxes_whatsapp_history_start` / `_status` / `_cancel` | Admin-only + flag `qr_history_import`; só caixa oficial. Acompanhe `state` no `_status` |
|
|
325
|
+
| Ver / limpar **falhas de envio** de uma caixa | `lionchat_inboxes_failed_messages_summary` primeiro; depois `_bulk_retry` (reenviar) ou `_bulk_cancel` (descartar) | Admin-only. Reenvio em massa e cancelamento em massa são ações irreversíveis: mostre as contagens do summary e confirme (seção 7a/7b). Numa mensagem só: `lionchat_conversations_messages_create_1` (reenviar) / `lionchat_conversations_messages_cancel_retry` (cancelar) |
|
|
325
326
|
| **Definir supervisor** de caixa | `lionchat_inbox_members_create` / `_update` com `supervisor_ids[]` | Supervisor vê TUDO da caixa mas fica fora do rodízio (ver abaixo) |
|
|
326
327
|
| Qualquer coisa de Ligação WP (Wavoip) | **NÃO HÁ TOOL** — removidas em 2026-07-16 por decisão do dono | Ligação WP é contratada e configurada **manualmente pelo cliente no painel**. O MCP não conecta, não desconecta, não entrega token de discagem nem muda config. Oriente o usuário a fazer pelo painel (Configurações da caixa → Ligação WP). |
|
|
327
328
|
| Restringir agendas que a IA oferece | `lionchat_captain_assistants_update` (`config.booking_event_type_ids: [Int]`) | binding de agenda por cenário NÃO é settable via API |
|
|
@@ -38,7 +38,8 @@ page=2 → próxima
|
|
|
38
38
|
|
|
39
39
|
O conector devolve `pagination.total_count` e `pagination.has_more` — **pagine enquanto `has_more=true`** (não pare na 1ª página). Se `has_more=false`, acabou. Não tente "paginar até zerar" quando o total já é enorme (milhões) — filtre antes.
|
|
40
40
|
|
|
41
|
-
**
|
|
41
|
+
**Respostas grandes (atualizado 2026-07-24):** o teto continua 80 mil caracteres, mas agora com 3 melhorias:
|
|
42
|
+
(1) **Slim por padrão** — listas voltam sem campos pesados/decorativos (`message_templates`, `working_hours`, avatares, `meta_history_import` viram `[omitido...]`); pra resposta completa use `full_response:true` (tools de lista/show pesadas). (2) **Corte limpo** — ao estourar o teto, a resposta é enxugada por ITENS INTEIROS com o aviso `[LISTA ENXUGADA: exibindo N de M itens...]`; o JSON nunca vem quebrado no meio. (3) **Segredos** — chaves de credencial (api_key, tokens, senhas) saem SEMPRE `[REDACTED]`, sem exceção. Se ainda aparecer `[RESPOSTA CORTADA ...]` (shape sem lista reconhecível), os dados vieram INCOMPLETOS — NÃO insista na mesma chamada: **ESTREITE** (reduza `since`/`until`, adicione filtros, use `per_page` menor, ou pagine com `page`). **Relatórios agregados** (`reports_summary`, `sla_metrics`, `csat_metrics`, `journey_funnel_reports`, `lead_origin_reports`) **NÃO paginam** — se cortar, restrinja o período. Pra CSAT em lista (`csat_list`), o total vem só no `csat_metrics` — combine os dois. Guia completo de filtros: resource `filtros-e-relatorios`.
|
|
42
43
|
|
|
43
44
|
## Cache local mental
|
|
44
45
|
|
|
@@ -146,6 +147,12 @@ Dispara quando o CLIENTE fica inativo após resposta da IA. O motor de follow-up
|
|
|
146
147
|
**só-leitura** (não executa ferramentas, não coleta dado — só redige a mensagem de retomada,
|
|
147
148
|
com saída estruturada garantida). `paused=true` no assistente corta os follow-ups também.
|
|
148
149
|
|
|
150
|
+
**Corrigido em 2026-07-24:** quando a IA é ativada por um **Flow** (ação "Ativar IA") ou por uma
|
|
151
|
+
**automação**, o follow-up agora é agendado no ato da ativação. Antes, nesses dois caminhos a
|
|
152
|
+
cadência simplesmente nunca começava — a conversa ficava com IA ativa e sem nenhum follow-up. Se um
|
|
153
|
+
cliente relatar "a IA nunca faz o follow-up", confira primeiro se a ativação veio por flow/automação
|
|
154
|
+
e se a conta já está na versão de 24/07.
|
|
155
|
+
|
|
149
156
|
## Condições para NÃO fazer follow-up + horário de silêncio (2026-07)
|
|
150
157
|
|
|
151
158
|
`config.follow_up_skip_conditions` — array de até 3 condições (lógica OU: qualquer uma verdadeira
|
|
@@ -197,6 +204,11 @@ Como a coleta de dados/cenários funciona hoje (importante pra diagnosticar "IA
|
|
|
197
204
|
- Cenários são instruções inline no prompt (sem troca de personagem); o raciocínio do cenário
|
|
198
205
|
fica no "caderninho" da conversa (campo scenario_checklist, visível no card Raciocínio).
|
|
199
206
|
- Sem AI Agente ativo na conversa = NENHUMA resposta de IA (motor V1 aposentado em 2026-06).
|
|
207
|
+
- **Corrigido em 2026-07-24:** a IA agora enxerga no prompt a lista de atributos personalizados
|
|
208
|
+
definidos de **Conversa** e de **Card do Kanban** (antes só a de Contato chegava, e mesmo essa em
|
|
209
|
+
parte) — por isso ela conseguia gravar atributo de contato mas "não funcionava" pra conversa/card.
|
|
210
|
+
Regra prática que continua valendo: só dá pra a IA preencher atributo que **existe cadastrado**
|
|
211
|
+
(`custom_attributes_create`) no modelo certo — conversa, contato ou card.
|
|
200
212
|
|
|
201
213
|
## Cenários com parâmetro fixo e execução determinística (2026-06)
|
|
202
214
|
|
|
@@ -308,7 +320,9 @@ criar a campanha e mostre a contagem ao usuário — estimativa e disparo usam o
|
|
|
308
320
|
## Variáveis de conta (account_variables)
|
|
309
321
|
|
|
310
322
|
Pra dados fixos que se repetem (slogans, endereços, horários):
|
|
311
|
-
- `account_variables_create` UMA vez — campos: `attribute_display_name` (rótulo), `attribute_key` (a chave usada no `{{ }}`), `attribute_display_type
|
|
323
|
+
- `account_variables_create` UMA vez — campos: `attribute_display_name` (rótulo), `attribute_key` (a chave usada no `{{ }}`), `attribute_display_type`, `value`. Admin-only.
|
|
324
|
+
- Tipos oferecidos na tela (2026-07-25): **Texto** (`text`), **Data** (`date`), **Hora** (`time`) e **Confidencial** (`secret`). Data e Hora gravam o valor já normalizado (`AAAA-MM-DD` e `HH:MM` em 24h) — antes a tela só tinha Texto e a data entrava como texto solto, sem validar formato. Os demais tipos do enum (`number`, `list`, `link`, `checkbox`, `currency`, `percent`, `datetime`) funcionam pela API, mas a tela os edita como texto.
|
|
325
|
+
- O **tipo e a chave não mudam depois de criados** — `account_variables_update` só altera rótulo, descrição e valor. Pra trocar o tipo, apague e crie de novo.
|
|
312
326
|
- Use em templates com a sintaxe COMPLETA `{{ account.custom_attribute.<attribute_key> }}` (ex: `{{ account.custom_attribute.slogan }}`). NÃO existe atalho `{{slogan}}` solto — sem o prefixo `account.custom_attribute.` não resolve.
|
|
313
327
|
- Resolve em: mensagens, respostas prontas, campanhas e automações. NÃO resolve nas instruções do AI Agente (base/cenário) — ali só `contact.*` e `conversation.*`.
|
|
314
328
|
- `secret` nunca aparece em template (sai vazio); só resolve em nós API Request do FlowBuilder.
|
|
@@ -359,6 +373,9 @@ Endereço: {% assign chave = "endereco_" | append: contact.custom_attribute.unid
|
|
|
359
373
|
nas instruções do AI Agente.
|
|
360
374
|
- Se a chave montada não existir, o `{% echo %}` sai vazio (sem erro). Teste com um contato
|
|
361
375
|
de cada valor da lista antes de entregar.
|
|
376
|
+
- Botão com link (CTA) da resposta pronta/flow: a URL do botão aceita variáveis
|
|
377
|
+
(`{{contact.name}}`, `{{contact.phone}}`, atributo etc.) — cada valor é codificado
|
|
378
|
+
automaticamente (espaço vira `%20`), então o link nunca quebra. Útil pra rastrear cliques.
|
|
362
379
|
|
|
363
380
|
### Padrão geral (serve pra qualquer caso)
|
|
364
381
|
|
|
@@ -409,6 +426,48 @@ Fontes/campos disponíveis (`source` / `field`):
|
|
|
409
426
|
Lembrete: todo template recém-criado pelo MCP só mostra o texto na tela depois de **sincronizar**
|
|
410
427
|
(o MCP cria na Meta, mas o "puxar de volta" o conteúdo é o que a tela faz com o botão Sincronizar).
|
|
411
428
|
|
|
429
|
+
### Botão de link do template com variável — link rastreável por cliente (2026-07-25)
|
|
430
|
+
|
|
431
|
+
O botão de URL do template pode terminar com uma variável, pra montar um link diferente por contato
|
|
432
|
+
(rastrear cliques, pré-preencher formulário, etc).
|
|
433
|
+
|
|
434
|
+
Regras da Meta (o template é recusado na hora se furar qualquer uma):
|
|
435
|
+
|
|
436
|
+
- No máximo **UMA** variável no botão, e ela é sempre `{{1}}`.
|
|
437
|
+
- `{{1}}` só pode ficar **no FINAL** da URL, com base `https://` fixa antes.
|
|
438
|
+
- O componente `BUTTONS` precisa mandar `example` com a URL completa de exemplo (sem ele, erro 100).
|
|
439
|
+
|
|
440
|
+
E o `variable_mapping` recebe a chave especial `_button_url` (com underscore na frente de propósito:
|
|
441
|
+
ela **não** conta como variável de corpo):
|
|
442
|
+
|
|
443
|
+
```json
|
|
444
|
+
{
|
|
445
|
+
"components": [
|
|
446
|
+
{ "type": "BODY", "text": "Olá {{1}}, sua proposta está pronta." ,
|
|
447
|
+
"example": { "body_text": [["Maria"]] } },
|
|
448
|
+
{ "type": "BUTTONS", "buttons": [
|
|
449
|
+
{ "type": "URL", "text": "Ver proposta",
|
|
450
|
+
"url": "https://minhaempresa.com.br/proposta?cliente={{1}}",
|
|
451
|
+
"example": ["https://minhaempresa.com.br/proposta?cliente=Maria Silva"] }
|
|
452
|
+
] }
|
|
453
|
+
],
|
|
454
|
+
"variable_mapping": {
|
|
455
|
+
"1": { "source": "contact", "field": "name.split.first", "label": "Primeiro nome" },
|
|
456
|
+
"_button_url": { "source": "contact", "field": "name", "label": "Nome completo",
|
|
457
|
+
"example": "Maria Silva", "button_index": 0 }
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
- `button_index` = a **posição do botão** dentro do componente `BUTTONS` (0 = primeiro).
|
|
463
|
+
- `source`/`field` usam a mesma tabela de fontes acima, mais `custom` (texto fixo, escrito no `field`).
|
|
464
|
+
- No envio, o valor é **codificado automaticamente** (espaço vira `%20`) — o link nunca quebra.
|
|
465
|
+
- Vale em conversa, automação, flow, agendada e campanha (na campanha resolve por contato).
|
|
466
|
+
|
|
467
|
+
O mesmo vale pro **botão de link (CTA)** de resposta pronta e do FlowBuilder: a URL aceita
|
|
468
|
+
`{{contact.name}}`, `{{contact.phone}}`, atributo personalizado etc., com a mesma codificação
|
|
469
|
+
automática. Ver a seção de variáveis de conta acima.
|
|
470
|
+
|
|
412
471
|
## FlowBuilder — notas de editor (2026-07)
|
|
413
472
|
|
|
414
473
|
- **Tipo de atributo `time` (Hora 24h):** ao criar custom attribute com `attribute_display_type: "time"` (ou o numérico `9`), o valor canônico é `"HH:MM"` 24h e o fuso mora na definição (`attribute_timezone`, IANA, default `America/Sao_Paulo`). Uso principal: alimentar o campo Horário do node `wait` (modo date, `waitTimeMode: "variable"`).
|
|
@@ -408,6 +408,22 @@ Atributos de sistema no CONTATO (prefixo `eclinica_`, protegidos, usáveis como
|
|
|
408
408
|
| `eclinica_ultimo_pagamento` | text | Valor do último pagamento |
|
|
409
409
|
| `eclinica_ultimo_pagamento_data` | date | Data do último pagamento/baixa (novo 2026-07-06) |
|
|
410
410
|
| `eclinica_ultimo_pagamento_descricao` | text | Descrição da baixa (ex: CONSULTA INICIAL) |
|
|
411
|
+
| `eclinica_laboratorio_data_prevista` | date | Previsão de entrega da medicação (novo 2026-07-23) |
|
|
412
|
+
| `eclinica_laboratorio_data_moldagem` | date | Data do pedido da medicação |
|
|
413
|
+
| `eclinica_laboratorio_data_entrega` | date | Data de entrega da medicação |
|
|
414
|
+
| `eclinica_laboratorio_situacao` | text | Situação do pedido no laboratório |
|
|
415
|
+
| `eclinica_ultima_cobranca_valor` | text | Valor da última cobrança/carnê gerado |
|
|
416
|
+
| `eclinica_ultima_cobranca_vencimento` | date | Vencimento da última cobrança |
|
|
417
|
+
| `eclinica_ultima_cobranca_descricao` | text | Descrição da última cobrança |
|
|
418
|
+
|
|
419
|
+
**Lembretes automáticos (Integrações > e-Clínica > Lembretes).** Cada linha tem um **tipo de
|
|
420
|
+
evento** que decide de qual data a contagem parte: `agendamento` (data da consulta, padrão),
|
|
421
|
+
`controle_laboratorio_novo` (previsão de entrega da medicação) e `cliente_inclusao_pagamento`
|
|
422
|
+
(vencimento da cobrança). Desde 2026-07-25 cada linha exige também uma **hora do disparo** —
|
|
423
|
+
`HH:MM` fixo ou fórmula com variável de conta/contato (ex.: horário por unidade, ou a própria hora
|
|
424
|
+
da consulta) — em vez de herdar sempre o horário da consulta. Há ainda um filtro opcional
|
|
425
|
+
("Só quando") por atributo `eclinica_*` do contato. Nada disso é editável pelo MCP: só pelo painel.
|
|
426
|
+
Pra auditar o que foi/será disparado, use `lionchat_eclinica_reminder_history_list`.
|
|
411
427
|
|
|
412
428
|
## Relatórios e Métricas
|
|
413
429
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Filtros e Relatórios — Guia Completo
|
|
2
|
+
|
|
3
|
+
Como filtrar conversas, contatos e cards do Kanban com precisão, e como montar relatórios por
|
|
4
|
+
período/atendente/etapa/valor sem tentativa e erro. Tabelas extraídas do código da plataforma
|
|
5
|
+
(2026-07-24) — operador fora da lista da chave retorna **422 "Operador inválido"**.
|
|
6
|
+
|
|
7
|
+
## Os DOIS padrões de transporte de filtro (não confundir)
|
|
8
|
+
|
|
9
|
+
| Padrão | Onde | Como enviar |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| **A — array no BODY** | `conversations_filter`, `contacts_filter`, `audience`/`exclusion` de campanhas | Array NATIVO de objetos no parâmetro (`payload`, `audience`, `exclusion`) |
|
|
12
|
+
| **B — JSON-string na QUERY** | `*_custom_attribute_filters` do Kanban, `conversation_filters`/`contact_filters`/`kanban_filters` das buscas | STRING com o JSON serializado (`"[{\"attribute_key\":...}]"`) |
|
|
13
|
+
|
|
14
|
+
Regra de bolso: ferramenta POST de filtro = array nativo; parâmetro de filtro em ferramenta GET =
|
|
15
|
+
JSON-string. NUNCA mande array-de-objetos em parâmetro de query.
|
|
16
|
+
|
|
17
|
+
## 1. Conversas — `lionchat_conversations_filter`
|
|
18
|
+
|
|
19
|
+
`payload` = array de condições `{attribute_key, filter_operator, values[], query_operator:'and'|'or',
|
|
20
|
+
custom_attribute_type?}`. Ordenação FIXA `last_activity_at DESC`, 25/página (param `page`).
|
|
21
|
+
E/OU é encadeado condição a condição (sem parênteses).
|
|
22
|
+
|
|
23
|
+
| attribute_key | Operadores |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `status` (open/resolved/pending/snoozed, aceita 'all') | equal_to, not_equal_to |
|
|
26
|
+
| `chat_type` (individual/group/channel/broadcast/status) | equal_to, not_equal_to |
|
|
27
|
+
| `priority` | equal_to, not_equal_to |
|
|
28
|
+
| `assignee_id` (atendente), `inbox_id`, `team_id`, `campaign_id`, `captain_assistant_id` (IA), `labels` | equal_to, not_equal_to, is_present, is_not_present |
|
|
29
|
+
| `display_id` | equal_to, not_equal_to, contains, does_not_contain (o `contains`, busca por trecho do número, passou a funcionar de verdade em 2026-07-25 — antes dava erro de banco) |
|
|
30
|
+
| `referer`, `mail_subject` | equal_to, not_equal_to, contains, does_not_contain |
|
|
31
|
+
| `browser_language`, `conversation_language` | equal_to, not_equal_to |
|
|
32
|
+
| `created_at`, `last_activity_at` (valor = data) | is_greater_than, is_less_than, days_before |
|
|
33
|
+
| `card_funnel_stage` (conversa POR CARD do Kanban — valor `funnel:<id>` ou `stage:<id>:<chave_etapa>`) | equal_to, not_equal_to |
|
|
34
|
+
| **qualquer outra chave** = atributo personalizado | conforme o tipo do atributo (ver tabela em api-conventions) |
|
|
35
|
+
|
|
36
|
+
Atributo personalizado: informe `custom_attribute_type` na condição — `'conversation_attribute'`
|
|
37
|
+
(atributo da conversa) ou `'contact_attribute'`. Sem ele o escopo pode sair errado.
|
|
38
|
+
|
|
39
|
+
## 2. Contatos — `lionchat_contacts_filter`
|
|
40
|
+
|
|
41
|
+
Mesmo shape de condição. 15/página.
|
|
42
|
+
|
|
43
|
+
| attribute_key | Operadores |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `id` (id interno do contato) | equal_to, not_equal_to |
|
|
46
|
+
| `name`, `email`, `identifier`, `city`, `company`, `profession` | equal_to, not_equal_to, contains, does_not_contain |
|
|
47
|
+
| `phone_number` | + starts_with |
|
|
48
|
+
| `cpf`, `cnpj`, `rg` (cadastral) | equal_to, not_equal_to, contains, does_not_contain, is_present, is_not_present |
|
|
49
|
+
| `country_code` | equal_to, not_equal_to |
|
|
50
|
+
| `labels` | equal_to, not_equal_to, is_present, is_not_present |
|
|
51
|
+
| `created_at`, `last_activity_at` | is_greater_than, is_less_than, days_before |
|
|
52
|
+
| `blocked` | equal_to, not_equal_to |
|
|
53
|
+
| **qualquer outra chave** = atributo personalizado do contato | conforme o tipo |
|
|
54
|
+
|
|
55
|
+
**Registros vinculados** (acha o contato pelo que aconteceu com ele):
|
|
56
|
+
- `conversation_status`, `conversation_inbox_id` (equal_to/not_equal_to), `conversation_labels`
|
|
57
|
+
(+is_present/is_not_present) — conversa vinculada.
|
|
58
|
+
- `card_funnel_id`, `card_stage`, `card_priority`, `card_status` (equal_to/not_equal_to) — card
|
|
59
|
+
do Kanban vinculado.
|
|
60
|
+
- Condição com `custom_attribute_type:'conversation_attribute'` — atributo da conversa vinculada.
|
|
61
|
+
|
|
62
|
+
## 3. Kanban — `lionchat_kanban_items_filter` (lista rica de cards)
|
|
63
|
+
|
|
64
|
+
GET com parâmetros FLAT (não usa payload). Filtros REAIS (2026-07-24 — parâmetros fantasmas
|
|
65
|
+
stage_id/inbox_id/sort_by/sort_direction/page foram REMOVIDOS, eram ignorados pelo backend):
|
|
66
|
+
|
|
67
|
+
- `funnel_id` (obrigatório), `stages[]` (chaves internas das etapas), `priorities[]`,
|
|
68
|
+
`statuses[]` (open/won/lost), `agent_id`, `value_min`/`value_max`
|
|
69
|
+
- `date_start`/`date_end` (criação do card, YYYY-MM-DD)
|
|
70
|
+
- `scheduled_date_start`/`scheduled_date_end` (agendamento: scheduled_at/deadline_at do card E
|
|
71
|
+
tarefas da agenda vinculadas)
|
|
72
|
+
- `task_filter`: has_task | no_task | today | tomorrow | this_week | overdue
|
|
73
|
+
- `channel` (tipo de canal SEM prefixo: Waha, Whatsapp, Instagram...), `label` (etiqueta da
|
|
74
|
+
conversa do card), `offer` (descrição exata de oferta no card)
|
|
75
|
+
- `card_custom_attribute_filters` / `contact_custom_attribute_filters` /
|
|
76
|
+
`conversation_custom_attribute_filters` — **JSON-string** (padrão B) de condições
|
|
77
|
+
`{attribute_key, filter_operator, values[]}`, operadores: equal_to, not_equal_to, contains,
|
|
78
|
+
does_not_contain, is_present, is_not_present. `custom_attribute_match`: 'all' (E) | 'any' (OU).
|
|
79
|
+
|
|
80
|
+
ATENÇÃO: **sem paginação** — até 5000 cards, ordem created_at DESC, shape `{items, total, filters}`.
|
|
81
|
+
NÃO há filtro por time aqui (por time: use o relatório agregado abaixo, ou filtre por agent_id).
|
|
82
|
+
|
|
83
|
+
## 4. Relatório agregado do Kanban — `lionchat_kanban_items_list_3`
|
|
84
|
+
|
|
85
|
+
`GET /kanban_items/reports` — a resposta é um OBJETO de métricas (não lista): valores GANHOS,
|
|
86
|
+
contagem/valor por etapa, forecast ponderado, top negócios, cards parados, metas do funil.
|
|
87
|
+
Params: `funnel_id` (obrigatório), `from`, `to`, `user_ids[]` (agentes), `team_id`.
|
|
88
|
+
É a ferramenta certa pra "relatório de vendas/ganhos do mês por agente ou time".
|
|
89
|
+
|
|
90
|
+
## 5. Busca com filtro estruturado
|
|
91
|
+
|
|
92
|
+
`search_search` (tudo), `conversations_search`, `contacts_search`, `kanban_items_search` aceitam
|
|
93
|
+
`conversation_filters`/`contact_filters` (JSON-string no MESMO shape do payload dos /filter, mesmo
|
|
94
|
+
motor, cap 10 condições) e `kanban_filters` (JSON-string do subset flat da seção 3). Paginação por
|
|
95
|
+
categoria: 15/página (kanban: primeiros 15, sem paginação).
|
|
96
|
+
|
|
97
|
+
## 6. Respostas: enxutas por padrão + paginação
|
|
98
|
+
|
|
99
|
+
- **Slim (2026-07-24, default LIGADO):** listas voltam SEM campos pesados/decorativos
|
|
100
|
+
(`message_templates`, `working_hours`, `meta_history_import`, avatares — viram marcador
|
|
101
|
+
`[omitido...]`). Pra resposta completa: `full_response:true` (disponível nas tools de
|
|
102
|
+
lista/show pesadas). Anexos de mensagem (data_url/download_url) NUNCA são podados.
|
|
103
|
+
- **Segredos:** chaves de credencial (api_key, tokens, senhas) saem SEMPRE como `[REDACTED]` —
|
|
104
|
+
sem exceção, nem com full_response. Precisa de um token? Painel, não robô.
|
|
105
|
+
- **Paginação:** os DOIS conectores agora informam `pagination.{current_page,total_pages,
|
|
106
|
+
total_count,has_more}` — pagine até `has_more=false`. (No remoto o bloco é ADICIONADO ao lado
|
|
107
|
+
do shape original.)
|
|
108
|
+
- **Corte:** resposta acima do teto é enxugada por ITENS INTEIROS (aviso `[LISTA ENXUGADA...]`
|
|
109
|
+
com contagem exibida/total) — o JSON nunca vem quebrado no meio.
|
|
110
|
+
|
|
111
|
+
## 7. Receitas prontas
|
|
112
|
+
|
|
113
|
+
**R1 — Conversas de um período por atendente:**
|
|
114
|
+
```json
|
|
115
|
+
payload=[
|
|
116
|
+
{"attribute_key":"assignee_id","filter_operator":"equal_to","values":[6],"query_operator":"and"},
|
|
117
|
+
{"attribute_key":"created_at","filter_operator":"is_greater_than","values":["2026-07-01"],"query_operator":"and"},
|
|
118
|
+
{"attribute_key":"created_at","filter_operator":"is_less_than","values":["2026-07-31"]}
|
|
119
|
+
]
|
|
120
|
+
```
|
|
121
|
+
(paginar até has_more=false; pra métricas agregadas prefira `reports_summary` type=agent)
|
|
122
|
+
|
|
123
|
+
**R2 — Cards por etapa + faixa de valor no mês:**
|
|
124
|
+
`kanban_items_filter funnel_id=37 stages=["negociacao"] value_min=5000 date_start=2026-07-01 date_end=2026-07-31`
|
|
125
|
+
|
|
126
|
+
**R3 — Ganhos do mês por agente/time:**
|
|
127
|
+
`kanban_items_list_3 funnel_id=37 from=2026-07-01 to=2026-07-31 user_ids=[6,12]` (ou `team_id=3`)
|
|
128
|
+
|
|
129
|
+
**R4 — Conversas de uma campanha que FALHARAM/entregaram:** filtre por
|
|
130
|
+
`campaign_id equal_to <id>`; o status da MENSAGEM de template (sent/delivered/read/failed) está
|
|
131
|
+
nas mensagens da conversa (`conversations_messages_list`) — não é atributo da conversa.
|
|
132
|
+
|
|
133
|
+
**R5 — Contatos por atributo + etiqueta:**
|
|
134
|
+
```json
|
|
135
|
+
payload=[
|
|
136
|
+
{"attribute_key":"faixa_investimento","filter_operator":"equal_to","values":["300k_1m"],"query_operator":"and"},
|
|
137
|
+
{"attribute_key":"labels","filter_operator":"equal_to","values":["apoiador"]}
|
|
138
|
+
]
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**R6 — Cards parados (sem tarefa) com atributo do contato:**
|
|
142
|
+
`kanban_items_filter funnel_id=37 task_filter=no_task contact_custom_attribute_filters="[{\"attribute_key\":\"ja_investe\",\"filter_operator\":\"equal_to\",\"values\":[\"ja_invisto\"]}]"`
|
|
143
|
+
|
|
144
|
+
**Erros clássicos a evitar:** `includes` em labels (não existe — use equal_to); operador de
|
|
145
|
+
número/data em texto; array-de-objetos em query (padrão B exige JSON-string); esquecer
|
|
146
|
+
`custom_attribute_type` quando contato e conversa têm atributo de mesmo nome; esperar paginação
|
|
147
|
+
no kanban_items_filter (não tem — estreite o filtro).
|
|
@@ -12,6 +12,27 @@ Como interpretar cada um dos endpoints de relatório (`lionchat_reports_*`) e m
|
|
|
12
12
|
86400 segundos → "24 horas" ou "1 dia"
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
## Por que o número "não bate" — leia ANTES de responder ao usuário (2026-07-24)
|
|
16
|
+
|
|
17
|
+
Quando o usuário disser "o relatório está errado / não bate", quase sempre é UMA destas semânticas
|
|
18
|
+
(verificadas no código e com prova empírica em conta real):
|
|
19
|
+
|
|
20
|
+
1. **"Conversas" e "Resolvidas" têm âncoras de tempo DIFERENTES.** conversations_count = conversas
|
|
21
|
+
CRIADAS no período; resolutions_count = eventos de resolução OCORRIDOS no período (a conversa pode
|
|
22
|
+
ter sido criada antes). Um atendente pode "resolver mais do que recebeu" — correto, não é bug.
|
|
23
|
+
2. **"Resolvidas" conta EVENTOS, não conversas.** Resolver → reabrir → resolver = 2. Pode passar do
|
|
24
|
+
total de conversas.
|
|
25
|
+
3. **Recorte por ATENDENTE só enxerga conversas ATRIBUÍDAS.** Conversa sem responsável (auto-atribuição
|
|
26
|
+
desligada, disparo em massa) não aparece em NENHUM atendente — a soma dos atendentes pode ser uma
|
|
27
|
+
fração minúscula do total da conta (caso real: 202 de 4001). Sempre diga quantas estão sem atendente.
|
|
28
|
+
4. **A contagem de conversas por atendente usa o responsável ATUAL** — reatribuir conversa antiga move
|
|
29
|
+
o histórico de um atendente pro outro. Já resoluções/tempos usam quem era o dono NA HORA do evento.
|
|
30
|
+
Os dois cards podem divergir legitimamente em conta que reatribui.
|
|
31
|
+
5. **timezone_offset NÃO altera totais** de summary — só o agrupamento dos pontos da série temporal.
|
|
32
|
+
Diferenças de ~1% entre relatório e lista filtrada são borda de janela/fuso, não defeito.
|
|
33
|
+
6. **since/until são unix SEGUNDOS** em TODOS os endpoints de relatório. ISO 8601 quebra a janela em
|
|
34
|
+
silêncio (relatório vazio/errado).
|
|
35
|
+
|
|
15
36
|
## Mapeamento dos endpoints `lionchat_reports_*`
|
|
16
37
|
|
|
17
38
|
> ⚠️ **A numeração `_N` é gerada automaticamente e NÃO segue uma ordem lógica.** Use SEMPRE a tabela
|
|
@@ -116,6 +137,10 @@ Retorna array de métricas, **uma por usuário da conta**. Campos confirmados (e
|
|
|
116
137
|
> - **CSAT por agente:** use `lionchat_csat_list` com filtro `user_ids=<id>` e calcule a média.
|
|
117
138
|
> - **Tempo online / status:** use `lionchat_agent_availability` ou os live_reports (`_16`/`_17`).
|
|
118
139
|
|
|
140
|
+
**Filtro por caixa (novo em 2026-07-24):** aceita `inbox_id` — o desempenho dos agentes DENTRO de
|
|
141
|
+
uma caixa específica. É exclusivo deste relatório; os resumos de time/caixa/etiqueta/canal
|
|
142
|
+
(`_1` a `_4`) NÃO aceitam `inbox_id`.
|
|
143
|
+
|
|
119
144
|
`_1` (time), `_2` (inbox), `_3` (label), `_4` (canal) seguem a mesma ideia de resumo agrupado,
|
|
120
145
|
trocando a chave de agrupamento.
|
|
121
146
|
|
|
@@ -146,7 +171,7 @@ Retorna SOMENTE estes dois campos (não existe taxa pronta):
|
|
|
146
171
|
### `lionchat_reports_list_13` — Conversation Traffic (tráfego)
|
|
147
172
|
**Use quando:** "horário de pico", "quando tem mais demanda"
|
|
148
173
|
|
|
149
|
-
Heatmap de volume por hora. Aceita `timezone_offset` (
|
|
174
|
+
Heatmap de volume por hora. Aceita SÓ `timezone_offset` (sem ele o pico sai em UTC). ATENÇÃO: janela FIXA a partir de hoje — NÃO aceita `since`/`until`.
|
|
150
175
|
|
|
151
176
|
### `lionchat_reports_list_16` / `_17` — Tempo real (live)
|
|
152
177
|
**Use quando:** "quem tá online agora", "carga atual", "conversas abertas no momento"
|
|
@@ -154,6 +179,10 @@ Heatmap de volume por hora. Aceita `timezone_offset` (importante: sem ele o pico
|
|
|
154
179
|
São os live_reports (`conversation_metrics` e a versão agrupada). Use estes — e não os resumos
|
|
155
180
|
históricos — quando o usuário quiser o agora.
|
|
156
181
|
|
|
182
|
+
**Filtros aceitos (expostos na tool desde 2026-07-24):** `inbox_id`, `assignee_id` e `team_id`,
|
|
183
|
+
todos opcionais e combináveis — é o mesmo recorte da tela Visão Geral. Em `_17` o `group_by`
|
|
184
|
+
(`team_id` ou `assignee_id`) continua obrigatório e os filtros recortam a base ANTES de agrupar.
|
|
185
|
+
|
|
157
186
|
### `lionchat_csat_metrics` — CSAT agregado
|
|
158
187
|
**Use quando:** "satisfação", "nota média dos clientes", "CSAT"
|
|
159
188
|
|
|
@@ -171,7 +200,7 @@ Retorna SOMENTE estes campos (nem média, nem taxa de resposta vêm prontas):
|
|
|
171
200
|
> **Taxa de resposta** = `total_count / total_sent_messages_count`.
|
|
172
201
|
> No exemplo: 80/210 = **38%**.
|
|
173
202
|
|
|
174
|
-
**Filtros aceitos:** `user_ids`, `inbox_id`, `team_id`, `rating`, `since`/`until
|
|
203
|
+
**Filtros aceitos (expostos na tool desde 2026-07-24):** `user_ids[]`, `inbox_id`, `team_id`, `rating`, `since`/`until` (unix segundos). Agora dá pra recortar CSAT por caixa/atendente direto.
|
|
175
204
|
|
|
176
205
|
### `lionchat_sla_metrics` — SLA agregado (ENTERPRISE-ONLY)
|
|
177
206
|
**Use quando:** "cumprimento de SLA", "quantos prazos estouraram"
|
|
@@ -190,7 +219,7 @@ Retorna:
|
|
|
190
219
|
> O `hit_rate` já vem calculado como string (ex.: `"95.5%"`, ou `"100%"` quando não há falhas).
|
|
191
220
|
> Não divida nada — apenas exiba o valor.
|
|
192
221
|
|
|
193
|
-
**Filtros aceitos:** `inbox_id`, `team_id`, `sla_policy_id`, `label_list`, `assigned_agent_id`, `since`/`until
|
|
222
|
+
**Filtros aceitos (expostos na tool desde 2026-07-24):** `inbox_id`, `team_id`, `sla_policy_id`, `label_list[]`, `assigned_agent_id`, `since`/`until` (unix segundos).
|
|
194
223
|
|
|
195
224
|
## Padrões de interpretação
|
|
196
225
|
|
|
@@ -265,6 +265,39 @@ Participantes continuam vendo a conversa, mas não recebem sino/push a cada mens
|
|
|
265
265
|
alguém específico, use @menção em nota interna (que notifica pelo caminho próprio; a lista de quem
|
|
266
266
|
pode ser mencionado vem de `lionchat_conversations_mentionable_users`).
|
|
267
267
|
|
|
268
|
+
### "Mandei reenviar a mensagem falhada e voltou 422" (25/07)
|
|
269
|
+
Não é bug: mensagem **cancelada** ou **excluída** nunca reenvia. O bloqueio é na fonte e vale pros
|
|
270
|
+
três caminhos — botão da bolha (`lionchat_conversations_messages_create_1`), reenvio em lote
|
|
271
|
+
(`lionchat_inboxes_failed_messages_bulk_retry`) e a auto-recuperação do WAHA. Se o usuário quer
|
|
272
|
+
mesmo mandar de novo, o caminho é escrever uma mensagem nova.
|
|
273
|
+
|
|
274
|
+
### "A falha sumiu do painel" / "apareceu um grupo Excluídas" (25/07)
|
|
275
|
+
Dois comportamentos novos e propositais no painel Falhas de envio
|
|
276
|
+
(`lionchat_inboxes_failed_messages_summary`):
|
|
277
|
+
- **Cancelada** (`cancel_retry` / `bulk_cancel`) some do painel de vez — cancelar é limpar.
|
|
278
|
+
- **Excluída** NÃO some: vira o grupo informativo `deleted` (campo `deleted_count`), guardando
|
|
279
|
+
contato, horário e o **motivo original** da falha. É registro, então não tem botão de reenviar
|
|
280
|
+
nem de cancelar e fica fora de `retryable_count` e do `total`.
|
|
281
|
+
|
|
282
|
+
Cancelar vale pra TODOS os grupos (inclusive `permanent`, `window_expired`, `campaign` e `partial`,
|
|
283
|
+
que nunca seriam reenviados) — é assim que se limpa o painel. Ações irreversíveis: confirme com o
|
|
284
|
+
usuário e mostre as contagens do summary antes.
|
|
285
|
+
|
|
286
|
+
### "O Messenger parou de enviar / 'Invalid parameter'" (24/07)
|
|
287
|
+
Causa raiz do apagão de 22 a 24/07: a Meta **aposentou a message tag** que o sistema mandava em todo
|
|
288
|
+
envio de Messenger. Corrigido em 24/07. Agora o Messenger respeita a **janela de 24h** de verdade:
|
|
289
|
+
dentro da janela envia normal; passou de 24h da última mensagem do cliente, a Meta recusa — não é
|
|
290
|
+
falha do LionChat, é regra da plataforma. Não existe template de Messenger pra "reabrir" a janela
|
|
291
|
+
(isso é WhatsApp). Instagram nunca usou tag e não foi afetado.
|
|
292
|
+
|
|
293
|
+
### "A importação de histórico do WhatsApp (QR) parou no meio" (25/07)
|
|
294
|
+
A importação agora se recupera sozinha: se o servidor reiniciar no meio, ela fica `interrupted` e
|
|
295
|
+
**retoma de onde parou** (não baixa de novo o que já entrou) na próxima verificação. Estados
|
|
296
|
+
possíveis: `importing` (rodando), `interrupted` (caiu, vai retomar sozinha), `paused` (alguém pausou
|
|
297
|
+
pelo painel de suporte — só volta no botão Retomar), `cancelled` (encerrada de vez), `completed`.
|
|
298
|
+
Enquanto uma importação está viva, o repescador de mensagens da sessão fica fora do caminho, de
|
|
299
|
+
propósito. Pausar, retomar e cancelar são ações do painel de suporte — não existem no MCP.
|
|
300
|
+
|
|
268
301
|
### "Editei o evento no Google Calendar e não sincronizou"
|
|
269
302
|
Auto-cura desde 2026-06-09: o vigia horário re-arma o "watch" morto de conexões saudáveis
|
|
270
303
|
sozinho (sem reconectar a conta). Se persistir >1h, aí sim investigar a conexão
|
package/dist/resources.js
CHANGED
|
@@ -29,6 +29,12 @@ export const RESOURCES = [
|
|
|
29
29
|
description: 'Auth, paginacao, filtros, datas, codigos HTTP, rate limits. Use quando tiver duvida sobre como chamar endpoint.',
|
|
30
30
|
filename: 'api-conventions.md',
|
|
31
31
|
},
|
|
32
|
+
{
|
|
33
|
+
name: 'Filtros e Relatorios',
|
|
34
|
+
uri: 'lionchat://docs/filtros-e-relatorios',
|
|
35
|
+
description: 'Tabelas COMPLETAS de chaves/operadores dos filtros de conversas, contatos e Kanban + relatorio agregado do funil + receitas prontas. Consulte ANTES de montar qualquer filtro ou relatorio — evita 422 de operador invalido.',
|
|
36
|
+
filename: 'filtros-e-relatorios.md',
|
|
37
|
+
},
|
|
32
38
|
{
|
|
33
39
|
name: 'Fluxos de Conversacao',
|
|
34
40
|
uri: 'lionchat://docs/conversation-flows',
|
package/dist/resources.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const FULL_RESPONSE_PARAM = "full_response";
|
|
2
|
+
export declare const FULL_RESPONSE_DESCRIPTION: string;
|
|
3
|
+
export declare const FULL_RESPONSE_TOOLS: Set<string>;
|
|
4
|
+
export declare function supportsFullResponse(toolId: string): boolean;
|
|
5
|
+
export interface SanitizeOptions {
|
|
6
|
+
slim: boolean;
|
|
7
|
+
toolId?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function sanitizeResponse(value: unknown, opts: SanitizeOptions): unknown;
|
package/dist/sanitize.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// AIDEV-NOTE: [seguranca+slim 2026-07-24] Sanitizacao central de TODA resposta MCP.
|
|
2
|
+
// 1) Segredos: SEMPRE redigidos (sem opt-out) — respostas embutiam provider_config.api_key
|
|
3
|
+
// (token da Meta Cloud), smtp_password, hmac_token etc. Chave de credencial vira '[REDACTED]'.
|
|
4
|
+
// 2) Slim: default LIGADO — poda sub-objetos pesados (message_templates com 13 templates,
|
|
5
|
+
// working_hours, meta_history_import, avatares) que estouravam o teto de 80k e cortavam
|
|
6
|
+
// o JSON no meio. Escape: full_response:true nas tools curadas (FULL_RESPONSE_TOOLS).
|
|
7
|
+
// AIDEV-SECURITY: recursivo POR NOME DE CHAVE (nao por caminho) de proposito — o conector NPM
|
|
8
|
+
// normaliza a resposta ({data,pagination}) e o remoto entrega o shape cru; poda por caminho
|
|
9
|
+
// fixo seria no-op num dos dois. Este arquivo e PORTADO byte-identico pro lionchat-mcp-remote
|
|
10
|
+
// (src/mcp/sanitize.ts) — alterar um exige alterar o outro.
|
|
11
|
+
const REDACT_PLACEHOLDER = '[REDACTED]';
|
|
12
|
+
const SLIM_PLACEHOLDER = '[omitido — use full_response:true ou a tool dedicada]';
|
|
13
|
+
// AIDEV-SECURITY: chaves EXATAS de credencial (case-insensitive). Fontes: _inbox.json.jbuilder
|
|
14
|
+
// (auth_token/account_sid Twilio, imap/smtp_password Email, hmac_token, provider_config Meta),
|
|
15
|
+
// _account.json.jbuilder (topsend_api_key, liontrack_token), _user.json.jbuilder (access_token).
|
|
16
|
+
const REDACT_EXACT = new Set([
|
|
17
|
+
'api_key',
|
|
18
|
+
'apikey',
|
|
19
|
+
'api_key_plain',
|
|
20
|
+
'auth_token',
|
|
21
|
+
'access_token',
|
|
22
|
+
'account_sid',
|
|
23
|
+
'password',
|
|
24
|
+
'imap_password',
|
|
25
|
+
'smtp_password',
|
|
26
|
+
'hmac_token',
|
|
27
|
+
'webhook_verify_token',
|
|
28
|
+
'pubsub_token',
|
|
29
|
+
'topsend_api_key',
|
|
30
|
+
'liontrack_token',
|
|
31
|
+
'client_secret',
|
|
32
|
+
'consumer_key',
|
|
33
|
+
'consumer_secret',
|
|
34
|
+
'app_secret',
|
|
35
|
+
'secret',
|
|
36
|
+
]);
|
|
37
|
+
const REDACT_SUFFIXES = ['_password', '_secret', '_api_key', '_auth_token', '_access_token'];
|
|
38
|
+
// AIDEV-NOTE: website_token e publico por design (vai inline no HTML do site do cliente pro
|
|
39
|
+
// widget) — unica excecao da redacao. NAO adicionar excecoes sem decisao explicita do dono
|
|
40
|
+
// (politica 2026-07-24: censura total de credencial em resposta de robo).
|
|
41
|
+
const REDACT_EXCEPTIONS = new Set(['website_token']);
|
|
42
|
+
// AIDEV-NOTE: chaves PESADAS podadas pelo slim. NUNCA incluir aqui data_url/download_url/
|
|
43
|
+
// file_url/thumb_url — sao de ANEXO de mensagem (baixar midia e caso de uso legitimo).
|
|
44
|
+
// avatar_url/thumbnail/avatar sao foto de contato/agente/inbox (decorativo em lista).
|
|
45
|
+
const SLIM_KEYS = new Set([
|
|
46
|
+
'message_templates',
|
|
47
|
+
'working_hours',
|
|
48
|
+
'meta_history_import',
|
|
49
|
+
'avatar_url',
|
|
50
|
+
'thumbnail',
|
|
51
|
+
'avatar',
|
|
52
|
+
]);
|
|
53
|
+
// AIDEV-NOTE: tools cujo PROPOSITO e o campo pesado — slim nao se aplica nelas
|
|
54
|
+
// (segredos continuam redigidos mesmo assim).
|
|
55
|
+
const SLIM_EXEMPT_SUBSTRINGS = ['whatsapp_templates', 'csat_template'];
|
|
56
|
+
export const FULL_RESPONSE_PARAM = 'full_response';
|
|
57
|
+
export const FULL_RESPONSE_DESCRIPTION = 'true = resposta COMPLETA, sem a poda de campos pesados (message_templates, working_hours, ' +
|
|
58
|
+
'avatares, meta_history_import). Padrao false (resposta enxuta). Segredos sao SEMPRE censurados, ' +
|
|
59
|
+
'com ou sem esta opcao.';
|
|
60
|
+
// AIDEV-NOTE: conjunto CURADO de tools pesadas que ganham o param full_response no schema.
|
|
61
|
+
// Nao injetar nas 682 (inflaria o tools/list em ~20-30k tokens). Tools fora da lista continuam
|
|
62
|
+
// com slim ligado — o dado podado e alcancavel pela tool dedicada (ex: whatsapp_templates_list).
|
|
63
|
+
export const FULL_RESPONSE_TOOLS = new Set([
|
|
64
|
+
'lionchat_conversations_list',
|
|
65
|
+
'lionchat_conversations_filter',
|
|
66
|
+
'lionchat_conversations_search',
|
|
67
|
+
'lionchat_conversations_show',
|
|
68
|
+
'lionchat_conversations_meta',
|
|
69
|
+
'lionchat_conversations_messages_list',
|
|
70
|
+
'lionchat_conversations_messages_search',
|
|
71
|
+
'lionchat_contacts_list',
|
|
72
|
+
'lionchat_contacts_filter',
|
|
73
|
+
'lionchat_contacts_search',
|
|
74
|
+
'lionchat_contacts_show',
|
|
75
|
+
'lionchat_campaigns_list',
|
|
76
|
+
'lionchat_campaigns_show',
|
|
77
|
+
'lionchat_inboxes_list',
|
|
78
|
+
'lionchat_inboxes_show',
|
|
79
|
+
'lionchat_inboxes_list_1',
|
|
80
|
+
'lionchat_inboxes_show_1',
|
|
81
|
+
'lionchat_kanban_items_list',
|
|
82
|
+
'lionchat_kanban_items_filter',
|
|
83
|
+
'lionchat_kanban_items_search',
|
|
84
|
+
'lionchat_kanban_items_show',
|
|
85
|
+
'lionchat_search_search',
|
|
86
|
+
'lionchat_search_list',
|
|
87
|
+
'lionchat_search_list_1',
|
|
88
|
+
'lionchat_search_list_2',
|
|
89
|
+
'lionchat_agents_list',
|
|
90
|
+
'lionchat_teams_list',
|
|
91
|
+
'lionchat_account_show',
|
|
92
|
+
]);
|
|
93
|
+
export function supportsFullResponse(toolId) {
|
|
94
|
+
return FULL_RESPONSE_TOOLS.has(toolId);
|
|
95
|
+
}
|
|
96
|
+
function shouldRedact(key) {
|
|
97
|
+
const k = key.toLowerCase();
|
|
98
|
+
if (REDACT_EXCEPTIONS.has(k)) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
if (REDACT_EXACT.has(k)) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
return REDACT_SUFFIXES.some((suffix) => k.endsWith(suffix));
|
|
105
|
+
}
|
|
106
|
+
// AIDEV-NOTE: caminha a resposta inteira (qualquer shape) redigindo segredos e, se slim,
|
|
107
|
+
// substituindo campos pesados pelo marcador curto. Nao muta o objeto original.
|
|
108
|
+
export function sanitizeResponse(value, opts) {
|
|
109
|
+
const slimActive = opts.slim &&
|
|
110
|
+
!SLIM_EXEMPT_SUBSTRINGS.some((s) => (opts.toolId ?? '').includes(s));
|
|
111
|
+
const walk = (node) => {
|
|
112
|
+
if (Array.isArray(node)) {
|
|
113
|
+
return node.map(walk);
|
|
114
|
+
}
|
|
115
|
+
if (node && typeof node === 'object') {
|
|
116
|
+
const out = {};
|
|
117
|
+
for (const [key, val] of Object.entries(node)) {
|
|
118
|
+
if (shouldRedact(key)) {
|
|
119
|
+
// AIDEV-SECURITY: valor vazio/null passa como esta (informativo); qualquer valor
|
|
120
|
+
// presente vira o placeholder — nunca o conteudo.
|
|
121
|
+
out[key] = val === null || val === undefined || val === '' ? val : REDACT_PLACEHOLDER;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (slimActive && SLIM_KEYS.has(key.toLowerCase()) && val !== null && val !== undefined) {
|
|
125
|
+
out[key] = SLIM_PLACEHOLDER;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
out[key] = walk(val);
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
return node;
|
|
133
|
+
};
|
|
134
|
+
return walk(value);
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=sanitize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../src/sanitize.ts"],"names":[],"mappings":"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"}
|