# Respostas e streaming

> A interface de conversa principal do LMSP, com requisições e itens de saída no estilo Responses, geração síncrona e em streaming, tipos de eventos enviados pelo servidor, IDs de evento, reconexão e ferramentas.

Source: https://madeforagent.com/pt-br/lmsp/1.0/responses/
Language: pt-BR
Specification: LMSP 1.0 (draft)
Updated: 2026-11-08

## 6.1 Requisição {#request}

```http
POST /lmsp/v1/responses
Authorization: Bearer <token>
Content-Type: application/json
Idempotency-Key: 01J8M5T7Z2K4N6Q8S0V3X5B9DG
LMSP-Version: 1.0
```

```json
{
  "model": "qwen3:14b-q4_k_m",
  "input": [
    {
      "type": "message",
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "Describe a local model service in one sentence."
        }
      ]
    }
  ],
  "stream": false,
  "max_output_tokens": 512,
  "temperature": 0.7,
  "response_format": {
    "type": "text"
  },
  "store": true
}
```

O protocolo principal usa uma estrutura `input` e `output` no estilo Responses, em vez de uma lista simples de strings de mensagem, para que um único formato de requisição possa carregar:

- mensagens de vários turnos;
- texto, imagens, áudio e arquivos;
- chamadas de ferramentas e resultados de ferramentas;
- saída estruturada;
- resumos de raciocínio;
- saída multimodal.

O LMSP 1.0 define apenas conteúdo de texto. Os tipos de conteúdo de imagem, áudio e arquivo ficam reservados para versões futuras.

