@lionchat/mcp-server 1.9.0 → 1.10.1
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 +222 -13
- package/dist/docs/resources/data-model.md +16 -7
- 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 +220 -122
- 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
|
|
|
@@ -359,6 +420,154 @@ POST /api/v1/accounts/{account_id}/automation_rules
|
|
|
359
420
|
"event_name": "conversation_updated",
|
|
360
421
|
"action_types": ["label_added"],
|
|
361
422
|
"conditions": [{"attribute_key": "labels", "filter_operator": "contains", "values": ["vip"]}],
|
|
362
|
-
"actions": [{"action_name": "send_email_to_team", "action_params": {"team_ids": [1], "message": "VIP!"}}]
|
|
423
|
+
"actions": [{"action_name": "send_email_to_team", "action_params": [{"team_ids": [1], "message": "VIP!"}]}]
|
|
363
424
|
}
|
|
364
425
|
```
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## Condicoes de automacao — e a REGRA DO CONECTOR
|
|
430
|
+
|
|
431
|
+
```json
|
|
432
|
+
"conditions": [
|
|
433
|
+
{"attribute_key": "status", "filter_operator": "equal_to", "values": ["resolved"], "query_operator": "AND"},
|
|
434
|
+
{"attribute_key": "labels", "filter_operator": "equal_to", "values": ["vip"], "query_operator": null}
|
|
435
|
+
]
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### O conector (`query_operator`) — leia isto antes de gravar
|
|
439
|
+
|
|
440
|
+
O conector **liga a condicao com a SEGUINTE**. Logo:
|
|
441
|
+
|
|
442
|
+
- A **ULTIMA** condicao **TEM** que ter `query_operator: null`.
|
|
443
|
+
- Condicao **UNICA** = `query_operator: null` (nao ha proxima pra ligar).
|
|
444
|
+
- Valores aceitos nas demais: `"AND"` ou `"OR"`.
|
|
445
|
+
|
|
446
|
+
> **A API valida o VALOR do conector, mas NAO a POSICAO.** Conector na ultima condicao **salva com
|
|
447
|
+
> sucesso**, aparece certo na tela — e a regra nunca dispara.
|
|
448
|
+
>
|
|
449
|
+
> Incidente real: **8 regras criadas pelo conector de IA entre 26 e 30/07/2026, em 3 contas
|
|
450
|
+
> diferentes, todas com conector na ultima condicao. Todas nasceram mortas.** A pergunta ao banco
|
|
451
|
+
> saia pela metade (`... IN ($1) and`), o erro era engolido e a regra respondia "nada casou". A conta
|
|
452
|
+
> 62 ficou com as **6** regras de etiquetagem automatica paradas. Medido em producao em 03/08:
|
|
453
|
+
> **732 erros por hora**.
|
|
454
|
+
>
|
|
455
|
+
> O motor foi corrigido em 03/08 (a limpeza acontece ao montar a consulta), entao regra torta nao
|
|
456
|
+
> quebra mais. **Mas continue gravando certo:** a tela de edicao le o dado cru e formato errado
|
|
457
|
+
> aparece estranho ali — mesmo efeito do campo de template que sumia da tela.
|
|
458
|
+
|
|
459
|
+
### Campos da condicao
|
|
460
|
+
|
|
461
|
+
| Campo | Obrigatorio | O que e |
|
|
462
|
+
|---|---|---|
|
|
463
|
+
| `attribute_key` | SIM | Campo padrao (ver abaixo) ou a chave de um atributo personalizado que **exista na conta** |
|
|
464
|
+
| `filter_operator` | SIM | Como comparar |
|
|
465
|
+
| `values` | SIM (menos em `is_present`/`is_not_present`) | Array, sempre |
|
|
466
|
+
| `query_operator` | SIM em todas | `"AND"`/`"OR"`; **`null` na ultima** |
|
|
467
|
+
| `custom_attribute_type` | so p/ atributo personalizado | `conversation_attribute` ou `contact_attribute` |
|
|
468
|
+
|
|
469
|
+
### Operadores de filtro
|
|
470
|
+
|
|
471
|
+
`equal_to`, `not_equal_to`, `contains`, `does_not_contain`, `is_present`, `is_not_present`,
|
|
472
|
+
`is_greater_than`, `is_less_than`, `starts_with`, `days_before`, `days_ago`, `last_days`, `today`,
|
|
473
|
+
`yesterday`.
|
|
474
|
+
|
|
475
|
+
**Cada campo aceita so um subconjunto.** Operador que o campo nao aceita faz a regra inteira falhar
|
|
476
|
+
na validacao. Na duvida, leia uma regra que ja funciona com `lionchat_automation_rules_show` e copie.
|
|
477
|
+
|
|
478
|
+
### Chave que a conta nao conhece
|
|
479
|
+
|
|
480
|
+
Se `attribute_key` nao for um campo padrao **nem** um atributo personalizado existente na conta, a
|
|
481
|
+
regra **inteira** falha na validacao e nunca dispara — erro
|
|
482
|
+
`Automation conditions <chave> not supported`. Aconteceu de verdade na conta 62 (`tipo_interesse`).
|
|
483
|
+
Antes de usar atributo personalizado numa condicao, confirme que ele existe com
|
|
484
|
+
`lionchat_custom_attributes_list`.
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
## Acoes de automacao — formato do `action_params`
|
|
489
|
+
|
|
490
|
+
> **REGRA DE OURO:** `action_params` e SEMPRE um **array**, mesmo quando so tem um item.
|
|
491
|
+
> O backend le `params[0]`. Passar um objeto solto (`{...}` em vez de `[{...}]`) quebra a acao.
|
|
492
|
+
|
|
493
|
+
> **PERIGO — falha silenciosa:** o `action_params` e um campo livre (JSONB). A API **aceita e grava
|
|
494
|
+
> qualquer formato**, sem validar. Se as chaves estiverem erradas, a regra e salva com sucesso, o
|
|
495
|
+
> painel mostra a acao na tela, e na hora de disparar ela **nao faz nada e nao registra erro nenhum**
|
|
496
|
+
> — sem log, sem mensagem falhada, sem aviso. Por isso: **nunca invente nome de chave**. Se a acao
|
|
497
|
+
> nao estiver documentada abaixo, leia uma regra existente com `lionchat_automation_rules_show` e
|
|
498
|
+
> copie o formato exato dela.
|
|
499
|
+
>
|
|
500
|
+
> Incidente real (conta 39, 02-03/08/2026): uma IA gravou `template_name`/`template_id` em vez de
|
|
501
|
+
> `name`/`id`. A regra ficou 14 horas sem enviar nada, 9 leads pagos entraram e ninguem foi avisado.
|
|
502
|
+
|
|
503
|
+
### `send_whatsapp_template` — ATENCAO ESPECIAL
|
|
504
|
+
|
|
505
|
+
Envia um modelo aprovado da Meta. **So funciona em caixa WhatsApp API Oficial (Cloud).**
|
|
506
|
+
|
|
507
|
+
```json
|
|
508
|
+
{
|
|
509
|
+
"action_name": "send_whatsapp_template",
|
|
510
|
+
"action_params": [{
|
|
511
|
+
"name": "confirmacao_pedido",
|
|
512
|
+
"id": "1071396275361941",
|
|
513
|
+
"language": "pt_BR",
|
|
514
|
+
"category": "UTILITY",
|
|
515
|
+
"processed_params": {"body": {"1": "{{contact.first_name}}"}}
|
|
516
|
+
}]
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
| Chave | Obrigatoria | O que e |
|
|
521
|
+
|---|---|---|
|
|
522
|
+
| `name` | **SIM** | Nome EXATO do modelo aprovado na Meta. E por ele que o envio acontece |
|
|
523
|
+
| `id` | nao | ID do modelo na Meta. Serve so de reserva se `name` faltar |
|
|
524
|
+
| `language` | nao (padrao `pt_BR`) | Precisa bater com o idioma do modelo aprovado |
|
|
525
|
+
| `category` | nao | `UTILITY`, `MARKETING` ou `AUTHENTICATION` |
|
|
526
|
+
| `processed_params` | nao | Valores das variaveis: `{"body": {"1": "...", "2": "..."}}`. Aceita Liquid (`{{contact.first_name}}`) |
|
|
527
|
+
|
|
528
|
+
**NUNCA use `template_name`, `template_id`, `template_category` nem `template_language` aqui.**
|
|
529
|
+
Esse e o formato dos **nos do FlowBuilder**, que e outra coisa. Na automacao, essas chaves sao
|
|
530
|
+
ignoradas e a acao vira um nada silencioso.
|
|
531
|
+
|
|
532
|
+
Antes de gravar, confirme que o modelo existe e esta aprovado com
|
|
533
|
+
`lionchat_inboxes_whatsapp_templates_list` — o envio so acha o modelo se `name` + `language`
|
|
534
|
+
casarem e o status for `approved`.
|
|
535
|
+
|
|
536
|
+
### Demais acoes
|
|
537
|
+
|
|
538
|
+
Todos os formatos abaixo foram conferidos linha a linha em `app/services/action_service.rb` e
|
|
539
|
+
`app/services/automation_rules/action_service.rb`.
|
|
540
|
+
|
|
541
|
+
| `action_name` | `action_params` |
|
|
542
|
+
|---|---|
|
|
543
|
+
| `send_message` | `["texto da mensagem"]` |
|
|
544
|
+
| `add_private_note` | `["nota interna"]` |
|
|
545
|
+
| `send_canned_response` | `[12]` — id da resposta pronta |
|
|
546
|
+
| `add_label` / `remove_label` | `["etiqueta1", "etiqueta2"]` |
|
|
547
|
+
| `assign_agent` | `[70]` — o agente precisa ser membro da caixa. `["nil"]` desatribui |
|
|
548
|
+
| `assign_team` | `[3]`. `["nil"]` desatribui |
|
|
549
|
+
| `assign_captain_assistant` | `[17]` ou `[{"assistant_id": 17, "proactive": true}]` — `proactive` false = a IA assume mas nao fala na hora |
|
|
550
|
+
| `send_email_to_team` | `[{"team_ids": [1], "message": "texto"}]` |
|
|
551
|
+
| `send_webhook_event` | `["https://..."]` |
|
|
552
|
+
| `send_attachment` | `[blob_ids]` — so funciona se a regra ja tiver arquivo anexado; nao da pra montar so por API |
|
|
553
|
+
| `change_status` | `["resolved"]`, `["open"]`, `["pending"]` ou `["snoozed"]` |
|
|
554
|
+
| `change_priority` | `["urgent"]`, `["high"]`, `["medium"]`, `["low"]`. `["nil"]` limpa |
|
|
555
|
+
| `send_email_transcript` | `["a@b.com,c@d.com"]` — UMA string, varios e-mails separados por virgula |
|
|
556
|
+
| `mute_conversation` | `[]` |
|
|
557
|
+
| `snooze_conversation` | `[]` |
|
|
558
|
+
| `resolve_conversation` / `open_conversation` / `pending_conversation` | `[]` |
|
|
559
|
+
| `update_contact_attribute` / `update_conversation_attribute` | `[{"attribute_key": "chave", "value": "texto ou {{contact.phone_number}}"}]` |
|
|
560
|
+
| `create_kanban_item` | `[{"funnel_id": 31, "funnel_stage": "prospeccao", "allow_duplicates": false}]` |
|
|
561
|
+
| `move_kanban_item_to_stage` | `[{"funnel_id": 31, "funnel_stage": "qualificacao"}]` |
|
|
562
|
+
| `assign_agent_to_kanban_item` | `[{"funnel_id": 31, "agent_id": 70, "mode": "add"}]` — `mode` aceita `add` (padrao) ou `remove_all` |
|
|
563
|
+
| `add_note_to_kanban_item` | `[{"funnel_id": 31, "text": "texto da nota"}]` — a chave e **`text`**, nao `note` |
|
|
564
|
+
| `set_kanban_item_status` | `[{"funnel_id": 31, "status": "won"}]` — `won`, `lost` ou `open`. Status fora disso e ignorado |
|
|
565
|
+
| `start_kanban_item_timer` / `stop_kanban_item_timer` | `[{"funnel_id": 31}]` |
|
|
566
|
+
|
|
567
|
+
**Acoes de Kanban:** todas precisam que a conversa ja tenha um card no funil informado. Sem card,
|
|
568
|
+
a acao e pulada (fica so no log do servidor). Use `create_kanban_item` antes, na mesma regra.
|
|
569
|
+
|
|
570
|
+
Lista autoritativa de nomes validos: `AutomationRule#actions_attributes` no backend. Nome de acao
|
|
571
|
+
fora dessa lista e recusado com 422 ao salvar — isso a API valida. O que ela **nao** valida e o
|
|
572
|
+
conteudo do `action_params`. `apply_kanban_checklist_template` existe no motor mas **nao** e uma
|
|
573
|
+
acao de automacao valida (e so do FlowBuilder) — usar aqui devolve 422.
|
|
@@ -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),
|
|
@@ -388,11 +396,12 @@ Booking (agendamento confirmado)
|
|
|
388
396
|
|
|
389
397
|
## e-Clínicas (Efficient) — integração de clínicas
|
|
390
398
|
|
|
391
|
-
|
|
399
|
+
13 eventos de webhook, cada um mapeável a automação OU flow na tela Integrações > e-Clínica:
|
|
392
400
|
`cliente_novo`, `agendamento_novo`, `falta`, `pagamento` (os 4 da doc oficial) +
|
|
393
401
|
`agendamento_atendido`, `agendamento_alterado`, `agendamento_desmarcado`,
|
|
394
|
-
`agendamento_transferido`, `cliente_baixa_pagamento`
|
|
395
|
-
|
|
402
|
+
`agendamento_transferido`, `cliente_baixa_pagamento`, `cliente_alteracao`,
|
|
403
|
+
`cliente_inclusao_pagamento`, `controle_laboratorio_novo`, `controle_laboratorio_alterado`
|
|
404
|
+
(capturados ao vivo, não documentados pelo e-Clínica).
|
|
396
405
|
|
|
397
406
|
Atributos de sistema no CONTATO (prefixo `eclinica_`, protegidos, usáveis como variável):
|
|
398
407
|
|
|
@@ -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`.
|