Skip to content

Chat completions ​

POST /v1/chat/completions ​

Envia uma mensagem da pessoa para o agente e devolve a resposta. O formato lembra o de chat completions de outras APIs, com diferenças importantes: o histórico fica na Cavori, e cada chamada envia só a mensagem nova.

Exige o cabeçalho Idempotency-Key, de 8 a 200 caracteres.

CampoTipoObrigatórioDescrição
modelstringsimAgente da conversa, agent:<id>. Diferente do agente com que a conversa foi aberta, responde 409 conflict.
conversation_idstringsimId devolvido por POST /v1/conversations.
messagesarraysimExatamente uma mensagem, { "role": "user", "content": "..." }, com 1 a 32.000 caracteres.
streambooleannãotrue para receber a resposta aos poucos. Padrão: false.

O que não é aceito ​

  • mais de uma mensagem, ou papel diferente de user;
  • prompt de sistema, histórico enviado de fora, ferramentas e anexos;
  • qualquer campo que não esteja na tabela (temperature, max_tokens etc.).

O contexto da conversa é o histórico guardado na Cavori. Esses casos respondem 400 invalid_request.

Resposta em JSON ​

bash
curl https://api.cavori.com.br/v1/chat/completions \
  -H "Authorization: Bearer $CAVORI_API_KEY" \
  -H "Idempotency-Key: usuario-123-turno-1" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "agent:cm9x0example0001",
    "conversation_id": "cm9x0conversa0001",
    "messages": [{ "role": "user", "content": "Olá, vocês abrem no sábado?" }]
  }'

Exemplo de resposta:

json
{
  "id": "cm9x0execucao0001",
  "object": "chat.completion",
  "conversation_id": "cm9x0conversa0001",
  "message_id": "cm9x0mensagem0002",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Abrimos sim, das 9h às 13h." },
      "finish_reason": "stop"
    }
  ]
}
CampoDescrição
idId da execução. Use em GET /v1/requests/:id.
message_idId da mensagem do agente, o mesmo de GET /v1/conversations/:id/messages.
choices[0].message.contentTexto da resposta.
choices[0].finish_reasonstop, ou content_filter quando uma proteção do agente interrompeu a resposta.

Resposta em streaming ​

Com "stream": true, a resposta é text/event-stream (SSE, UTF-8). Cada evento é uma linha data: com um JSON, seguida de uma linha em branco. O texto vem em choices[0].delta.content, sempre com finish_reason: null:

text
data: {"id":"cm9x0execucao0001","conversation_id":"cm9x0conversa0001","message_id":"cm9x0mensagem0002","choices":[{"index":0,"delta":{"content":"Abrimos "},"finish_reason":null}]}

data: {"id":"cm9x0execucao0001","conversation_id":"cm9x0conversa0001","message_id":"cm9x0mensagem0002","choices":[{"index":0,"delta":{"content":"sim, das 9h às 13h."},"finish_reason":null}]}

data: {"id":"cm9x0execucao0001","conversation_id":"cm9x0conversa0001","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]
  • Concatene os delta.content na ordem para montar a resposta.
  • O último evento com JSON traz delta vazio e o finish_reason final. Depois dele vem data: [DONE], e a conexão fecha.
  • Se a geração falhar depois de o texto começar a sair, o último evento traz finish_reason: "error", e o texto que já saiu fica gravado na conversa. Se falhar antes de qualquer texto, a resposta é um erro comum em JSON (veja Erros e limites).
  • Se você fechar a conexão antes do fim, a geração é cancelada.
  • Quando uma pessoa já assumiu a conversa, a resposta é o 202 em JSON descrito abaixo, e não um stream.

Exemplo com curl (-N desliga o buffer):

bash
curl -N https://api.cavori.com.br/v1/chat/completions \
  -H "Authorization: Bearer $CAVORI_API_KEY" \
  -H "Idempotency-Key: usuario-123-turno-2" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "agent:cm9x0example0001",
    "conversation_id": "cm9x0conversa0001",
    "messages": [{ "role": "user", "content": "E no domingo?" }],
    "stream": true
  }'

Quando uma pessoa assumiu ​

Se a conversa está em HUMAN ou HUMAN_REQUESTED, a mensagem é gravada, o agente não responde e a resposta é 202:

json
{ "id": "cm9x0execucao0002", "conversation_id": "cm9x0conversa0001", "status": "WAITING_HUMAN" }

A resposta humana chega por webhook ou por GET /v1/conversations/:id/messages.

Idempotência e conflitos ​

  • Mesma Idempotency-Key com o mesmo corpo: devolve a execução já feita, sem gerar outra resposta, sempre em JSON, mesmo que a primeira chamada tenha sido em streaming. Se ela ainda estava em andamento, ou terminou em FAILED ou PARTIAL, a resposta é o estado dela, com status 200 e no formato de Execuções. Se uma pessoa tinha assumido (WAITING_HUMAN), a resposta é 202, também no formato de Execuções.
  • Mesma Idempotency-Key com outro corpo: 409 conflict.
  • Já existe uma resposta sendo gerada para essa conversa: 409 conflict. Aguarde terminar antes de enviar a próxima mensagem.
  • Mais execuções simultâneas do que o permitido: 429 rate_limit. Os limites estão em Erros e limites.