| Campo | Obrigatório | Significado |
| --- | --- | --- |
| `model` | Sim | ID do modelo a usar. |
| `input` | Sim | Array de itens de entrada. Um item `message` tem um `role` (`system`, `user` ou `assistant`) e um array `content` de partes, como `input_text`. O uso de ferramentas acrescenta itens `function_call` e `function_call_output` ([seção 6.5](https://madeforagent.com/pt-br/lmsp/1.0/responses.md#tools)). |
| `stream` | Não | `true` para receber eventos enviados pelo servidor. O padrão é `false`. |
| `max_output_tokens` | Não | Limite superior do número de tokens gerados. |
| `temperature` | Não | Temperatura de amostragem. |
| `response_format` | Não | `{"type": "text"}` (o padrão) ou `{"type": "json_schema", "json_schema": {"name": "...", "schema": {...}}}` para saída estruturada. Exige a capacidade `structured_output`. |
| `tools`, `tool_choice` | Não | Ferramentas de função que o modelo pode chamar ([seção 6.5](https://madeforagent.com/pt-br/lmsp/1.0/responses.md#tools)). Exige a capacidade `tools`. |
| `store` | Não | Pede ao serviço que guarde a resposta, para que ela possa ser recuperada depois e usada como `previous_response_id`. O padrão é `false`. Ignorado por serviços sem a capacidade `conversations`. |
| `previous_response_id` | Não | Continua a partir de uma resposta armazenada. Exige a capacidade `conversations`. |
| `extensions` | Não | Extensões privadas ([seção 9.1](https://madeforagent.com/pt-br/lmsp/1.0/common-rules.md#versioning)). |

Uma requisição que exige uma capacidade que o modelo não tem é rejeitada com `400` e `unsupported_capability`. Uma requisição que não cabe na janela de contexto é rejeitada com `400` e `context_length_exceeded`.

Um serviço que consegue armazenar conversas **PODE** também suportar `previous_response_id`. Caso contrário, toda requisição **DEVE** carregar o contexto completo. Um serviço **NÃO DEVE** depender da conexão HTTP para manter o estado da conversa.

## 6.2 Resposta síncrona {#sync}

Quando `stream` é `false`, o serviço retorna `200 OK` com um objeto de resposta depois que a geração termina.

```json
{
  "id": "resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF",
  "object": "response",
  "created_at": 1794200000,
  "status": "completed",
  "model": "qwen3:14b-q4_k_m",
  "output": [
    {
      "id": "msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE",
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "A local model service is a resident interface layer that discovers, manages and calls models on the user's own device."
        }
      ]
    }
  ],
  "usage": {
    "input_tokens": 28,
    "output_tokens": 31,
    "total_tokens": 59
  },
  "error": null,
  "incomplete_details": null
}
```

| Campo | Significado |
| --- | --- |
| `id` | Identificador da resposta, como `resp_...`. |
| `object` | Sempre `"response"`. |
| `created_at` | Momento da criação, em segundos desde a época Unix. |
| `status` | `in_progress`, `completed`, `incomplete`, `failed` ou `cancelled`. Uma resposta síncrona é retornada em um status final. |
| `model` | ID do modelo que produziu a resposta. |
| `output` | Array de itens de saída. |
| `usage` | Contagens de tokens: `input_tokens`, `output_tokens` e `total_tokens`. |
| `error` | `null` ou um objeto de problema ([seção 9.3](https://madeforagent.com/pt-br/lmsp/1.0/common-rules.md#errors)) quando `status` é `failed`. |
| `incomplete_details` | `null` ou um objeto com um `reason`, como `max_output_tokens`, quando `status` é `incomplete`. |

Tipos de itens de saída:

| Tipo de item | Formato |
| --- | --- |
| `message` | `id`, `role` (`assistant`) e `content`, um array de partes `output_text` que têm, cada uma, um `text`. |
| `function_call` | `id`, `call_id`, `name` e `arguments`, uma string codificada em JSON. |
| `reasoning` | `id` e `summary`, um array de partes `summary_text` que têm, cada uma, um `text`. |

Se a geração falhar, uma requisição síncrona é respondida com um status de erro e um documento de problema ([seção 9.3](https://madeforagent.com/pt-br/lmsp/1.0/common-rules.md#errors)), e não com um objeto de resposta. O status `failed` aparece em streams, tarefas e respostas armazenadas.

`GET /lmsp/v1/responses/{response_id}` retorna uma resposta que foi armazenada com `store: true`. É opcional e exige a capacidade `conversations`. Um ID desconhecido resulta em `404` com `response_not_found`.

## 6.3 Streaming {#streaming}

Para fazer streaming, defina `stream` na requisição:

```json
{
  "stream": true
}
```

O serviço responde `200 OK` com `Content-Type: text/event-stream` e envia eventos semânticos. Cada evento tem um `id`, um nome `event` e um objeto JSON `data`:

```text
id: 1
event: response.created
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"in_progress"}

id: 2
event: response.output_item.added
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[]}}

id: 3
event: response.output_text.delta
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"A local model "}

id: 4
event: response.output_text.delta
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"service is a resident interface layer."}

id: 5
event: response.output_item.done
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[{"type":"output_text","text":"A local model service is a resident interface layer."}]}}

id: 6
event: response.completed
data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"completed","usage":{"input_tokens":28,"output_tokens":12,"total_tokens":40}}
```

Pelo menos estes eventos são definidos:

| Evento | Significado | Campos de dados |
| --- | --- | --- |
| `response.created` | A resposta foi criada. | `response_id`, `status` (`in_progress`) |
| `response.output_item.added` | Um novo item de saída começou. | `response_id`, `output_index`, `item` |
| `response.output_text.delta` | Texto foi acrescentado a um item de mensagem. | `response_id`, `item_id`, `delta` |
| `response.output_item.done` | Um item de saída está completo. | `response_id`, `output_index`, `item` |
| `response.completed` | A resposta terminou. Evento final. | `response_id`, `status`, `usage` |
| `response.incomplete` | A geração parou antes do fim, por exemplo no limite de tokens. Evento final. | `response_id`, `status`, `incomplete_details`, `usage` |
| `response.failed` | A geração falhou. Evento final. | `response_id`, `status`, `error` |
| `response.cancelled` | A resposta foi cancelada. Evento final. | `response_id`, `status` |
| `error` | Um problema que não está ligado a uma única resposta, após o qual o fluxo não pode continuar. | `error`, um objeto de problema |

Um serviço fecha o fluxo após um evento final ou um evento `error`.

Os serviços **PODEM** enviar eventos adicionais, por exemplo para argumentos de chamadas de ferramentas, imagens, áudio e deltas de JSON estruturado. Os clientes **DEVEM** ignorar os tipos de evento que não conhecem.

Se o cliente fechar a conexão de uma requisição em streaming, o serviço **DEVERIA** parar de gerar.

## 6.4 IDs de evento e reconexão {#reconnection}

O `id` de um evento **DEVE** ser um número de sequência inteiro, estritamente crescente dentro da resposta, começando em 1.

Após uma conexão interrompida, um cliente retoma enviando o último ID que recebeu. Ele faz isso com um cabeçalho:

```http
Last-Event-ID: 2
```

ou com um parâmetro de consulta:

```http
GET /lmsp/v1/tasks/{task_id}/events?after=2
```

Ambos vão para o endpoint de eventos de uma tarefa ([seção 7.4](https://madeforagent.com/pt-br/lmsp/1.0/tasks.md#events)). O serviço reenvia apenas os eventos cujo número de sequência é maior que 2. Se ambos estiverem presentes, `after` prevalece.

Se os eventos solicitados forem mais antigos que o período de retenção, o serviço responde `410 Gone` com o erro `event_history_expired`. O cliente então busca o resultado final, com `GET /lmsp/v1/tasks/{task_id}`.

Uma resposta enviada em streaming diretamente por `POST /lmsp/v1/responses` pertence àquela conexão HTTP e não pode ser retomada. Um cliente que precisa de saída retomável **DEVERIA** criar uma [tarefa](https://madeforagent.com/pt-br/lmsp/1.0/tasks.md) e acompanhar os seus eventos.

## 6.5 Chamadas de ferramentas {#tools}

O LMSP 1.0 define ferramentas de função que o cliente executa. O serviço não executa ferramentas por conta própria. O escopo `tools:execute` é reservado para extensões que o fazem ([seção 10.3](https://madeforagent.com/pt-br/lmsp/1.0/security.md#scopes)).

Primeiro, o cliente lista as ferramentas. Cada entrada tem `type` definido como `function`, um `name`, uma `description` e `parameters`, um objeto JSON Schema. `tool_choice` é `auto` (o padrão), `none`, `required` ou `{"type": "function", "name": "get_weather"}`.

```json
{
  "model": "qwen3:14b-q4_k_m",
  "input": [
    {
      "type": "message",
      "role": "user",
      "content": [
        {
          "type": "input_text",
          "text": "What is the weather in Hangzhou?"
        }
      ]
    }
  ],
  "tools": [
    {
      "type": "function",
      "name": "get_weather",
      "description": "Get the current weather for a city.",
      "parameters": {
        "type": "object",
        "properties": {
          "city": { "type": "string" }
        },
        "required": ["city"]
      }
    }
  ],
  "tool_choice": "auto"
}
```

Quando o modelo decide chamar uma ferramenta, a resposta contém um item `function_call`. Seus `arguments` são uma string codificada em JSON. Em um stream, o item chega completo em `response.output_item.done`.

```json
{
  "id": "resp_01J8M7B3N6Q9T2V5X8Z1C4D7FH",
  "object": "response",
  "created_at": 1794200050,
  "status": "completed",
  "model": "qwen3:14b-q4_k_m",
  "output": [
    {
      "id": "fc_01J8M7B3N8R1S4W7Y0A3E6G9JK",
      "type": "function_call",
      "call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM",
      "name": "get_weather",
      "arguments": "{\"city\":\"Hangzhou\"}"
    }
  ],
  "usage": {
    "input_tokens": 74,
    "output_tokens": 18,
    "total_tokens": 92
  },
  "error": null,
  "incomplete_details": null
}
```

O cliente executa a ferramenta e então envia uma nova requisição que carrega o contexto completo: os itens de entrada anteriores, o item `function_call` como foi recebido e um item `function_call_output` com o mesmo `call_id`. Seu `output` é uma string, geralmente codificada em JSON.

```json
{
  "type": "function_call_output",
  "call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM",
  "output": "{\"temperature_c\":17,\"condition\":\"light rain\"}"
}
```
