feat: add CRM templates

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2026-03-14 16:35:42 -03:00
parent 5db33107da
commit 1c026e3dcd
18 changed files with 1022 additions and 0 deletions

View file

@ -0,0 +1,40 @@
PARAM title AS STRING LIKE "Equipamento com defeito" DESCRIPTION "Título do problema"
PARAM category AS STRING LIKE "support" DESCRIPTION "Categoria: support, billing, sales, bug" OPTIONAL
PARAM priority AS STRING LIKE "high" DESCRIPTION "Nível: low, normal, high, urgent" OPTIONAL
PARAM contact_email AS EMAIL LIKE "usuario@dominio.com" DESCRIPTION "Email do reclamante" OPTIONAL
PARAM description AS STRING LIKE "O mouse parou" DESCRIPTION "Detalhes da solicitação"
DESCRIPTION "Cria um Ticket de suporte de longo prazo no sistema, fora da fila de atendimento tempo-real."
IF NOT category THEN
category = "support"
END IF
IF NOT priority THEN
priority = "normal"
END IF
contact_id = ""
IF contact_email THEN
existing = GET "/api/crm/contacts?search=" + contact_email
IF UBOUND(existing) > 0 THEN
contact_id = FIRST(existing).id
END IF
END IF
new_ticket = POST "/api/tickets", #{
title: title,
description: description,
category: category,
priority: priority,
status: "open",
contact_id: contact_id
}
TALK "🎫 **Ticket Criado com Sucesso!**"
TALK "ID: " + new_ticket.id
TALK "Título: " + title
TALK "Prioridade: " + priority
TALK "A equipe será notificada para escalonamento conforme SLA."
RETURN new_ticket.id

View file

@ -0,0 +1,63 @@
PARAM session_id AS STRING LIKE "uuid" DESCRIPTION "ID da sessão atendida" OPTIONAL
PARAM status AS STRING LIKE "resolved" DESCRIPTION "Finalizar o chat ou aguardar (resolved, pending_customer)" OPTIONAL
PARAM summary AS STRING LIKE "Dúvida resolvida com sucesso" DESCRIPTION "Breve resumo da solução" OPTIONAL
DESCRIPTION "Resolve a conversa, registrando o final no CRM (atividade) ou deixa pendente pelo cliente."
IF NOT status THEN
status = "resolved"
END IF
IF status = "resolved" THEN
IF NOT summary THEN
TALK "A sessão foi totalmente concluída? Qual seria o resumo?"
HEAR summary AS STRING
END IF
END IF
' Tratar ID da sessão conversacionalmente
IF NOT session_id THEN
my_sessions = GET "/api/attendance/queue?status=active"
IF UBOUND(my_sessions) = 0 THEN
TALK "Você não tem nenhuma sessão de atendimento ativa no momento."
RETURN
END IF
IF UBOUND(my_sessions) = 1 THEN
session_id = FIRST(my_sessions).session_id
ELSE
TALK "Você tem várias sessões ativas. Qual delas quer resolver? Diga o nome do cliente."
FOR EACH s IN my_sessions
TALK "- **" + s.user_name + "**"
NEXT s
HEAR query AS STRING
FOR EACH s IN my_sessions
IF INSTR(LCASE(s.user_name), LCASE(query)) > 0 THEN
session_id = s.session_id
END IF
NEXT s
IF NOT session_id THEN
TALK "Sessão não identificada."
RETURN
END IF
END IF
END IF
resolution_payload = #{
status: status,
resolution_summary: summary,
resolved_by: GET "session.user_id",
resolved_at: FORMAT(NOW(), "YYYY-MM-DD HH:mm:ss")
}
PUT "/api/attendance/sessions/" + session_id + "/resolve", resolution_payload
IF status = "resolved" THEN
TALK "✅ **Atendimento Encerrado!**"
TALK "A conversa foi marcada como **Resolvida**."
TALK "Resumo: " + summary
ELSE
TALK "⏳ **Aguardando Cliente**"
TALK "O atendimento ficará pausado aguardando retorno do cliente."
END IF
RETURN session_id

View file

@ -0,0 +1,48 @@
ADD TOOL "view-queue"
ADD TOOL "take-next"
ADD TOOL "transfer-chat"
ADD TOOL "resolve-chat"
ADD TOOL "queue-stats"
ADD TOOL "create-ticket"
SET CONTEXT "attendance" AS "You are a customer service assistant for General Bots. You help attendants manage the support queue: view waiting customers, take conversations, transfer between attendants, resolve cases, and create tickets. All actions affect real sessions in the database."
CLEAR SUGGESTIONS
ADD SUGGESTION "queue" AS "Ver fila de espera"
ADD SUGGESTION "take" AS "Atender próximo"
ADD SUGGESTION "transfer" AS "Transferir conversa"
ADD SUGGESTION "resolve" AS "Resolver conversa"
BEGIN TALK
**Atendimento Gestão de Fila**
Posso ajudar com:
Ver a fila de clientes aguardando
Atender o próximo da fila
Transferir conversa para outro atendente
Resolver/encerrar conversa
Criar ticket de suporte
Ver estatísticas do atendimento
O que deseja?
END TALK
BEGIN SYSTEM PROMPT
You are a customer service queue manager.
Queue statuses:
- new: Just arrived, not yet in queue
- waiting: In queue, waiting for an attendant
- active: Being handled by an attendant
- pending_customer: Waiting for customer reply
- resolved: Completed
Key rules:
- Always show the customer's name and channel (WhatsApp, Web, Telegram, etc.)
- Show how long the customer has been waiting
- When transferring, always ask for the reason
- When resolving, ask if the customer's issue was fully resolved
- Prioritize customers who have been waiting the longest
- If a customer is from a known CRM contact, show their company and deal info
END SYSTEM PROMPT

