API: Agents¶
Visão Geral¶
Gerenciamento de agentes IA que processam conversas. Cada agente possui um system prompt, mensagens customizáveis e base de conhecimento.
Endpoints¶
GET /api/agents¶
Lista todos os agentes do tenant.
Response (200 OK):
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Suporte TI",
"isActive": true,
"createdAt": "2024-01-15T10:30:00Z",
"todayConversations": 12
}
]
GET /api/agents/{id}¶
Retorna detalhes de um agente.
Response (200 OK):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Suporte TI",
"description": "Agente para suporte técnico interno",
"systemPrompt": "Você é um assistente de TI...",
"isActive": true,
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-20T14:00:00Z",
"totalConversations": 150,
"todayConversations": 12
}
POST /api/agents¶
Cria um novo agente.
Request:
{
"name": "Suporte TI",
"description": "Agente para suporte técnico interno",
"systemPrompt": "Você é um assistente de TI especializado...",
"isActive": true
}
Response (201 Created):
PUT /api/agents/{id}¶
Atualiza um agente.
Request:
{
"name": "Suporte TI v2",
"description": "Agente atualizado",
"systemPrompt": "Você é um assistente de TI...",
"isActive": true
}
Response (200 OK):
DELETE /api/agents/{id}¶
Remove um agente.
Response: 204 No Content
Sub-recursos¶
Mensagens Customizadas¶
GET /api/agents/{agentId}/messages¶
Retorna as mensagens customizadas do agente.
Response (200 OK):
{
"errorMessage": "Desculpe, estou com dificuldades técnicas.",
"welcomeMessage": "Olá! Como posso ajudar?",
"rateLimitMessage": "Você está enviando muitas mensagens.",
"outOfHoursMessage": "Nosso atendimento funciona das 8h às 18h."
}
PUT /api/agents/{agentId}/messages¶
Atualiza as mensagens customizadas.
Request:
{
"errorMessage": "Desculpe, tente novamente.",
"welcomeMessage": "Bem-vindo!",
"rateLimitMessage": null,
"outOfHoursMessage": null
}
Base de Conhecimento¶
GET /api/agents/{agentId}/knowledge¶
Lista blocos de conhecimento do agente.
Response (200 OK):
[
{
"id": "660e8400-e29b-41d4-a716-446655440000",
"title": "Impressoras",
"content": "## Problemas comuns\n\n- Papel atolado...",
"displayOrder": 0,
"isActive": true,
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
]
GET /api/agents/{agentId}/knowledge/{id}¶
Retorna um bloco específico.
POST /api/agents/{agentId}/knowledge¶
Cria um bloco de conhecimento.
Request:
{
"title": "Impressoras",
"content": "## Problemas comuns\n\n- Papel atolado...",
"displayOrder": 0,
"isActive": true
}
PUT /api/agents/{agentId}/knowledge/{id}¶
Atualiza um bloco.
DELETE /api/agents/{agentId}/knowledge/{id}¶
Remove um bloco.
POST /api/agents/{agentId}/knowledge/reorder¶
Reordena os blocos.
Request:
{
"orderedIds": [
"660e8400-e29b-41d4-a716-446655440000",
"770e8400-e29b-41d4-a716-446655440001"
]
}
FAQ (Perguntas Frequentes)¶
FAQs são pares pergunta/resposta que participam da busca semântica junto com a base de conhecimento.
GET /api/agents/{agentId}/faq¶
Lista FAQs do agente.
Response (200 OK):
[
{
"id": "990e8400-e29b-41d4-a716-446655440000",
"agentId": "550e8400-e29b-41d4-a716-446655440000",
"question": "Qual o horário de funcionamento?",
"answer": "Funcionamos de segunda a sexta, das 9h às 18h.",
"displayOrder": 0,
"isActive": true,
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
]
GET /api/agents/{agentId}/faq/{id}¶
Retorna uma FAQ específica.
POST /api/agents/{agentId}/faq¶
Cria uma FAQ. O embedding é gerado automaticamente.
Request:
{
"question": "Qual o horário de funcionamento?",
"answer": "Funcionamos de segunda a sexta, das 9h às 18h.",
"isActive": true
}
Response (201 Created):
{
"id": "990e8400-e29b-41d4-a716-446655440000",
"agentId": "550e8400-e29b-41d4-a716-446655440000",
"question": "Qual o horário de funcionamento?",
"answer": "Funcionamos de segunda a sexta, das 9h às 18h.",
"displayOrder": 0,
"isActive": true,
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
PUT /api/agents/{agentId}/faq/{id}¶
Atualiza uma FAQ. Se pergunta ou resposta mudarem, o embedding é regenerado.
Request:
{
"question": "Qual o horário de atendimento?",
"answer": "Funcionamos de segunda a sexta, das 9h às 18h, e sábados das 9h às 13h.",
"isActive": true
}
DELETE /api/agents/{agentId}/faq/{id}¶
Remove uma FAQ.
Response: 204 No Content
POST /api/agents/{agentId}/faq/reorder¶
Reordena as FAQs.
Request:
{
"orderedIds": [
"990e8400-e29b-41d4-a716-446655440000",
"aa0e8400-e29b-41d4-a716-446655440001"
]
}
Configurações de IA¶
Controle o comportamento da IA: tom, idioma e emojis.
Nota: Campos como
showTyping,delaySeconds,signatureTextesignaturePositionforam movidos para a entidade WhatsAppInstance (configurados na aba "Configurações" da instância).
GET /api/agents/{agentId}/ai-settings¶
Retorna as configurações de IA do agente.
Response (200 OK):
PUT /api/agents/{agentId}/ai-settings¶
Atualiza as configurações de IA.
Request:
Campos:
| Campo | Tipo | Descrição | Default |
|---|---|---|---|
| tone | AgentTone | Tom de comunicação | Professional |
| language | AgentLanguage | Idioma das respostas | PtBr |
| allowEmojis | bool | Permite emojis nas respostas | true |
Enums:
- AgentTone: Formal, Professional, Friendly
- AgentLanguage: PtBr, PtPt, En, Es
Etapas de Atendimento¶
Etapas guiam a IA por um fluxo estruturado de atendimento. Sem etapas, o agente responde livremente.
GET /api/agents/{agentId}/steps¶
Lista etapas do agente ordenadas por posição.
Response (200 OK):
[
{
"id": "aa0e8400-e29b-41d4-a716-446655440000",
"name": "Saudação",
"instructions": "Cumprimente o cliente e pergunte como pode ajudar...",
"optimizedInstructions": null,
"order": 1,
"isActive": true,
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
]
POST /api/agents/{agentId}/steps¶
Cria uma nova etapa. Instruções são otimizadas automaticamente.
Request:
Response (201 Created):
PUT /api/agents/{agentId}/steps/{id}¶
Atualiza uma etapa. Re-otimiza se as instruções mudaram.
Request:
{
"name": "Coleta do Pedido",
"instructions": "Pergunte ao cliente o que deseja pedir. Confirme cada item."
}
DELETE /api/agents/{agentId}/steps/{id}¶
Remove uma etapa. Conversas ativas nesta etapa terão CurrentStepId limpo.
Response: 204 No Content
PUT /api/agents/{agentId}/steps/reorder¶
Reordena as etapas.
Request:
PUT /api/agents/{agentId}/steps/{id}/toggle¶
Ativa/desativa uma etapa.
Validações de Etapas¶
| Campo | Regra |
|---|---|
| Name | Obrigatório, máx 100 caracteres |
| Instructions | Obrigatório, máx 20000 caracteres |
Playground¶
Endpoints para testar o agente diretamente pelo portal administrativo. Todos os endpoints do playground:
- Requerem autorização Admin (RequireAuthorization(AuthConstants.Roles.Admin))
- Estão sob rate limiting LLM (RequireRateLimiting(RateLimitPolicies.Llm))
- Upload de mídia para R2 é feito em paralelo com o processamento via PlaygroundMediaHelper
POST /api/agents/{agentId}/playground/chat¶
Envia mensagens de teste para o agente. Suporta texto e imagens (Claude Vision).
Request:
{
"messages": [
{
"role": "user",
"content": "Olá",
"type": "text"
},
{
"role": "assistant",
"content": "Olá! Como posso ajudar?",
"type": "text"
},
{
"role": "user",
"content": "O que tem nesta imagem?",
"type": "image",
"mediaBase64": "iVBORw0KGgo...",
"mediaMimeType": "image/jpeg"
}
]
}
Campos da mensagem (PlaygroundMessageDto):
| Campo | Tipo | Descrição |
|---|---|---|
| role | string | "user" ou "assistant" |
| content | string | Texto da mensagem (ou legenda da imagem) |
| type | string | "text" (padrão) ou "image" |
| mediaBase64 | string? | Dados da imagem em base64 (apenas type="image") |
| mediaMimeType | string? | MIME type da mídia (ex: "image/jpeg") |
Response (200 OK):
Comportamento:
- Mensagens de texto são enviadas normalmente ao LLM
- Mensagens de imagem são convertidas para ChatMessage.WithImage() (Claude Vision multimodal)
- Limitado às últimas 20 mensagens do histórico
POST /api/agents/{agentId}/playground/transcribe¶
Transcreve áudio em texto usando Whisper (OpenAI).
Request:
| Campo | Tipo | Descrição |
|---|---|---|
| audioBase64 | string | Áudio gravado em base64 |
| mimeType | string | MIME type do áudio (ex: "audio/webm", "audio/ogg") |
Response (200 OK):
Comportamento: - Converte base64 para bytes e envia ao Whisper API - Retorna texto transcrito que o frontend usa como mensagem de texto - Validação: audioBase64 e mimeType são obrigatórios
POST /api/agents/{agentId}/playground/describe-image¶
Realiza OCR/descrição de imagem via Claude Vision. O frontend usa o texto retornado como contexto antes de enviar ao LLM no chat.
Request:
| Campo | Tipo | Descrição |
|---|---|---|
| imageBase64 | string | Dados da imagem em base64 |
| mimeType | string | MIME type da imagem (ex: "image/jpeg", "image/png") |
| caption | string? | Legenda opcional da imagem |
Response (200 OK):
{
"description": "Uma foto de uma pizza margherita em uma caixa de papelão branca...",
"mediaUrl": "https://r2.example.com/tenants/.../playground/image.jpeg"
}
| Campo | Tipo | Descrição |
|---|---|---|
| description | string | Texto descritivo gerado pelo Claude Vision |
| mediaUrl | string? | URL da imagem salva no R2 (pode ser null se upload falhar) |
Comportamento:
- OCR via Claude Vision e upload para R2 executam em paralelo (Task.WhenAll)
- Se o upload falhar, o processamento continua e mediaUrl retorna null
- Se a descrição falhar, retorna erro 400 com mensagem de validação
- Handler: PlaygroundDescribeImageHandler
Validações¶
CreateAgentRequest / UpdateAgentRequest¶
| Campo | Regra |
|---|---|
| Name | Obrigatório, máx 100 caracteres |
| SystemPrompt | Obrigatório |
CreateKnowledgeBlockRequest¶
| Campo | Regra |
|---|---|
| Title | Obrigatório, máx 200 caracteres |
| Content | Obrigatório |
CreateFaqItemRequest / UpdateFaqItemRequest¶
| Campo | Regra |
|---|---|
| Question | Obrigatório, máx 500 caracteres |
| Answer | Obrigatório |
UpdateAgentAiSettingsRequest¶
| Campo | Regra |
|---|---|
| tone | Enum válido (AgentTone) |
| language | Enum válido (AgentLanguage) |
Erros Comuns¶
| Status | Código | Descrição |
|---|---|---|
| 404 | AGENT_NOT_FOUND | Agente não encontrado |
| 409 | AGENT_NAME_EXISTS | Já existe agente com este nome |
| 400 | VALIDATION_ERROR | Campos inválidos |