@lionchat/mcp-server 1.9.0 → 1.10.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 +12 -2
- package/dist/docs/resources/api-conventions.md +14 -4
- package/dist/docs/resources/best-practices.md +82 -10
- package/dist/docs/resources/conversation-flows.md +73 -12
- package/dist/docs/resources/data-model.md +12 -4
- package/dist/docs/resources/flowbuilder-design-guide.md +45 -12
- package/dist/docs/resources/glossary.md +22 -8
- package/dist/docs/resources/kanban-deep-dive.md +35 -3
- package/dist/docs/resources/reports-guide.md +117 -16
- package/dist/tools.js +32 -8
- package/dist/tools.js.map +1 -1
- package/endpoints.json +216 -118
- package/package.json +1 -1
|
@@ -227,9 +227,15 @@ POST /api/v1/accounts/{account_id}/kanban_items
|
|
|
227
227
|
### Relatório de produtividade
|
|
228
228
|
```
|
|
229
229
|
1. lionchat_reports_summary (visão geral)
|
|
230
|
-
2. lionchat_reports_list (por agente — passa since/until
|
|
230
|
+
2. lionchat_reports_list (por agente — passa since/until em Unix EM SEGUNDOS)
|
|
231
231
|
3. Comparar avg_first_response_time entre agentes
|
|
232
232
|
```
|
|
233
|
+
**`since`/`until` dos relatórios só aceitam número Unix em SEGUNDOS** (`1782864000` = 01/07/2026 00:00
|
|
234
|
+
UTC), nunca ISO 8601 nem data por extenso — o formato ISO do resto da plataforma (seção 3) NÃO vale
|
|
235
|
+
aqui. Desde 29/07/2026 a API recusa com HTTP 400 (`invalid_date_params`); antes disso o relatório
|
|
236
|
+
voltava ZERADO com HTTP 200 (a conta 19 tinha 4.396 conversas no período e a resposta vinha zero).
|
|
237
|
+
Converta a data do usuário para segundos antes de chamar. Os exports em CSV (agents, inboxes, labels,
|
|
238
|
+
teams, conversations_summary) exigem as DUAS pontas; nos demais, `since` ou `until` sozinho é válido.
|
|
233
239
|
|
|
234
240
|
### Criar campanha de WhatsApp (disparo em massa)
|
|
235
241
|
```
|
|
@@ -292,11 +298,15 @@ e pular evita que ela receba tudo em dobro. Quem está sendo atendido pela equip
|
|
|
292
298
|
| Limite | Valor |
|
|
293
299
|
|---|---|
|
|
294
300
|
| `per_page` max | 100 |
|
|
295
|
-
| Bulk actions (IDs) max |
|
|
301
|
+
| Bulk actions (IDs) max | 300 por chamada (desde 18/05/2026; passou disso = HTTP 422 `bulk_ids_limit_exceeded`) |
|
|
296
302
|
| Rate limit leitura | 1200/min por token |
|
|
297
303
|
| Rate limit escrita | 600/min por token |
|
|
298
304
|
| Loop detection | bloqueia chamada idêntica >10x em 10s |
|
|
299
305
|
|
|
306
|
+
Exceção ao teto de 300: em ação em massa de **contatos** com `select_all: true` (agir sobre todos os
|
|
307
|
+
contatos do filtro) não há teto de IDs — o servidor refaz o filtro e processa em lotes no fundo. O
|
|
308
|
+
teto de 300 vale para o caminho normal, com a lista de IDs. Kanban usa o mesmo teto no `item_ids`.
|
|
309
|
+
|
|
300
310
|
## 7. Confirmar antes de agir — regra de ouro
|
|
301
311
|
|
|
302
312
|
Antes de QUALQUER ação que escreve, modifica, apaga ou envia, pare e avalie se o pedido está claro e completo. Na dúvida, pergunte — **nunca chute**.
|
|
@@ -349,17 +349,27 @@ Quando rate-limited:
|
|
|
349
349
|
|
|
350
350
|
### Bulk actions
|
|
351
351
|
|
|
352
|
-
`POST /bulk_actions` aceita arrays de IDs. **Máximo
|
|
352
|
+
`POST /bulk_actions` aceita arrays de IDs. **Máximo 300 IDs por chamada** (`MAX_BULK_IDS`, desde
|
|
353
|
+
2026-05-15). Acima disso o servidor recusa com `422` + `code: "bulk_ids_limit_exceeded"` — quebre em
|
|
354
|
+
chamadas de 300.
|
|
355
|
+
|
|
356
|
+
**Exceção:** contato com `select_all: true` (agir sobre TODOS os contatos do filtro) **não tem teto** —
|
|
357
|
+
o servidor resolve pelo próprio filtro (`query` / `labels_filter`), em lotes no fundo, e não usa `ids`.
|
|
353
358
|
|
|
354
359
|
```json
|
|
355
360
|
{
|
|
356
361
|
"type": "Conversation",
|
|
357
|
-
"ids": [1, 2, 3, ...],
|
|
358
|
-
"
|
|
359
|
-
"action_attributes": { "assignee_id": 6 }
|
|
362
|
+
"ids": [1, 2, 3, ...], // max 300
|
|
363
|
+
"fields": { "assignee_id": 6 } // conversa: status, assignee_id, team_id, inbox_id, captain_assistant_id
|
|
360
364
|
}
|
|
361
365
|
```
|
|
362
366
|
|
|
367
|
+
**⚠️ `action_attributes` NÃO EXISTE.** O servidor não lê esse campo em lugar nenhum (só aparece em
|
|
368
|
+
comentário de TODO no código). Mandar a mudança por ali devolve **200 OK e não faz absolutamente nada** —
|
|
369
|
+
falha silenciosa, sem erro na tela. Conversa se altera por `fields` (+ `labels: {add:[], remove:[]}` e
|
|
370
|
+
`snoozed_until`). Em conversa o `action_name` é **ignorado**; ele só tem efeito em **contato**, onde
|
|
371
|
+
`"delete"` apaga os contatos (sem ele, o que vale é `labels: {add: []}`).
|
|
372
|
+
|
|
363
373
|
### Search (overhaul 2026-06-10)
|
|
364
374
|
|
|
365
375
|
`GET /search?q=texto` — busca cross-entidade (conversations, contacts, messages, articles, kanban_items)
|
|
@@ -77,7 +77,14 @@ Conversa com 200 mensagens? **Não baixe tudo**:
|
|
|
77
77
|
## Operações em massa
|
|
78
78
|
|
|
79
79
|
Pra atribuir labels, mover cards, etc em vários itens:
|
|
80
|
-
|
|
80
|
+
|
|
81
|
+
- `kanban_bulk_bulk_actions` — **NÃO é de cards do Kanban**, apesar do nome. Ela bate em
|
|
82
|
+
`POST /bulk_actions` e age em **conversas ou contatos** (o `type` é `Conversation` ou `Contact`).
|
|
83
|
+
Usar ela achando que move card não dá erro visível — só não faz o que você queria.
|
|
84
|
+
- Cards do Kanban têm **três** ferramentas próprias, uma por ação:
|
|
85
|
+
- `kanban_bulk_create` → `bulk_move_items` (mover cards de etapa)
|
|
86
|
+
- `kanban_bulk_create_1` → `bulk_assign_agent` (definir o responsável)
|
|
87
|
+
- `kanban_bulk_create_2` → `bulk_set_priority` (definir a prioridade)
|
|
81
88
|
- `kanban_items_kanban_agents_create` em massa (passar array)
|
|
82
89
|
- `automation_rules_*` (criar regras em vez de fazer manualmente)
|
|
83
90
|
|
|
@@ -127,7 +134,32 @@ O `config` DEVE ser enviado como **objeto** (ex.: `config: { disabled_tools: [..
|
|
|
127
134
|
## Limite do prompt e cache OpenAI (2026-05-22)
|
|
128
135
|
|
|
129
136
|
- `config.instructions` (system prompt do agente) aceita até **20.000 caracteres** (antes 10k). Acima de 15k, o frontend mostra aviso "lost in the middle" — prefira colocar instruções críticas no início ou final.
|
|
130
|
-
- **Cache automático** ativo em todos os
|
|
137
|
+
- **Cache automático** ativo em todos os 16 modelos oferecidos na plataforma. Desconto 50-75% no input cachado, sem configuração. Reuso do prompt do agente em múltiplas conversas maximiza a economia.
|
|
138
|
+
|
|
139
|
+
### Lista real de modelos (`config.model`)
|
|
140
|
+
|
|
141
|
+
Estes são os 16 valores que o seletor de modelo do painel oferece (`ModelSelector.vue`). Só recomende
|
|
142
|
+
valores desta lista:
|
|
143
|
+
|
|
144
|
+
| Faixa | Modelos |
|
|
145
|
+
|---|---|
|
|
146
|
+
| Econômicos / rápidos | `gpt-4.1-nano`, `gpt-4o-mini`, `gpt-4.1-mini`, `gpt-5.4-nano`, `gpt-5.4-mini` |
|
|
147
|
+
| Intermediários | `gpt-4o`, `gpt-4.1`, `gpt-5-mini`, `gpt-5.4` |
|
|
148
|
+
| Raciocínio | `o3-mini`, `o4-mini` |
|
|
149
|
+
| Premium | `gpt-5`, `gpt-5.2`, `gpt-5.5`, `o1`, `o3` |
|
|
150
|
+
|
|
151
|
+
**`GPT-5.2 Pro` não existe.** O valor válido é `gpt-5.2`, sem "Pro".
|
|
152
|
+
|
|
153
|
+
> **PERIGO — família `gpt-5.6` (`gpt-5.6-luna`, `gpt-5.6-terra`, `gpt-5.6-sol`): REMOVIDA em 29/07/2026.**
|
|
154
|
+
> Esses modelos **recusam function tools** em `/v1/chat/completions` (erro 400 real: "Function tools with
|
|
155
|
+
> reasoning_effort are not supported"). Como o AI Agente usa ferramentas em **toda** resposta, 100% das
|
|
156
|
+
> chamadas falhavam e a IA ficava **MUDA** — sem erro na tela, sem resposta. Ficou 2 semanas invisível.
|
|
157
|
+
> **Nunca sugira, nunca grave** um `gpt-5.6` — nem se o cliente pedir "o mais novo/mais forte".
|
|
158
|
+
>
|
|
159
|
+
> O campo `config.model` **não tem lista branca no servidor**: ele é `store_accessor` do `config` e
|
|
160
|
+
> aceita qualquer texto sem validar. Modelo inválido salva com 200 e só quebra na hora de responder.
|
|
161
|
+
> Desde 29/07 o erro vira uma **nota privada em português** na conversa (`llm_request_rejected`) — é o
|
|
162
|
+
> primeiro lugar a olhar quando "a IA parou de responder logo depois de mexerem nas configurações".
|
|
131
163
|
|
|
132
164
|
## Follow-up automático multi-etapa (2026-06)
|
|
133
165
|
|
|
@@ -137,21 +169,61 @@ O follow-up do AI Agente agora suporta **cadência de até 3 etapas** via `confi
|
|
|
137
169
|
{ "config": { "feature_follow_up": true, "follow_up_steps": [
|
|
138
170
|
{ "after_minutes": 30, "prompt": "Pergunte gentilmente se ainda tem interesse" },
|
|
139
171
|
{ "after_minutes": 240, "prompt": "Ofereça tirar dúvidas" },
|
|
140
|
-
{ "after_minutes":
|
|
172
|
+
{ "after_minutes": 1110, "prompt": "Última tentativa, despeça-se cordialmente" }
|
|
141
173
|
] } }
|
|
142
174
|
```
|
|
143
175
|
|
|
144
|
-
Regras: cada etapa ≥ 5 min; soma total ≤
|
|
145
|
-
`follow_up_time` + `follow_up_prompt` continuam funcionando como 1 etapa única
|
|
176
|
+
Regras: cada etapa ≥ 5 min; **soma total ≤ 1380 min (23h)**; máx 3 etapas. Campos legados
|
|
177
|
+
`follow_up_time` + `follow_up_prompt` continuam funcionando como 1 etapa única (e obedecem ao **mesmo
|
|
178
|
+
teto de 1380**).
|
|
179
|
+
|
|
180
|
+
> **O teto é 1380, não 1440** (`Captain::Assistant::FOLLOW_UP_MAX_TOTAL_MINUTES`). Motivo: a janela de
|
|
181
|
+
> 24h do WhatsApp conta a partir da **mensagem do cliente**, não do primeiro acompanhamento — 1h de
|
|
182
|
+
> folga evita agendar uma cobrança que a Meta recusaria na hora de enviar. Montar a cadência somando
|
|
183
|
+
> 1440 faz o salvamento ser **recusado**. Pegadinha: a mensagem de erro do campo legado `follow_up_time`
|
|
184
|
+
> ainda diz "must be between 5 and 1440 minutes", mas a validação usa 1380 — não confie no texto do erro.
|
|
185
|
+
|
|
186
|
+
(O exemplo acima soma exatamente 1380: 30 + 240 + 1110.)
|
|
187
|
+
|
|
146
188
|
Dispara quando o CLIENTE fica inativo após resposta da IA. O motor de follow-up é dedicado e
|
|
147
189
|
**só-leitura** (não executa ferramentas, não coleta dado — só redige a mensagem de retomada,
|
|
148
190
|
com saída estruturada garantida). `paused=true` no assistente corta os follow-ups também.
|
|
149
191
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
192
|
+
### "A IA nunca faz o follow-up" — o conserto é de 29/07, NÃO de 24/07
|
|
193
|
+
|
|
194
|
+
**Não repita que isso foi corrigido em 24/07.** A versão de 24/07 agendava o follow-up **dentro** do
|
|
195
|
+
bloco do "Responder na hora": ou seja, ela só funcionava quando esse interruptor estava **LIGADO** —
|
|
196
|
+
justamente o caso que menos precisa dela. Com "Responder na hora" **desligado**, a IA não fala, o único
|
|
197
|
+
outro gatilho (o hook de mensagem enviada) também não dispara, e a conversa fica **com IA ativa e sem
|
|
198
|
+
nenhum acompanhamento, para sempre**. Aconteceu em **140 conversas da conta 52** — todas criadas
|
|
199
|
+
DEPOIS do suposto conserto de 24/07. A ativação **manual pela tela** nunca esteve coberta em nenhuma
|
|
200
|
+
das duas versões até 29/07.
|
|
201
|
+
|
|
202
|
+
**"Responder na hora" e acompanhamento são INDEPENDENTES.** São perguntas diferentes:
|
|
203
|
+
- *Responder na hora* (`captain_reply_now` / `proactive`) = "a IA fala agora, sem esperar o cliente?"
|
|
204
|
+
- *Acompanhamento* (`feature_follow_up`) = "a IA cobra depois, se ninguém responder?"
|
|
205
|
+
|
|
206
|
+
Desligar o primeiro **não** deve desligar o segundo. Nunca oriente o cliente a ligar "Responder na
|
|
207
|
+
hora" para o acompanhamento funcionar.
|
|
208
|
+
|
|
209
|
+
**Corrigido de verdade em 2026-07-29**, nos três caminhos que ativam a IA, com o agendamento **fora**
|
|
210
|
+
do bloco do "Responder na hora":
|
|
211
|
+
- Flow, ação "Ativar IA" (`FlowBuilder::ActionDelegator`) — só em ativação nova (a conversa não tinha IA)
|
|
212
|
+
- Automação, ação "Atribuir assistente" (`AutomationRules::ActionService`)
|
|
213
|
+
- Ativação manual pela tela da conversa (`ConversationsController`) — armado **antes** da checagem do
|
|
214
|
+
"Responder na hora"
|
|
215
|
+
|
|
216
|
+
**Ainda descoberto (não corrigido):** ativar a IA em **lote** (ação em massa de conversas com
|
|
217
|
+
`captain_assistant_id`) **não arma o acompanhamento nem dispara resposta imediata**. Se o cliente
|
|
218
|
+
ativou a IA em massa e reclama que ela não cobra de volta, é isso — e o caminho é reativar pela tela
|
|
219
|
+
ou por automação.
|
|
220
|
+
|
|
221
|
+
Diagnóstico, nesta ordem, quando relatarem "a IA nunca faz o follow-up":
|
|
222
|
+
1. `config.feature_follow_up` está ligado no assistente? E `paused` está desligado? (`paused=true`
|
|
223
|
+
corta os follow-ups)
|
|
224
|
+
2. A ativação veio por **lote**? Então nunca foi armado.
|
|
225
|
+
3. Tem `follow_up_skip_conditions` batendo (etiqueta, atributo, janela de silêncio)?
|
|
226
|
+
4. A soma das etapas passa de 1380 min? Nesse caso o assistente nem salvou a cadência.
|
|
155
227
|
|
|
156
228
|
## Condições para NÃO fazer follow-up + horário de silêncio (2026-07)
|
|
157
229
|
|
|
@@ -98,17 +98,65 @@ Avaliação:
|
|
|
98
98
|
|
|
99
99
|
### 4. Auto-assignment
|
|
100
100
|
|
|
101
|
-
Roda após automation rules.
|
|
101
|
+
Roda após automation rules. Existem **DOIS caminhos vivos** (`Inbox#auto_assignment_v2_enabled?`),
|
|
102
|
+
não um moderno e um legado:
|
|
102
103
|
|
|
103
104
|
```
|
|
104
|
-
SE inbox.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
SE inbox.assignment_policy vinculada:
|
|
106
|
+
→ modo POLÍTICA: round-robin ou balanced, prioridade da fila, capacidade
|
|
107
|
+
SENÃO SE inbox.enable_auto_assignment (botão "Distribuição automática" da própria caixa):
|
|
108
|
+
→ modo SIMPLES: round-robin entre os membros da caixa
|
|
109
|
+
SENÃO:
|
|
110
|
+
→ assignee_id fica null (atribuição manual)
|
|
109
111
|
```
|
|
110
112
|
|
|
111
|
-
|
|
113
|
+
Os dois caminhos rodam no MESMO serviço (`AutoAssignment::AssignmentService`), usam o MESMO rodízio
|
|
114
|
+
(`AutoAssignment::RoundRobinSelector` — só a política pode trocá-lo pelo modo `balanced`) e passam
|
|
115
|
+
pelo MESMO freio de rajada
|
|
116
|
+
(`AutoAssignment::RateLimiter`). O que muda é de onde vem a configuração: com política vinculada, ela
|
|
117
|
+
manda em tudo (inclusive em "distribuir para agentes offline"); sem política, vale o que está no
|
|
118
|
+
`auto_assignment_config` da própria caixa.
|
|
119
|
+
|
|
120
|
+
**NUNCA escreva que o modo simples é legado, nem recomende criar Política de Atribuição para quem só
|
|
121
|
+
quer o botão da caixa.** Vincular uma política **esconde a seção inteira de Distribuição Automática da
|
|
122
|
+
tela da caixa** (`CollaboratorsPage.vue`: `showAutoDistribution = !inbox.has_assignment_policy`). O
|
|
123
|
+
cliente perde os controles que estava usando, não entende por que sumiram, e o que ele configurou lá
|
|
124
|
+
passa a ser ignorado (o valor fica gravado e só volta a valer se a política for desvinculada).
|
|
125
|
+
|
|
126
|
+
Regra prática:
|
|
127
|
+
- Cliente quer só "dividir os leads entre a equipe" → **botão da própria caixa**. Não crie política.
|
|
128
|
+
- Cliente quer regra compartilhada entre várias caixas, modo balanced, prioridade de fila ou limite de
|
|
129
|
+
capacidade por atendente → aí sim Política de Atribuição.
|
|
130
|
+
|
|
131
|
+
Quem entra no rodízio: só `inbox_members` com `auto_assignable: true` (supervisor de caixa fica de
|
|
132
|
+
fora) e, se "distribuir para agentes offline" estiver desligado, só quem está online.
|
|
133
|
+
|
|
134
|
+
**LEIA o valor da conta antes de responder — NUNCA recite um número de cabeça.** Os valores reais
|
|
135
|
+
vêm na resposta da API:
|
|
136
|
+
- `has_assignment_policy` (resposta da caixa) diz QUAL dos dois caminhos vale ali. `true` = política
|
|
137
|
+
manda; `false` = vale o botão da própria caixa.
|
|
138
|
+
- Com política vinculada, leia `fair_distribution_limit` (quantas conversas por atendente),
|
|
139
|
+
`fair_distribution_window` (tamanho da janela, **em segundos**) e `assign_offline_agents` na
|
|
140
|
+
resposta da política. O `auto_assignment_config` da caixa é **IGNORADO** nesse caso — não o cite.
|
|
141
|
+
- Sem política, leia as MESMAS chaves dentro do bloco `auto_assignment_config` da caixa
|
|
142
|
+
(`fair_distribution_limit`, `fair_distribution_window`, `assign_offline_agents`).
|
|
143
|
+
- Chave ausente/vazia = vale o padrão de fábrica (hoje 10 conversas a cada 600 segundos) — cite isso
|
|
144
|
+
só como "valor de fábrica, confira o da conta", nunca como se fosse a configuração do cliente.
|
|
145
|
+
|
|
146
|
+
**EXCEÇÃO SEM FREIO (não dá pra descobrir lendo a resposta):** caixa **sem** política vinculada, com
|
|
147
|
+
`assign_offline_agents` LIGADO e **sem número escolhido** em `fair_distribution_limit`, roda **SEM
|
|
148
|
+
FREIO NENHUM** (`AutoAssignment::RateLimiter#resolve_limit`: `return 0 if inbox.assign_offline_agents?`).
|
|
149
|
+
Racional (decisão do dono 29/07): com offline ligado todo membro está sempre na roleta, então a divisão
|
|
150
|
+
já é igual por construção e o freio só atrasaria a entrega. Não existe campo dizendo "sem freio" — o
|
|
151
|
+
bloco vazio parece "padrão", mas não é. Efeito prático: **nessas caixas, dizer ao cliente que existe um
|
|
152
|
+
teto por atendente é MENTIRA**. Número escolhido pelo cliente sempre vence o toggle: se
|
|
153
|
+
`fair_distribution_limit` tem um número MAIOR QUE ZERO, o freio existe mesmo com offline ligado.
|
|
154
|
+
|
|
155
|
+
**Zero também é "sem freio":** na caixa (não na política), `fair_distribution_limit: 0` é a saída
|
|
156
|
+
explícita de quem não quer teto nenhum — o freio fica desligado (`RateLimiter#enabled?` exige limite
|
|
157
|
+
positivo). Ou seja, existem DUAS formas de a caixa ficar sem freio: campo vazio com offline ligado, ou
|
|
158
|
+
zero escrito de propósito. Na Política de Atribuição o zero nem é aceito (o cadastro exige maior que
|
|
159
|
+
zero), então política vinculada SEMPRE tem freio.
|
|
112
160
|
|
|
113
161
|
### 5. Captain (IA Agente)
|
|
114
162
|
|
|
@@ -138,7 +186,10 @@ handoff consultor→gestor). Pendente só acontece por ação explícita:
|
|
|
138
186
|
- Ferramenta nativa da IA (deixar conversa pendente)
|
|
139
187
|
|
|
140
188
|
Comportamentos importantes:
|
|
141
|
-
- Mensagem nova do
|
|
189
|
+
- Mensagem nova do CLIENTE REABRE conversa pendente (volta pra Aberta, com pílula de aviso na
|
|
190
|
+
conversa). Só a do cliente: resposta do ATENDENTE não reabre. Vale desde 30/07/2026 e REVOGA a
|
|
191
|
+
regra anterior de 20/07 ("pendente não reabre") — decisão do dono depois de a conta 19 acumular
|
|
192
|
+
258 clientes esperando sem o time ver. NUNCA responda que a conversa fica parada em Pendente
|
|
142
193
|
- Pendente ATRIBUÍDA notifica o responsável (o gestor recebe o aviso)
|
|
143
194
|
|
|
144
195
|
### 7. Resolução (status 1)
|
|
@@ -186,10 +237,20 @@ Conversation
|
|
|
186
237
|
|
|
187
238
|
### "Conversa não atribuiu ninguém"
|
|
188
239
|
|
|
189
|
-
1. `inbox.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
240
|
+
1. A distribuição está ligada em ALGUM dos dois caminhos? `inbox.assignment_policy` vinculada **ou**
|
|
241
|
+
`inbox.enable_auto_assignment` true. Não existe campo `enable_auto_assignment_v2` — não peça por ele.
|
|
242
|
+
Política vinculada **não é requisito**: caixa sem política e com o botão ligado distribui normalmente.
|
|
243
|
+
2. Se há política: ela está com `enabled: true`? Política desligada = ninguém é atribuído.
|
|
244
|
+
3. Tem `InboxMember` com `auto_assignable: true`? Supervisor de caixa é membro mas **não entra** no rodízio.
|
|
245
|
+
4. Se "distribuir para agentes offline" está desligado, tem alguém **online** agora? Sem ninguém online
|
|
246
|
+
a fila fica parada até alguém logar.
|
|
247
|
+
5. O atendente pode estar no **teto da janela** do freio de rajada (o robô só entrega N conversas por
|
|
248
|
+
atendente/caixa dentro de uma janela deslizante). A vaga volta quando a conversa é resolvida, adiada
|
|
249
|
+
ou vira pendente — e a fila anda sozinha em até 1 minuto. Antes de culpar o freio, confira os
|
|
250
|
+
valores reais da conta e a exceção SEM FREIO (seção 4) — pode não haver teto nenhum ali.
|
|
251
|
+
6. Se a caixa tem **uma única** conversa esperando, o freio **nem se aplica** (`should_apply_rate_limit?`
|
|
252
|
+
exige mais de 1 não atribuída). Nesse caso a causa é outra — não culpe o freio.
|
|
253
|
+
7. Tem `automation_rule` que poderia ter atribuído antes?
|
|
193
254
|
|
|
194
255
|
### "IA não respondeu"
|
|
195
256
|
|
|
@@ -245,15 +245,23 @@ Captain::Assistant
|
|
|
245
245
|
├── config (jsonb) — chaves principais:
|
|
246
246
|
│ model, temperature, instructions (max 20.000 chars), feature_memory, feature_faq,
|
|
247
247
|
│ feature_follow_up (bool), follow_up_steps (array de {after_minutes, prompt} — ATE 3 etapas,
|
|
248
|
-
│ cada uma >= 5 min, soma <=
|
|
248
|
+
│ cada uma >= 5 min, soma <= 1380 min = 23h (2026-07-29 — NAO 1440: a janela de 24h do WhatsApp
|
|
249
|
+
│ conta da MENSAGEM DO CLIENTE, nao do 1o follow-up, entao 1440 disparava com a janela ja fechada.
|
|
250
|
+
│ Somar 1440 = 422. GOTCHA: no campo legado follow_up_time a mensagem de erro do servidor ainda
|
|
251
|
+
│ diz "must be between 5 and 1440 minutes" por engano — o teto que ele aplica e 1380);
|
|
252
|
+
│ legado follow_up_time+follow_up_prompt = 1 etapa),
|
|
249
253
|
│ follow_up_skip_conditions (array — condicoes pra NAO fazer follow-up, logica OU, ate 3; tipos:
|
|
250
254
|
│ label {operator present|absent, labels[]}; contact_attr/conversation_attr {attribute, operator
|
|
251
255
|
│ equal|not_equal|contains|present|blank|gt|lt, value}; time_window {start, end — horas inteiras
|
|
252
256
|
│ 0-23; NAO envia follow-up nesse periodo, janela circular ex 22->7; a IA SEGUE respondendo o
|
|
253
257
|
│ cliente normal — o silencio e so do follow-up}),
|
|
254
|
-
│ feature_pause_on_human_reply (bool — a IA se DESLIGA sozinha na
|
|
255
|
-
│ assume: atendente responde pelo painel (ao vivo) OU mensagem enviada
|
|
256
|
-
│ nota privada, msg da propria IA, automacao, campanha, confirmacao de
|
|
258
|
+
│ feature_pause_on_human_reply (bool, nasce DESLIGADO — quando ligado, a IA se DESLIGA sozinha na
|
|
259
|
+
│ conversa quando um HUMANO assume: atendente responde pelo painel (ao vivo) OU mensagem enviada
|
|
260
|
+
│ do celular. NAO conta: nota privada, msg da propria IA, automacao, campanha, confirmacao de
|
|
261
|
+
│ agendamento. MENSAGEM AGENDADA DEPENDE DE QUEM AGENDOU (2026-07-29): agendada pela IA (a tool
|
|
262
|
+
│ carimba source_type='Captain::Assistant' e o disparo assina como o assistente) NAO desliga;
|
|
263
|
+
│ agendada por ATENDENTE assina como User com Current.user setado no disparo = conta como
|
|
264
|
+
│ atendente ao vivo e DESLIGA a IA da conversa),
|
|
257
265
|
│ activation_label (etiqueta que ativa o agente — unica por conta),
|
|
258
266
|
│ min_response_time / max_response_time (delay humanizado, 1-60s),
|
|
259
267
|
│ disabled_tools (array de IDs de tools desativadas pro assistente),
|
|
@@ -107,8 +107,16 @@ Item (sem `config`): `{ "key": "campaign_trigger" }`
|
|
|
107
107
|
- Pode conviver com outros gatilhos no mesmo flow (ex.: um flow que responde a mensagem E também pode
|
|
108
108
|
ser disparado em campanha). É **isento** da trava de gatilho duplicado.
|
|
109
109
|
- Só flow de conversa (`flow_type: conversation`); flow de grupo funciona, mas o público é de contatos.
|
|
110
|
-
- Em caixa WhatsApp **oficial**, o
|
|
111
|
-
|
|
110
|
+
- Em caixa WhatsApp **oficial**, o primeiro bloco de mensagem de **CADA CAMINHO** que sai do Início
|
|
111
|
+
precisa abrir com **template aprovado** — não só o primeiro bloco que o flow encontra. Com
|
|
112
|
+
randomizador (teste A/B) ou condição logo no começo, **todas** as variações são conferidas: basta
|
|
113
|
+
UMA sem template pra campanha ser recusada na criação (422). O erro nomeia os blocos culpados pelo
|
|
114
|
+
rótulo, teto de 5: `must start with an approved WhatsApp template on official inboxes (no template
|
|
115
|
+
in: <rótulos>)`. O que vale é o **primeiro item** do `messageItems` daquele bloco, e os tipos
|
|
116
|
+
aceitos são `template` (o que a tela grava) e `whatsapp_template` (legado). Flow sem nenhum bloco
|
|
117
|
+
de mensagem não tem o que validar. Em QR Code não existe essa regra.
|
|
118
|
+
(Corrigido em 2026-07-29: até então a checagem aceitava só `whatsapp_template` — nome que a tela
|
|
119
|
+
NUNCA gravou — e olhava um caminho só; recusava 100% das caixas oficiais.)
|
|
112
120
|
- Como a campanha inicia o flow com o contato **sem ter mandado nada**, escreva o 1º bloco assumindo
|
|
113
121
|
contato frio (apresente-se, dê contexto) — diferente de um flow de atendimento, que responde a alguém.
|
|
114
122
|
|
|
@@ -418,6 +426,10 @@ o botão "Usar variável" ao lado do campo alterna lista fixa ↔ variável.
|
|
|
418
426
|
|
|
419
427
|
**`update_attribute` — campos EXATOS:** `attr_source` (`'contact'`, `'conversation'` ou `'card'`), `attr_key` (nome do atributo), `attr_value` (valor). NÃO existem `entity`/`key`/`value` — esses são ignorados e não salvam nada.
|
|
420
428
|
|
|
429
|
+
**Coerção por TIPO (2026-07-29):** em `attr_source: 'contact'|'conversation'`, o `attr_value` de atributo personalizado é coagido pelo tipo da definição antes de gravar: número/moeda/porcentagem viram numérico ("1.234,56" → 1234.56; inteiro fica inteiro), checkbox aceita sim/não/true/false e grava BOOLEANO, lista casa caixa-insensível e grava a opção canônica, data aceita DD/MM/AAAA ou ISO, hora aceita "14:30"/"14h30". Valor irreconhecível grava como veio e o passo mostra nota âmbar no histórico. Card NÃO coage (atributo de card não tem definição tipada no backend).
|
|
430
|
+
|
|
431
|
+
**Campos NATIVOS do contato (2026-07-29):** com `attr_source: 'contact'`, `attr_key` também aceita os paths canônicos `contact.name`, `contact.email`, `contact.cpf`, `contact.cnpj`, `contact.rg`, `contact.passport`, `contact.date_of_birth`, `contact.gender`, `contact.marital_status`, `contact.profession` e `contact.address.{cep,street,number,complement,neighborhood,city,state,country}` — gravam na ficha nativa do contato (não em custom_attributes). Regras: telefone/identifier/etiquetas NÃO são aceitos (mapa fechado — chave fora dele vira atributo personalizado comum); documentos, nascimento, gênero e **e-mail** só preenchem campo VAZIO; nome/profissão/estado civil/endereço sobrescrevem; valor em branco nunca grava; gênero aceita `m|f|o|na` e estado civil `solteiro|casado|uniao_estavel|divorciado|separado|viuvo`; data de nascimento em `dd/mm/aaaa` ou `aaaa-mm-dd`. Recusas aparecem no histórico de execução (passo 'skipped'/'error' com mensagem).
|
|
432
|
+
|
|
421
433
|
**Somar/subtrair NÃO é operação dedicada** — é filtro Liquid no próprio `attr_value`. O valor é resolvido como template antes de salvar. Exemplos:
|
|
422
434
|
|
|
423
435
|
```json
|
|
@@ -497,14 +509,22 @@ NÃO existe `.payload`/`.response` (`{{api_response.payload.x}}` resolve vazio).
|
|
|
497
509
|
|
|
498
510
|
**Modelo por ação — `aiModel` + `aiModelExplicit` (2026-07-13):** TODO modo aceita escolher o modelo
|
|
499
511
|
LLM no próprio nó, com ou sem assistente, em qualquer tipo de flow. Enviar o par:
|
|
500
|
-
`"aiModel": "gpt-4.1-mini"`
|
|
501
|
-
|
|
502
|
-
`
|
|
503
|
-
|
|
504
|
-
conta.
|
|
505
|
-
assistente usaria). Modelo fora da whitelist = ignorado (cai no padrão da conta).
|
|
512
|
+
`"aiModel": "gpt-4.1-mini"` JUNTO de `"aiModelExplicit": true`. SEM a flag o backend ignora o
|
|
513
|
+
aiModel nos modos novos (proteção de nós antigos que carregam aiModel de default nunca honrado).
|
|
514
|
+
`aiModel` vazio/ausente = modelo padrão da conta. Com assistente selecionado, o override também vale
|
|
515
|
+
(sobrepõe o modelo que o caminho do assistente usaria). Modelo fora da whitelist = ignorado (cai no
|
|
516
|
+
padrão da conta).
|
|
506
517
|
Exemplo: `{"aiMode":"sentiment","aiAssistantId":"12","aiModel":"gpt-4.1-mini","aiModelExplicit":true}`.
|
|
507
518
|
|
|
519
|
+
**A whitelist (`FlowBuilder::RawLlmService::SUPPORTED_MODELS`) é uma lista FECHADA de 16 nomes, SEM
|
|
520
|
+
curinga** — não existe "a família gpt-5 inteira":
|
|
521
|
+
`gpt-4o-mini`, `gpt-4o`, `gpt-4.1-nano`, `gpt-4.1-mini`, `gpt-4.1`, `gpt-5-mini`, `gpt-5`,
|
|
522
|
+
`gpt-5.2`, `gpt-5.4-nano`, `gpt-5.4-mini`, `gpt-5.4`, `gpt-5.5`, `o1`, `o3`, `o3-mini`, `o4-mini`.
|
|
523
|
+
A família **`gpt-5.6` (luna/terra/sol) foi REMOVIDA em 2026-07-29**: ela recusa function tools
|
|
524
|
+
(erro 400 na OpenAI), o que deixava o Agente de IA **mudo em 100% das chamadas** — saiu também daqui
|
|
525
|
+
pra não ser oferecida numa tela e faltar na outra. Também não existem `o1-mini`, `gpt-4.5-preview`,
|
|
526
|
+
`gpt-5.2-pro` nem `gpt-5.5-pro` (a OpenAI recusa).
|
|
527
|
+
|
|
508
528
|
**OBRIGATÓRIO via API — `aiAssistantId`:** os modos `generate`/`intent`/`sentiment`/`extract`
|
|
509
529
|
EXIGEM um `aiAssistantId` válido (id de um assistente Captain da conta). Sem ele o nó SAI cedo
|
|
510
530
|
(`action: continue`) sem gravar nada — a variável de saída (`aiResponseVar`/`ai_intent`/`ai_sentiment`)
|
|
@@ -581,15 +601,22 @@ O campo raiz é **`waitMode`**: `"duration"` (default), `"date"` ou `"weekday"`.
|
|
|
581
601
|
"waitMode": "weekday",
|
|
582
602
|
"waitWeekday": 1,
|
|
583
603
|
"waitWeekdayTime": "09:00",
|
|
604
|
+
"waitWeekdayTimeMode": "fixed",
|
|
584
605
|
"waitTimezone": "America/Sao_Paulo"
|
|
585
606
|
}
|
|
586
607
|
}
|
|
587
608
|
```
|
|
588
609
|
|
|
589
|
-
- `waitWeekday`: 0=domingo, 1=segunda... 6=sábado. `waitWeekdayTime` = `"HH:MM"` 24h
|
|
610
|
+
- `waitWeekday`: 0=domingo, 1=segunda... 6=sábado. `waitWeekdayTime` = `"HH:MM"` 24h. `waitTimezone` = mesmo campo do modo date.
|
|
611
|
+
- **Variável no Horário (novo 2026-07-29 — reverte a proibição de 06/07):** o campo `waitWeekdayTime` ACEITA variável `{{ }}`, com o mesmo contrato dos campos do modo `date`. O modo mora em **`waitWeekdayTimeMode`**: `"fixed"` (default, e o que vale quando a chave está ausente) ou `"variable"` — espelho exato do `waitTimeMode`.
|
|
612
|
+
- **Mandar a variável SEM `"waitWeekdayTimeMode": "variable"` não funciona e não avisa:** o motor trata o campo como texto fixo, a chave `{{ }}` nunca é resolvida e o horário calculado não é o pretendido. Não há erro de validação, nem na API nem na tela. Como o MCP escreve o JSON do fluxo direto, sem passar pela tela, esse par é obrigatório.
|
|
613
|
+
- Exemplo: `{"waitMode":"weekday","waitWeekday":1,"waitWeekdayTime":"{{contact.custom_attribute.horario_retorno}}","waitWeekdayTimeMode":"variable","waitTimezone":"America/Sao_Paulo"}`.
|
|
614
|
+
- Resolve UMA única vez, na entrada do node (quem já está esperando mantém o valor capturado). Aceita `"14:30"`, `"9:30"`, `"14h30"`, `"14h"`, `"14:30:00"` — ou seja, atributo tipo `time` (Hora 24h). Valor ISO de atributo `date`/`datetime` é rejeitado (mesma regra do campo Horário do modo `date`).
|
|
615
|
+
- Variável que não resolve pra horário válido → saída `error` (payload `invalid_variable_datetime`, `field: waitWeekdayTime`).
|
|
616
|
+
- Modo `fixed` NUNCA emite erro: horário em branco cai no default `09:00` — flow antigo intacto.
|
|
590
617
|
- (Os nomes `targetWeekday`/`targetHour` NÃO existem — eram um erro de documentação antiga.)
|
|
591
618
|
|
|
592
|
-
**Handles que SAEM:** `success` (+ `error`, emitido
|
|
619
|
+
**Handles que SAEM:** `success` (+ `error`, emitido quando um campo em modo `variable` resolve pra valor inválido — vale nos DOIS modos, `date` e `weekday`; em modo `fixed` o `error` nunca é emitido).
|
|
593
620
|
|
|
594
621
|
### 2.9 `set_variable`
|
|
595
622
|
|
|
@@ -621,13 +648,19 @@ O campo raiz é **`waitMode`**: `"duration"` (default), `"date"` ou `"weekday"`.
|
|
|
621
648
|
"label": "A/B test mensagem",
|
|
622
649
|
"mode": "branches",
|
|
623
650
|
"branches": [
|
|
624
|
-
{ "id": "A", "label": "Variante A", "
|
|
625
|
-
{ "id": "B", "label": "Variante B", "
|
|
651
|
+
{ "id": "A", "label": "Variante A", "percent": 50 },
|
|
652
|
+
{ "id": "B", "label": "Variante B", "percent": 50 }
|
|
626
653
|
]
|
|
627
654
|
}
|
|
628
655
|
}
|
|
629
656
|
```
|
|
630
657
|
|
|
658
|
+
**O campo é `percent`, NÃO `weight` (2026-07-30):** a tela sempre gravou `percent` (`randomizerBranches`
|
|
659
|
+
do FlowNodeConfigModal) e o motor lia só `weight` — nenhum node configurado pela tela funcionava.
|
|
660
|
+
Corrigido em 30/07: o motor lê `percent` e aceita `weight` só como dado antigo. **Escreva sempre
|
|
661
|
+
`percent`** — randomizador criado com `weight` até roda, mas abre com as porcentagens EM BRANCO na
|
|
662
|
+
tela do cliente (a tela lê só `percent`).
|
|
663
|
+
|
|
631
664
|
**Modo `distribute_agents` (sorteio PONDERADO):** `data.mode: 'distribute_agents'` + `data.agents: [{ agent_id, percent }]` — sorteia UM agente por probabilidade (percentuais somando 100) e atribui automaticamente. Isso é SORTEIO, não rodízio: no curto prazo pode cair no mesmo agente várias vezes seguidas. Pra RODÍZIO EXATO (cada um na vez), use a AÇÃO `distribute_agents` no node `action` (ver seção 2.5) — não este modo.
|
|
632
665
|
|
|
633
666
|
**Handles que SAEM:** o `id` de cada branch (`A`, `B`, ...). Em `mode: 'distribute_agents'` é `success`.
|
|
@@ -214,7 +214,10 @@ os de `user_ids` viram membros comuns. A resposta traz `is_supervisor` (boolean)
|
|
|
214
214
|
- `config.feature_memory`: gera notas no contato ao resolver conversas
|
|
215
215
|
- `config.feature_faq`: gera FAQs sugeridas ao resolver conversas
|
|
216
216
|
- `config.feature_follow_up` + `config.follow_up_steps`: follow-up automático em cadência de até
|
|
217
|
-
3 etapas (cada ≥5 min, soma ≤24h) quando o cliente some — motor dedicado
|
|
217
|
+
3 etapas (cada ≥5 min, **soma ≤1380 min = 23h**, não 24h) quando o cliente some — motor dedicado
|
|
218
|
+
só-leitura. O teto é 1380 porque a janela de 24h do WhatsApp conta da **mensagem do cliente**, não do
|
|
219
|
+
primeiro follow-up; somar 1440 é recusado com 422 (e no campo legado `follow_up_time` a mensagem de
|
|
220
|
+
erro ainda diz "1440" por engano — o teto aplicado é 1380)
|
|
218
221
|
- `config.follow_up_skip_conditions`: array (até 3, lógica OU) de condições pra NÃO fazer follow-up.
|
|
219
222
|
Tipos: `label`, `contact_attr`/`conversation_attr`, e `time_window` (horário de silêncio: `start`/`end`
|
|
220
223
|
horas 0-23, janela circular — no período não envia follow-up, mas a IA segue respondendo o cliente)
|
|
@@ -223,8 +226,12 @@ os de `user_ids` viram membros comuns. A resposta traz `is_supervisor` (boolean)
|
|
|
223
226
|
com 422 "step 1 must be at least 5 minutes"). `feature_pause_on_human_reply`,
|
|
224
227
|
`feature_follow_up` e demais booleans de config aceitam update direto via
|
|
225
228
|
`captain_assistants_update` (merge parcial de config).
|
|
226
|
-
- `config.feature_pause_on_human_reply`: bool — a IA se desliga sozinha na conversa
|
|
227
|
-
assume (atendente responde pelo painel OU mensagem do celular); nota
|
|
229
|
+
- `config.feature_pause_on_human_reply`: bool (nasce desligado) — a IA se desliga sozinha na conversa
|
|
230
|
+
quando um humano assume (atendente responde pelo painel OU mensagem do celular); nota
|
|
231
|
+
privada/automação/campanha não contam. **Mensagem agendada depende de quem agendou (2026-07-29):**
|
|
232
|
+
agendada **pela IA** não desliga (o disparo assina como o assistente); agendada **por um atendente**
|
|
233
|
+
conta como atendente ao vivo e **DESLIGA** a IA da conversa — na prática, programar uma mensagem em
|
|
234
|
+
nome do atendente numa conversa com IA ativa tira a IA dali quando ela for enviada
|
|
228
235
|
- `config.model`: modelo OpenAI usado (gpt-4o, gpt-4o-mini)
|
|
229
236
|
- `config.temperature`: 0.0-1.0
|
|
230
237
|
- `config.instructions`: prompt sistema (Liquid template, até 20.000 chars)
|
|
@@ -373,16 +380,23 @@ Campos MUTÁVEIS (atualizáveis livremente por IA/integração): `marital_status
|
|
|
373
380
|
|
|
374
381
|
`custom_attribute_definitions` (model=`contact_attribute`) fica reservado a dado de NEGÓCIO genérico que não tem modelo dedicado (ex: "plano contratado", "nicho do cliente").
|
|
375
382
|
|
|
376
|
-
## Ligações —
|
|
383
|
+
## Ligações — CINCO sistemas distintos (não confundir!)
|
|
377
384
|
|
|
378
385
|
| Sistema | O que é | Tools | Canal |
|
|
379
386
|
|---|---|---|---|
|
|
380
|
-
| **Ligação WP (Wavoip)** | Voz pelo WhatsApp em caixa **QR Code/WAHA** — QR conecta um "device" Wavoip; widget de discagem, gravação e transcrição automática | **NENHUMA — sem tool no MCP** (ver nota abaixo) | WhatsApp QR Code |
|
|
387
|
+
| **Ligação WP (Wavoip)** | Voz pelo WhatsApp em caixa **QR Code/WAHA** — QR conecta um "device" Wavoip (pago, por caixa); widget de discagem, gravação e transcrição automática | **NENHUMA — sem tool no MCP** (ver nota abaixo) | WhatsApp QR Code |
|
|
388
|
+
| **LionCalls** | Voz pelo WhatsApp em caixa **QR Code**, mas pelo **motor próprio do LionChat** (credencial global, 1 sessão por caixa; flag `lioncalls_calling`, nasce desligada e é ligada conta a conta) | **NENHUMA — sem tool no MCP** | WhatsApp QR Code |
|
|
381
389
|
| **WhatsApp Calling (Cloud)** | Voz pelo WhatsApp na **API oficial** (enterprise) | `whatsapp_calls_*` + enable/disable_whatsapp_calling | WhatsApp oficial |
|
|
382
|
-
| **VoIP (Zenvia)** | Telefonia COMUM (ramais, saldo, recarga) | `voip_*` | Telefone |
|
|
390
|
+
| **VoIP (Zenvia)** | Telefonia COMUM com softphone no navegador (ramais, saldo, recarga) | `voip_*` | Telefone |
|
|
391
|
+
| **VTCall** | Telefonia por **PABX click-to-call**, config por conta + ramal por atendente; **sem softphone no navegador** — o atendente fala pelo app/ramal do VTCall | `vtcall_settings_*` (show/update/test_connection), `vtcall_ramals_*` (list/create/destroy) | Telefone (PABX do cliente) |
|
|
383
392
|
|
|
384
|
-
Quando o usuário falar "ligação", descubra o canal: caixa QR Code → Wavoip
|
|
385
|
-
|
|
393
|
+
Quando o usuário falar "ligação", descubra o canal ANTES de responder: caixa QR Code → Wavoip **ou**
|
|
394
|
+
LionCalls (dois motores diferentes para o MESMO tipo de caixa — veja qual está conectado nela); caixa
|
|
395
|
+
oficial → `whatsapp_calls`; telefone/ramal → Zenvia (softphone) ou VTCall (PABX).
|
|
396
|
+
|
|
397
|
+
**Histórico é compartilhado.** Wavoip, LionCalls, Zenvia e VTCall gravam na MESMA tabela de ligações,
|
|
398
|
+
então `voip_calls_list` (`/voip/calls`) devolve as quatro juntas — mesmo as que não têm tool própria.
|
|
399
|
+
Só o WhatsApp Calling (Cloud) fica fora, em `whatsapp_calls_*`.
|
|
386
400
|
|
|
387
401
|
**Wavoip — SEM TOOL NO MCP (decisão do dono, 2026-07-16).** As 8 tools `wavoip_*` (status, token,
|
|
388
402
|
calls, connect, disconnect, settings, should_ring, flag_rejected) foram REMOVIDAS dos dois conectores.
|
|
@@ -121,9 +121,31 @@ Um card individual dentro de uma etapa.
|
|
|
121
121
|
| `custom_attributes` | jsonb — campos custom (igual contatos) |
|
|
122
122
|
| `assigned_agents` | jsonb array de agentes responsáveis |
|
|
123
123
|
| `activities` | jsonb array — log de atividades |
|
|
124
|
-
| `checklist` | jsonb array de tarefas
|
|
124
|
+
| `checklist` | **O que fica guardado:** jsonb array de tarefas do card (item: `text`/`completed`/`position` + `group_id`/`group_name` opcionais para agrupar). **O que a API devolve é OUTRA coisa** — ver o aviso logo abaixo |
|
|
125
125
|
| `timer_started_at`, `timer_duration` | Timer interno do card |
|
|
126
126
|
|
|
127
|
+
> **ATENÇÃO — na maioria das respostas o `checklist` NÃO é a lista de tarefas, e sim um resumo com
|
|
128
|
+
> os números:** `{ total_count, completed_count, groups: [{ group_id, group_name, total_count,
|
|
129
|
+
> completed_count }] }`. Não existe nenhum `text` ali. Procurar a tarefa nesse campo faz a IA
|
|
130
|
+
> concluir "esse card não tem checklist" num card que tem 12 tarefas.
|
|
131
|
+
>
|
|
132
|
+
> O formato **muda por ferramenta** — não é o mesmo em todas:
|
|
133
|
+
>
|
|
134
|
+
> | Ferramenta | `checklist` | `attachments` | `item_details.notes` / `offers` / `custom_attributes` | `activities` / `funnel` |
|
|
135
|
+
> |---|---|---|---|---|
|
|
136
|
+
> | `kanban_items_list` | **array completo** | `{ total_count }` | completos | ausentes |
|
|
137
|
+
> | `kanban_items_show` | **resumo** | `{ total_count }` | completos | presentes |
|
|
138
|
+
> | `kanban_items_filter` / `_search` | **resumo** | `{ total_count }` | `notes` vira `{ total_count }`; `offers`/`custom_attributes` **removidos** | ausentes |
|
|
139
|
+
> | card embutido em `conversations_show` | **resumo** | — | — | — |
|
|
140
|
+
>
|
|
141
|
+
> - Para ler as tarefas de verdade em QUALQUER caso: **`lionchat_kanban_items_kanban_checklist_list`**
|
|
142
|
+
> (`GET .../kanban_items/{id}/get_checklist`) → `{ item_id, checklist: [ ...itens completos... ],
|
|
143
|
+
> checklist_count }`.
|
|
144
|
+
> - No resumo, `groups` só conta o que está agrupado: tarefa **avulsa** (sem `group_id`) entra no
|
|
145
|
+
> `total_count`/`completed_count` gerais mas **não aparece** em `groups`. Somar os grupos ≠ total.
|
|
146
|
+
> - O card embutido em `conversations_list`/`conversations_filter` **não traz `checklist` nenhum** —
|
|
147
|
+
> nem resumo. Só `conversations_show` traz o resumo.
|
|
148
|
+
|
|
127
149
|
### item_details (detalhes do card)
|
|
128
150
|
|
|
129
151
|
```json
|
|
@@ -326,8 +348,18 @@ qualquer agente no card (`assigned_agents`), não só ao responsável da convers
|
|
|
326
348
|
- `conversations_list` / `conversations_search` retornam SÓ conversas de caixas acessíveis (mais as
|
|
327
349
|
liberadas pela ponte de card atribuído).
|
|
328
350
|
- `conversations_show` / `conversations_messages_*` de conversa inacessível → **404**.
|
|
329
|
-
- Buscar card por ID
|
|
330
|
-
|
|
351
|
+
- Buscar card por ID de caixa inacessível → **404** (não revela sequer que o card existe).
|
|
352
|
+
- Ação em massa de CARD (`kanban_bulk_create` = mover, `kanban_bulk_create_1` = atribuir agente,
|
|
353
|
+
`kanban_bulk_create_2` = definir prioridade) em que NENHUM dos `item_ids` é acessível → **404**
|
|
354
|
+
`{ "error": "Nenhum item valido encontrado" }`. Se só PARTE for inacessível, a ação roda nos
|
|
355
|
+
acessíveis e ignora o resto em silêncio.
|
|
356
|
+
- `kanban_items_export` **não dá 404** — ele filtra: exporta só os cards das caixas que o agente vê
|
|
357
|
+
(pode voltar vazio). Em nenhum dos casos a resposta vaza card de caixa sem acesso.
|
|
358
|
+
|
|
359
|
+
> **Não confunda:** apesar do nome, **`kanban_bulk_bulk_actions` NÃO é ação em massa de card do
|
|
360
|
+
> Kanban** — ela bate em `POST /accounts/{id}/bulk_actions`, que é a ação em massa de **conversas e
|
|
361
|
+
> contatos** (`type: Conversation` ou `Contact`). Card do Kanban tem as **três** ferramentas
|
|
362
|
+
> listadas acima, todas com `item_ids: [...]`, e nenhuma delas aceita etiqueta.
|
|
331
363
|
|
|
332
364
|
**Pro MCP:** se uma conversa/card "some" da listagem ou dá 404 pra um agente que jura que existe,
|
|
333
365
|
provavelmente é acesso por caixa — explique que ele só vê as caixas das quais participa, e que o
|