View file

@ -0,0 +1,27 @@
PARAM session_id AS STRING LIKE "uuid" DESCRIPTION "ID da sessão (opcional). Se vazio, pega o próximo da fila." OPTIONAL
DESCRIPTION "Atender o próximo cliente da fila ou um cliente específico."
IF NOT session_id THEN
' Tentar pegar o mais antigo da fila ("waiting", sem assignee)
queue = GET "/api/attendance/queue?status=waiting"
IF UBOUND(queue) = 0 THEN
TALK "A fila está vazia no momento. Bom trabalho!"
RETURN
END IF
' Pega o primeiro (mais antigo, se a API ordenar por tempo de espera)
first_item = FIRST(queue)
session_id = first_item.session_id
END IF
' Endpoint hipotético para "tomar posse" da sessão
assign_result = POST "/api/attendance/sessions/" + session_id + "/assign", #{
attendant_id: GET "session.user_id"
}
TALK "✅ **Sessão atribuída a você!**"
TALK "Você agora está atendendo: " + assign_result.user_name + " via " + assign_result.channel
TALK "Use as ferramentas de chat para conversar com o cliente."
RETURN session_id

View file

@ -0,0 +1,66 @@
PARAM session_id AS STRING LIKE "uuid" DESCRIPTION "ID da sessão" OPTIONAL
PARAM skill AS STRING LIKE "suporte" DESCRIPTION "Habilidade ou fila destino (ex: financeiro, vendas)" OPTIONAL
PARAM priority AS STRING LIKE "high" DESCRIPTION "Nova prioridade (urgent, high, normal, low)" OPTIONAL
PARAM reason AS STRING LIKE "Dúvida sobre boleto" DESCRIPTION "Motivo da transferência (obrigatório)"
DESCRIPTION "Transfere o chat para outro nível de suporte ou fila usando Habilidades, ajustando prioridade."
IF NOT reason THEN
TALK "Qual é o motivo da transferência para o próximo atendente?"
HEAR reason AS STRING
END IF
IF NOT priority THEN
priority = "normal"
END IF
' Tratar ID da sessão conversacionalmente
IF NOT session_id THEN
' Busca sessões ativas do atendente
my_sessions = GET "/api/attendance/queue?status=active"
IF UBOUND(my_sessions) = 0 THEN
TALK "Você não tem nenhuma sessão de atendimento ativa no momento para transferir."
RETURN
END IF
IF UBOUND(my_sessions) = 1 THEN
session_id = FIRST(my_sessions).session_id
ELSE
TALK "Você tem " + UBOUND(my_sessions) + " atendimentos ativos. Vou mostrar os nomes, por favor diga qual deseja transferir:"
FOR EACH s IN my_sessions
TALK "- **" + s.user_name + "** via " + s.channel
NEXT s
HEAR query AS STRING
' Busca simplificada
FOR EACH s IN my_sessions
IF INSTR(LCASE(s.user_name), LCASE(query)) > 0 THEN
session_id = s.session_id
END IF
NEXT s
IF NOT session_id THEN
TALK "Não consegui identificar a sessão."
RETURN
END IF
END IF
END IF
' TRANSFER TO HUMAN envia para a roleta novamente
' No BASIC real, seria executado ou POSTado na API de transferência
transfer_payload = #{
required_skill: skill,
priority: priority,
transfer_reason: reason,
transferred_by: GET "session.user_id"
}
POST "/api/attendance/sessions/" + session_id + "/transfer", transfer_payload
TALK "✅ **Sessão Transferida!**"
TALK "Motivo: " + reason
IF skill THEN
TALK "Aguardando um especialista em **" + skill + "**"
ELSE
TALK "Aguardando o próximo atendente livre."
END IF
RETURN session_id

View file

