# История диалога

Используйте историю для восстановления переписки в собственном интерфейсе. Идентификаторы секции, пользователя и диалога должны совпадать с исходными запросами генерации. Web-виджет `1.41` не вызывает этот метод автоматически.

## `POST /shopping/history`

Чтобы восстановить сообщения после перезагрузки страницы или повторного открытия чата, вызовите:

```http
POST https://shopping-assistant-api.gravityfield.ai/shopping/history
Content-Type: application/json
```

Endpoint возвращает только сообщения покупателя и ответы Shopping Assistant. Внутренние system-сообщения, вызовы инструментов и служебные данные в ответ не попадают.

### Запрос истории

```bash
curl --request POST \
  --url 'https://shopping-assistant-api.gravityfield.ai/shopping/history' \
  --header 'Content-Type: application/json' \
  --data '{
    "tenant_id": "demo-section",
    "resourceId": "demo-user",
    "threadId": "thread-8f2b1c",
    "page": 1,
    "limit": 50
  }'
```

| Поле | Обязательное | Назначение |
| :--- | :--- | :--- |
| `tenant_id` | Да | ID секции Gravity Field. Должен совпадать с `runtimeContext.tenant_id`, который использовался при создании диалога. |
| `resourceId` | Да | `uid` пользователя Gravity Field, которому принадлежит диалог. |
| `threadId` | Да | ID диалога, историю которого нужно получить. |
| `page` | Нет | Номер страницы, начиная с `1`. По умолчанию `1`. |
| `limit` | Нет | Количество сообщений на странице: от `1` до `100`. По умолчанию `50`. |

История доступна только при точном совпадении `tenant_id`, `resourceId` и `threadId`. Если диалог не найден или не принадлежит указанной секции или пользователю, API возвращает одинаковый ответ `404`.

### Ответ

```json
{
  "threadId": "thread-8f2b1c",
  "resourceId": "demo-user",
  "items": [
    {
      "id": "shopping:user:4f8c...",
      "role": "user",
      "content": "Помогите выбрать корм для взрослой кошки",
      "createdAt": "2026-07-28T10:00:00.000Z"
    },
    {
      "id": "shopping:assistant:8a21...",
      "role": "assistant",
      "createdAt": "2026-07-28T10:00:01.250Z",
      "threadId": "thread-8f2b1c",
      "resourceId": "demo-user",
      "response": {
        "contents": [
          {
            "type": "message",
            "value": "Кошка стерилизована и есть ли особенности по здоровью?"
          }
        ],
        "ui": {
          "suggests": [
            "Стерилизована, без особенностей",
            "Не стерилизована",
            "Есть особенности по здоровью"
          ]
        }
      },
      "feedback": {
        "reaction": "like"
      },
      "responseLatencyMs": 1250
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "hasMore": false
  }
}
```

Элементы в `items` отсортированы по времени создания от ранних к поздним в пределах страницы:

- для `role: "user"` поле `content` имеет тот же формат, что в запросе `/shopping/generate`: строка для текста или массив блоков `text` и `image`;
- для `role: "assistant"` поле `response` имеет тот же контракт, что ответ `/shopping/generate`; `id` сообщения используйте как `messageId` для `/shopping/feedback`;
- поле `feedback.reaction` в сообщении ассистента содержит текущую оценку пользователя: `like`, `dislike` или `null`;
- дополнительно в сообщении ассистента могут присутствовать `responseLatencyMs` и `events`;
- если `pagination.hasMore` равно `true`, запросите следующую страницу, увеличив `page` на `1`.

Для сообщения с изображением history endpoint возвращает блок `image` с Base64. Для отображения превью соберите data URL из `source.mediaType` и `source.data`, но не передавайте это сообщение повторно в `/shopping/generate`.

```js
const previewUrl =
  `data:${image.source.mediaType};base64,${image.source.data}`;
```

Ответ содержит заголовок `Cache-Control: no-store`. Не сохраняйте историю в общем или публичном кеше на клиентской стороне.

### Ошибки получения истории

| HTTP-статус | Причина | Что делать клиенту |
| :--- | :--- | :--- |
| `400` | Некорректный JSON, отсутствует обязательное поле или `page`/`limit` выходит за допустимый диапазон. | Проверить payload перед повторной отправкой. |
| `403` | IP не разрешён для секции. | Проверить условия доступа с командой Gravity Field. |
| `404` | Диалог не найден или связка `tenant_id`, `resourceId` и `threadId` не совпадает. Код ответа: `SHOPPING_HISTORY_NOT_FOUND`. | Начать новый диалог или проверить сохраненные идентификаторы. |
| `500` | Историю не удалось загрузить. | Показать ошибку и предложить повторить запрос. |