@ -0,0 +1,43 @@
PARAM status AS STRING LIKE "waiting" DESCRIPTION "Filtrar por status: waiting, active, all" OPTIONAL
DESCRIPTION "Ver a fila de atendimento: quem está aguardando, há quanto tempo, e por qual canal."
IF NOT status THEN
status = "waiting"
END IF
queue = GET "/api/attendance/queue?status=" + status
item_count = UBOUND(queue)
IF item_count = 0 THEN
TALK "✅ Fila vazia! Nenhum cliente aguardando."
RETURN
END IF
TALK "📋 **Fila de Atendimento — " + item_count + " cliente(s)**"
TALK ""
FOR EACH item IN queue
channel_icon = "💬"
IF item.channel = "whatsapp" THEN
channel_icon = "📱"
ELSE IF item.channel = "telegram" THEN
channel_icon = "✈️"
ELSE IF item.channel = "email" THEN
channel_icon = "📧"
END IF
TALK "---"
TALK channel_icon + " **" + item.user_name + "** via " + item.channel
TALK "⏱️ Aguardando há " + item.wait_time
TALK "💬 Última mensagem: " + item.last_message
IF item.assigned_to THEN
TALK "👤 Atendente: " + item.assigned_to
END IF
TALK "🔗 Session: " + item.session_id
NEXT item
RETURN queue

View file

@ -0,0 +1,77 @@
PARAM deal_id AS STRING LIKE "uuid" DESCRIPTION "ID do deal a fechar" OPTIONAL
PARAM won AS BOOLEAN LIKE TRUE DESCRIPTION "TRUE se ganhou, FALSE se perdeu"
PARAM lost_reason AS STRING LIKE "Preço acima do mercado" DESCRIPTION "Motivo da perda (obrigatório se won=FALSE)" OPTIONAL
DESCRIPTION "Fechar um deal como ganho (won) ou perdido (lost). Se perdido, informe o motivo."
IF NOT deal_id OR deal_id = "uuid" THEN
TALK "Qual deal você deseja fechar? (Diga o nome da empresa ou título)"
HEAR query AS STRING
deals = GET "/api/crm/deals?search=" + query + "&limit=5"
IF UBOUND(deals) = 0 THEN
TALK "Não encontrei nenhum deal relacionado a '" + query + "'."
RETURN
END IF
IF UBOUND(deals) = 1 THEN
deal_id = FIRST(deals).id
ELSE
TALK "Encontrei várias opções. Qual delas quer fechar? Especifique melhor, por favor."
FOR EACH d IN deals
TALK "- **" + d.title + "** (" + d.stage + ")"
NEXT d
RETURN
END IF
END IF
deal = GET "/api/crm/deals/" + deal_id
IF NOT deal THEN
TALK "Deal não encontrado: " + deal_id
RETURN
END IF
IF won THEN
PUT "/api/crm/deals/" + deal_id, #{
stage: "won",
won: TRUE,
probability: 100,
actual_close_date: FORMAT(TODAY(), "YYYY-MM-DD")
}
POST "/api/crm/activities", #{
activity_type: "deal_won",
subject: "Deal ganho: " + deal.title,
contact_id: deal.contact_id,
account_id: deal.account_id
}
TALK "🎉 **Deal ganho!**"
TALK "**" + deal.title + "** — R$ " + FORMAT(deal.value, "#,##0")
TALK "Parabéns pela conquista!"
ELSE
IF NOT lost_reason THEN
TALK "Qual foi o motivo da perda?"
HEAR lost_reason AS STRING
END IF
PUT "/api/crm/deals/" + deal_id, #{
stage: "lost",
won: FALSE,
probability: 0,
lost_reason: lost_reason,
actual_close_date: FORMAT(TODAY(), "YYYY-MM-DD")
}
POST "/api/crm/activities", #{
activity_type: "deal_lost",
subject: "Deal perdido: " + deal.title,
description: "Motivo: " + lost_reason,
contact_id: deal.contact_id,
account_id: deal.account_id
}
TALK "📋 **Deal perdido**"
TALK "**" + deal.title + "** — Motivo: " + lost_reason
TALK "Use essa experiência para os próximos negócios."
END IF
RETURN deal_id

View file

@ -0,0 +1,106 @@
PARAM title AS STRING LIKE "Contrato Empresa ABC" DESCRIPTION "Título do deal ou oportunidade"
PARAM contact_email AS EMAIL LIKE "joao@empresa.com" DESCRIPTION "Email do contato principal"
PARAM contact_name AS STRING LIKE "João Silva" DESCRIPTION "Nome do contato" OPTIONAL
PARAM company AS STRING LIKE "Empresa ABC Ltda" DESCRIPTION "Nome da empresa/conta" OPTIONAL
PARAM value AS MONEY LIKE 50000 DESCRIPTION "Valor estimado do deal"
PARAM stage AS STRING LIKE "new" DESCRIPTION "Estágio inicial: new, qualified, proposal, negotiation" OPTIONAL
PARAM source AS STRING LIKE "WHATSAPP" DESCRIPTION "Origem: WHATSAPP, EMAIL, CALL, WEBSITE, REFERAL, PARTNER, CHAT" OPTIONAL
PARAM close_date AS DATE LIKE "2026-06-30" DESCRIPTION "Data prevista de fechamento" OPTIONAL
PARAM notes AS STRING LIKE "Conheceu na feira" DESCRIPTION "Observações sobre o deal" OPTIONAL
DESCRIPTION "Criar um novo deal no pipeline de vendas. Registra o negócio com valor, estágio, contato e empresa."
IF NOT stage THEN
stage = "new"
END IF
IF NOT source THEN
source = "CHAT"
END IF
IF NOT close_date THEN
close_date = DATEADD(TODAY(), 30, "day")
END IF
' Determine probability based on stage
probability = 10
IF stage = "qualified" THEN
probability = 30
ELSE IF stage = "proposal" THEN
probability = 50
ELSE IF stage = "negotiation" THEN
probability = 70
END IF
' Check if contact exists, create if not
contact_id = ""
IF contact_email THEN
existing = GET "/api/crm/contacts?search=" + contact_email
IF UBOUND(existing) > 0 THEN
contact_id = FIRST(existing).id
TALK "Contato encontrado: " + FIRST(existing).first_name + " " + FIRST(existing).last_name
ELSE
' Create contact
IF NOT contact_name THEN
contact_name = "Contato"
END IF
parts = SPLIT(contact_name, " ")
first_name = FIRST(parts)
last_name = LAST(parts)
new_contact = POST "/api/crm/contacts", #{
first_name: first_name,
last_name: last_name,
email: contact_email,
company: company,
source: source
}
contact_id = new_contact.id
TALK "Novo contato criado: " + contact_name
END IF
END IF
' Check if account exists, create if not
account_id = ""
IF company THEN
existing_acc = GET "/api/crm/accounts?search=" + company
IF UBOUND(existing_acc) > 0 THEN
account_id = FIRST(existing_acc).id
ELSE
new_account = POST "/api/crm/accounts", #{
name: company
}
account_id = new_account.id
TALK "Nova conta criada: " + company
END IF
END IF
' Create the deal
deal = POST "/api/crm/deals", #{
title: title,
value: value,
stage: stage,
probability: probability,
source: source,
expected_close_date: close_date,
contact_id: contact_id,
account_id: account_id,
notes: notes
}
TALK "✅ **Deal criado com sucesso!**"
TALK ""
TALK "**" + title + "**"
TALK "💰 Valor: R$ " + FORMAT(value, "#,##0")
TALK "📊 Estágio: " + stage + " (" + probability + "% probabilidade)"
TALK "📅 Previsão de fechamento: " + close_date
IF company THEN
TALK "🏢 Empresa: " + company
END IF
IF contact_email THEN
TALK "👤 Contato: " + contact_email
END IF
RETURN deal.id

View file

@ -0,0 +1,50 @@
PARAM query AS STRING LIKE "Acme" DESCRIPTION "Nome da empresa, pessoa ou título do deal"
PARAM return_id_only AS BOOLEAN LIKE TRUE DESCRIPTION "Se TRUE retorna apenas o ID. Se FALSE, descreve as opções ao usuário." OPTIONAL
DESCRIPTION "Procura por um deal pelo nome da empresa, título ou pessoa. Usado por outros tools para não obrigar o humano a saber UUIDs."
IF NOT return_id_only THEN return_id_only = TRUE
' Search API (assuming ?search= looks at title, contact email/name, and account name)
deals = GET "/api/crm/deals?search=" + query + "&limit=5"
count = UBOUND(deals)
IF count = 0 THEN
TALK "Não encontrei nenhum deal relacionado a '" + query + "'."
RETURN ""
END IF
IF count = 1 THEN
found_deal = FIRST(deals)
IF NOT return_id_only THEN
TALK "Encontrei: **" + found_deal.title + "** (R$ " + FORMAT(found_deal.value, "#,##0") + ", " + found_deal.stage + ")"
END IF
RETURN found_deal.id
END IF
' If multiple matches found, ask user to disambiguate
TALK "Encontrei " + count + " opções para '" + query + "'. Qual delas?"
idx = 1
FOR EACH d IN deals
TALK idx + ". **" + d.title + "** (" + d.stage + ") - R$ " + FORMAT(d.value, "#,##0")
idx = idx + 1
NEXT d
HEAR choice
' Simple index selection logic (assuming user types "1", "2")
choice_num = TO_NUMBER(choice)
IF choice_num > 0 AND choice_num <= count THEN
selected = deals[choice_num - 1]
RETURN selected.id
ELSE
' Fallback to string matching on title
FOR EACH d IN deals
IF INSTR(LCASE(d.title), LCASE(choice)) > 0 THEN
RETURN d.id
END IF
NEXT d
END IF
TALK "Desculpe, não consegui identificar qual você escolheu."
RETURN ""

View file

@ -0,0 +1,60 @@
PARAM stage AS STRING LIKE "proposal" DESCRIPTION "Filtrar por estágio: new, qualified, proposal, negotiation, won, lost" OPTIONAL
PARAM owner AS STRING LIKE "joao@empresa.com" DESCRIPTION "Filtrar por dono do deal" OPTIONAL
DESCRIPTION "Listar deals do pipeline de vendas. Pode filtrar por estágio e por dono."
url = "/api/crm/deals?"
IF stage THEN
url = url + "stage=" + stage + "&"
END IF
IF owner THEN
url = url + "search=" + owner + "&"
END IF
url = url + "limit=20"
deals = GET url
deal_count = UBOUND(deals)
IF deal_count = 0 THEN
TALK "Nenhum deal encontrado com os filtros informados."
RETURN
END IF
TALK "📊 **Pipeline — " + deal_count + " deal(s) encontrado(s)**"
TALK ""
total_value = 0
total_weighted = 0
FOR EACH deal IN deals
prob = deal.probability
weighted = deal.value * prob / 100
total_value = total_value + deal.value
total_weighted = total_weighted + weighted
TALK "---"
TALK "**" + deal.title + "**"
TALK "💰 R$ " + FORMAT(deal.value, "#,##0") + " | " + deal.stage + " (" + prob + "%)"
IF deal.expected_close_date THEN
TALK "📅 Previsão: " + deal.expected_close_date
END IF
IF deal.contact_id THEN
contact = GET "/api/crm/contacts/" + deal.contact_id
IF contact THEN
TALK "👤 " + contact.first_name + " " + contact.last_name
END IF
END IF
NEXT deal
TALK ""
TALK "**Totais:**"
TALK "💰 Valor total: R$ " + FORMAT(total_value, "#,##0")
TALK "📊 Valor ponderado: R$ " + FORMAT(total_weighted, "#,##0")
RETURN deals

View file

@ -0,0 +1,54 @@
PARAM activity_type AS STRING LIKE "call" DESCRIPTION "Tipo: call, email, meeting, note, follow_up"
PARAM subject AS STRING LIKE "Ligação de follow-up" DESCRIPTION "Assunto da atividade"
PARAM contact_email AS EMAIL LIKE "joao@empresa.com" DESCRIPTION "Email do contato relacionado" OPTIONAL
PARAM deal_id AS STRING LIKE "uuid" DESCRIPTION "ID do deal relacionado" OPTIONAL
PARAM description AS STRING LIKE "Discutimos termos do contrato" DESCRIPTION "Detalhes da atividade" OPTIONAL
PARAM due_date AS DATE LIKE "2026-04-01" DESCRIPTION "Data de follow-up" OPTIONAL
DESCRIPTION "Registrar uma atividade de CRM: ligação, email, reunião, nota ou follow-up. Pode vincular a contato e/ou deal."
' Resolve contact_id from email
contact_id = ""
IF contact_email THEN
contacts = GET "/api/crm/contacts?search=" + contact_email
IF UBOUND(contacts) > 0 THEN
contact_id = FIRST(contacts).id
END IF
END IF
' Resolve deal_id if empty or uuid but we need it
IF NOT deal_id OR deal_id = "uuid" THEN
TALK "A qual deal esta atividade se refere? (Opcional: Diga 'nenhum' ou o nome da empresa)"
HEAR query AS STRING
IF LCASE(query) != "nenhum" AND LCASE(query) != "none" THEN
deals = GET "/api/crm/deals?search=" + query + "&limit=5"
IF UBOUND(deals) > 0 THEN
deal_id = FIRST(deals).id
TALK "Atividade será vinculada ao deal: " + FIRST(deals).title
END IF
ELSE
deal_id = ""
END IF
END IF
' Create activity
activity = POST "/api/crm/activities", #{
activity_type: activity_type,
subject: subject,
description: description,
contact_id: contact_id,
due_date: due_date
}
TALK "✅ **Atividade registrada!**"
TALK "📋 " + activity_type + ": " + subject
IF contact_email THEN
TALK "👤 Contato: " + contact_email
END IF
IF due_date THEN
TALK "📅 Follow-up: " + due_date
END IF
RETURN activity.id

View file

@ -0,0 +1,21 @@
DESCRIPTION "Exibe resumo do pipeline de vendas: total por estágio, valor, taxa de conversão."
stats = GET "/api/crm/stats"
stages = GET "/api/crm/pipeline"
TALK "📊 **Resumo do Pipeline de Vendas**"
TALK ""
TALK "💰 Valor total no pipeline: R$ " + FORMAT(stats.total_value, "#,##0")
TALK "🏆 Valor ganho: R$ " + FORMAT(stats.won_value, "#,##0")
TALK "📈 Taxa de conversão: " + FORMAT(stats.conversion_rate, "#0.0") + "%"
TALK "📐 Ticket médio: R$ " + FORMAT(stats.avg_deal_size, "#,##0")
TALK ""
IF stats.stages THEN
TALK "**Por estágio:**"
FOR EACH sg IN stats.stages
TALK " " + sg.name + ": " + sg.count + " deals — R$ " + FORMAT(sg.total_value, "#,##0")
NEXT sg
END IF
RETURN stats

View file

@ -0,0 +1,52 @@
ADD TOOL "create-deal"
ADD TOOL "update-deal"
ADD TOOL "list-deals"
ADD TOOL "close-deal"
ADD TOOL "add-contact"
ADD TOOL "search-contact"
ADD TOOL "add-account"
ADD TOOL "log-activity"
ADD TOOL "pipeline-summary"
SET CONTEXT "crm" AS "You are a CRM sales assistant for General Bots. You help salespeople create and manage deals, contacts, and accounts. All data is stored in PostgreSQL via the API. Deals follow a unified pipeline: new → qualified → proposal → negotiation → won/lost. There are no separate 'leads' or 'opportunities' — everything is a Deal with a stage. Business units are Departments from people_departments."
CLEAR SUGGESTIONS
ADD SUGGESTION "newdeal" AS "Criar um novo deal"
ADD SUGGESTION "pipeline" AS "Ver meu pipeline"
ADD SUGGESTION "contacts" AS "Buscar contato"
ADD SUGGESTION "report" AS "Relatório de vendas"
BEGIN TALK
**CRM Gestão de Vendas**
Posso ajudar com:
Criar e gerenciar deals (negócios)
Buscar e cadastrar contatos
Cadastrar contas (empresas)
Atualizar estágios do pipeline
Relatórios e previsões de vendas
Registrar atividades (ligações, emails, reuniões)
O que deseja fazer?
END TALK
BEGIN SYSTEM PROMPT
You are a CRM sales assistant. All entities are managed via the General Bots REST API.
Pipeline stages (in order):
- new: Initial contact, just entered the funnel
- qualified: Budget, authority, need, timeline confirmed (BANT)
- proposal: Quote or proposal sent to the customer
- negotiation: Active discussions on terms
- won: Deal successfully closed
- lost: Deal lost (always ask for lost_reason)
Key rules:
- Always confirm information BEFORE saving
- Use Brazilian Real (BRL) as default currency unless the user specifies otherwise
- When creating a deal, always try to link to an existing contact or create one
- When closing a deal as lost, always ask for the reason
- Encourage the salesperson and suggest next actions based on the new stage
END SYSTEM PROMPT
ADD TOOL "find-deal"

View file

@ -0,0 +1,118 @@
PARAM deal_id AS STRING LIKE "uuid" DESCRIPTION "ID do deal a atualizar" OPTIONAL
PARAM stage AS STRING LIKE "qualified" DESCRIPTION "Novo estágio: new, qualified, proposal, negotiation, won, lost" OPTIONAL
PARAM value AS MONEY LIKE 75000 DESCRIPTION "Novo valor do deal" OPTIONAL
PARAM lost_reason AS STRING LIKE "Preço" DESCRIPTION "Motivo da perda (obrigatório se stage=lost)" OPTIONAL
PARAM notes AS STRING LIKE "Reunião positiva" DESCRIPTION "Observações adicionais" OPTIONAL
DESCRIPTION "Atualizar um deal existente: mudar estágio, valor, adicionar notas. Se mudar para 'won' ou 'lost', o deal é fechado."
' Validate deal exists
IF NOT deal_id OR deal_id = "uuid" THEN
TALK "Qual deal você deseja atualizar? (Pode dizer o nome da empresa ou o título)"
HEAR query AS STRING
' Usar a ferramenta recém-criada (ou lógica similar) para buscar
deals = GET "/api/crm/deals?search=" + query + "&limit=5"
IF UBOUND(deals) = 0 THEN
TALK "Não encontrei nenhum deal relacionado a '" + query + "'."
RETURN
END IF
IF UBOUND(deals) = 1 THEN
deal_id = FIRST(deals).id
ELSE
TALK "Encontrei várias opções. Seguem as 3 primeiras:"
count = 1
FOR EACH d IN deals
IF count <= 3 THEN
TALK count + ". **" + d.title + "** (R$ " + FORMAT(d.value, "#,##0") + ", " + d.stage + ")"
END IF
count = count + 1
NEXT d
TALK "Por favor, especifique melhor informando o título exato ou o e-mail do contato."
RETURN
END IF
END IF
deal = GET "/api/crm/deals/" + deal_id
IF NOT deal THEN
TALK "Deal não encontrado com ID: " + deal_id
RETURN
END IF
TALK "Deal atual: **" + deal.title + "** — " + deal.stage + " — R$ " + FORMAT(deal.value, "#,##0")
' Build update payload
update = #{}
IF stage THEN
' Validate stage
valid_stages = "new,qualified,proposal,negotiation,won,lost"
IF INSTR(valid_stages, stage) = 0 THEN
TALK "Estágio inválido. Use: new, qualified, proposal, negotiation, won, lost"
RETURN
END IF
update.stage = stage
' Set probability
IF stage = "new" THEN
update.probability = 10
ELSE IF stage = "qualified" THEN
update.probability = 30
ELSE IF stage = "proposal" THEN
update.probability = 50
ELSE IF stage = "negotiation" THEN
update.probability = 70
ELSE IF stage = "won" THEN
update.probability = 100
update.won = TRUE
update.actual_close_date = FORMAT(TODAY(), "YYYY-MM-DD")
ELSE IF stage = "lost" THEN
update.probability = 0
update.won = FALSE
update.actual_close_date = FORMAT(TODAY(), "YYYY-MM-DD")
IF NOT lost_reason THEN
TALK "Por que o deal foi perdido?"
HEAR lost_reason AS STRING
END IF
update.lost_reason = lost_reason
END IF
END IF
IF value THEN
update.value = value
END IF
IF notes THEN
update.notes = notes
END IF
' Execute update
PUT "/api/crm/deals/" + deal_id, update
' Log activity
POST "/api/crm/activities", #{
activity_type: "stage_change",
subject: "Deal atualizado para " + stage,
description: notes,
contact_id: deal.contact_id
}
' Response by stage
IF stage = "won" THEN
TALK "🎉 **Parabéns! Deal ganho!**"
TALK "**" + deal.title + "** fechado com sucesso!"
TALK "💰 Valor: R$ " + FORMAT(COALESCE(value, deal.value), "#,##0")
ELSE IF stage = "lost" THEN
TALK "📋 **Deal perdido**"
TALK "**" + deal.title + "** marcado como perdido."
TALK "📝 Motivo: " + lost_reason
TALK "Analise o que aconteceu para melhorar nas próximas!"
ELSE IF stage THEN
TALK "✅ **Deal atualizado!**"
TALK "**" + deal.title + "** → **" + stage + "**"
TALK "📊 Probabilidade: " + update.probability + "%"
ELSE
TALK "✅ Deal atualizado com sucesso."
END IF
RETURN deal_id

View file

@ -0,0 +1,52 @@
PARAM name AS STRING LIKE "Promoção Dia das Mães" DESCRIPTION "Nome descritivo da campanha"
PARAM channel AS STRING LIKE "email" DESCRIPTION "Canal de envio: whatsapp, email, sms, telegram"
PARAM scheduled_date AS DATE LIKE "2026-05-01 09:00:00" DESCRIPTION "Data/Hora de agendamento do envio (opcional)" OPTIONAL
PARAM list_id AS STRING LIKE "uuid_da_lista" DESCRIPTION "ID da Lista de Contatos alvo" OPTIONAL
PARAM template_id AS STRING LIKE "uuid_do_template" DESCRIPTION "ID do Template de Conteúdo" OPTIONAL
PARAM ai_generate_template AS STRING LIKE "Crie um email rápido de 3 parágrafos sobre sapatos com desconto de 15%" DESCRIPTION "Prompt para IA caso queira gerar um template agora" OPTIONAL
DESCRIPTION "Cria uma Campanha de Marketing e agenda seu envio. Pode integrar/vincular a listas e templates existentes."
IF NOT list_id THEN
TALK "Qual lista de contatos você deseja usar para esta campanha?"
' Aqui seria uma busca na db ou listagem interativa
HEAR list_id AS STRING
END IF
// Create template if an AI prompt was given but no template_id
IF ai_generate_template AND NOT template_id THEN
TALK "🤖 Gerando e salvando um template de " + channel + " baseado no seu pedido..."
new_template = POST "/api/marketing/templates", #{
name: name + " Template",
channel: channel,
ai_prompt: ai_generate_template
}
template_id = new_template.id
TALK "Template ID retornado: " + template_id
ELSE IF NOT template_id THEN
TALK "Tem o ID do template guardado? Diga-me por favor."
HEAR template_id AS STRING
END IF
new_campaign = POST "/api/marketing/campaigns", #{
name: name,
channel: channel,
status: "draft",
scheduled_at: scheduled_date,
template_id: template_id,
list_id: list_id
}
TALK "📣 **Campanha Criada!**"
TALK "Nome: " + name
TALK "Canal: " + UCASE(channel)
TALK "Status: Draft"
TALK "ID: " + new_campaign.id
IF scheduled_date THEN
TALK "Agendada para: " + scheduled_date
ELSE
TALK "Pendente de envio. Use 'send-campaign' para dispará-la agora."
END IF
RETURN new_campaign.id

View file

@ -0,0 +1,44 @@
PARAM status AS STRING LIKE "draft" DESCRIPTION "Filtro de status (draft, scheduled, sending, sent, completed)" OPTIONAL
PARAM limit AS INTEGER LIKE 10 DESCRIPTION "Número máximo de campanhas a exibir" OPTIONAL
DESCRIPTION "Lista as campanhas de marketing."
IF NOT limit THEN
limit = 10
END IF
url = "/api/marketing/campaigns?limit=" + limit
IF status THEN
url = url + "&status=" + status
END IF
campaigns = GET url
count = UBOUND(campaigns)
IF count = 0 THEN
TALK "Nenhuma campanha encontrada."
RETURN
END IF
TALK "📊 **Campanhas — " + count + " resultado(s)**"
FOR EACH c IN campaigns
TALK "---"
TALK "**" + c.name + "** (" + c.status + ")"
TALK "📣 Canal: " + UCASE(c.channel)
TALK "🔑 ID: " + c.id
IF c.scheduled_at THEN
TALK "🕒 Agendada: " + c.scheduled_at
END IF
IF c.metrics THEN
TALK "📈 Enviados: " + c.metrics.sent + " | Erros: " + c.metrics.failed
IF c.channel = "email" THEN
TALK " Aberturas: " + c.metrics.opened + " | Clicks: " + c.metrics.clicked
END IF
END IF
NEXT c
RETURN campaigns

View file

@ -0,0 +1,59 @@
PARAM campaign_id AS STRING LIKE "uuid" DESCRIPTION "ID da Campanha" OPTIONAL
PARAM allow_over_budget AS BOOLEAN LIKE FALSE DESCRIPTION "Permitir envio mesmo se ultrapassar o orçamento do canal?" OPTIONAL
DESCRIPTION "Confirma e inicia o disparo (envio) imediato de uma campanha."
IF NOT campaign_id OR campaign_id = "uuid" THEN
TALK "Qual campanha você deseja enviar? (Diga o nome)"
HEAR query AS STRING
camps = GET "/api/marketing/campaigns?search=" + query + "&limit=5"
IF UBOUND(camps) = 0 THEN
TALK "Não encontrei nenhuma campanha com o termo '" + query + "'."
RETURN
END IF
IF UBOUND(camps) = 1 THEN
campaign_id = FIRST(camps).id
ELSE
TALK "Encontrei várias campanhas. Qual delas?"
FOR EACH c IN camps
TALK "- **" + c.name + "** (" + c.status + ")"
NEXT c
RETURN
END IF
END IF
camp = GET "/api/marketing/campaigns/" + campaign_id
IF NOT camp THEN
TALK "Campanha não encontrada: " + campaign_id
RETURN
END IF
IF camp.status = "sent" OR camp.status = "completed" THEN
TALK "A campanha '" + camp.name + "' já foi enviada."
RETURN
END IF
IF NOT camp.list_id THEN
TALK "Esta campanha não tem uma lista de contatos vinculada. Não é possível enviar."
RETURN
END IF
list_info = GET "/api/marketing/lists/" + camp.list_id
TALK "🔍 **Análise Pré-Envio:**"
TALK "• Campanha: " + camp.name
TALK "• Canal: " + UCASE(camp.channel)
TALK "• Segmentação/Lista: " + list_info.name + " (" + list_info.contact_count + " contatos)"
TALK "Deseja realmente iniciar o envio AGORA para " + list_info.contact_count + " pessoas?"
HEAR confirm AS BOOLEAN
IF confirm THEN
POST "/api/marketing/campaigns/" + campaign_id + "/send"
TALK "🚀 **Envio Iniciado!**"
TALK "As automações do " + UCASE(camp.channel) + " foram engatilhadas."
TALK "Você pode acompanhar as métricas em 'list-campaigns' depois de alguns minutos."
ELSE
TALK "Envio cancelado. A campanha continua no status '" + camp.status + "'."
END IF
RETURN camp_id

View file

@ -0,0 +1,42 @@
ADD TOOL "create-campaign"
ADD TOOL "list-campaigns"
ADD TOOL "send-campaign"
ADD TOOL "create-template"
ADD TOOL "list-templates"
ADD TOOL "create-dynamic-list"
SET CONTEXT "marketing" AS "You are a marketing automation assistant for General Bots. You help marketers create campaigns, design templates (email/WhatsApp), build contact lists (static or dynamic), and schedule or send messages. All features interact with the CRM contacts via the General Bots marketing REST API."
CLEAR SUGGESTIONS
ADD SUGGESTION "newcamp" AS "Criar nova campanha"
ADD SUGGESTION "viewcamps" AS "Ver minhas campanhas"
ADD SUGGESTION "lists" AS "Criar lista de contatos"
ADD SUGGESTION "send" AS "Enviar uma campanha"
BEGIN TALK
**Marketing Campanhas e Envio**
Posso ajudar com:
Criar Campanhas (WhatsApp, Email, SMS)
Gerenciar Templates (com IA ou predefinidos)
Construir Listas Dinâmicas (ex: VIPs, Clientes do Bairro X)
Enviar campanhas em massa (Broadcast)
Ver métricas e estatísticas de aberturas
O que quer divulgar hoje?
END TALK
BEGIN SYSTEM PROMPT
You are a Marketing Automation assistant.
Key workflows:
1. Contact List -> Select *who* receives it.
2. Template -> Define *what* is sent. If it's WhatsApp, it usually needs a "meta_template_id" or approval.
3. Campaign -> Groups List + Template + Schedule + Channel. We can "send" or "schedule" it.
Key rules:
- Provide marketing advice: suggest A/B testing or better copy when writing templates.
- Ensure the user confirms the number of recipients before sending a campaign.
- AI prompt in templates allows personalizing messages per recipient (e.g. "Escreva de forma amigável e ofereça 10%").
END SYSTEM PROMPT