Skip to content

Контракт chat S3 ​

Как сервис MCP читает файл чата и записывает результат: адреса, структура ключей, папка результатов, временные доступы, изоляция чатов и ограничения.

Адрес обращения ​

{endpoint}/{bucket}/{key}?token={token}

где endpoint заканчивается на /api/chat-s3, а bucket по умолчанию chat-files.

Пример:

http://localhost:3000/api/chat-s3/chat-files/sessions/sess_123/report.html?token=...

Границы чата ​

Все файлы чата лежат под общим префиксом:

sessions/<идентификатор чата>/

Структура ключей ​

sessions/<идентификатор чата>/<имя файла>

Вид файла, то есть загрузка, рабочий или результат, это пометка в базе данных платформы. Частью пути он не является.

Что передала модельВо что превращается
report.docxsessions/<чат>/report.docx
Идентификатор файлаsessions/<чат>/<идентификатор>
Путь с подкаталогомОтклоняется
Путь с ..Отклоняется
Полный ключ другого чатаОтклоняется

Проверка выхода за границы своего чата это главная граница безопасности на стороне сервиса.

Имя результата должно отличаться от имени источника

В одном чате не может быть двух файлов с одинаковым именем. Поэтому инструмент, который запишет результат под именем исходного файла, заменит исходный файл. Имя результата должно отличаться: либо другим расширением, либо добавкой к имени.

Операции ​

ОперацияЗапрос
Список объектовGET /{bucket}?list-type=2&prefix=...&token=...
ЧтениеGET /{bucket}/{key}?token=...
Проверка наличияHEAD на тот же адрес
ЗаписьPUT /{bucket}/{key}?token=... с телом
УдалениеDELETE /{bucket}/{key}?token=...

Ответ на список объектов приходит в виде XML:

xml
<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <Name>chat-files</Name>
  <Prefix>sessions/sess_123/</Prefix>
  <KeyCount>1</KeyCount>
  <MaxKeys>1000</MaxKeys>
  <IsTruncated>false</IsTruncated>
  <Contents>
    <Key>sessions/sess_123/report.html</Key>
    <Size>1234</Size>
    <LastModified>2026-08-11T09:14:02.113Z</LastModified>
  </Contents>
</ListBucketResult>

Ошибка приходит так:

json
{ "error": "FORBIDDEN", "message": "Token does not match session scope" }

Коды ошибок: UNAUTHORIZED, FORBIDDEN, NOT_FOUND, BAD_REQUEST, INTERNAL_ERROR.

Ни один сервис не пользуется всеми операциями

Проверку наличия, удаление и список объектов не вызывает ни один из переданных сервисов. Все они только читают по известному имени и пишут результат.

Правила работы по сети ​

Одинаковые у всех сервисов и описаны в общем регламенте.

ПравилоЗначение
Ключ доступаДобавляется к каждому запросу отдельно, не встраивается в клиент
ЧтениеОбычный GET
ЗаписьPUT с указанием типа содержимого
Ответ 415 при записиОдна повторная попытка с типом application/octet-stream
Повторные попыткиТолько при кодах 502, 503, 504 и сетевых сбоях, с растущей задержкой
Коды 404, 415, 500Возвращаются без повторов, разбираются вызывающей стороной

Соответствие ответов ошибкам сервиса:

ОтветОшибка сервиса
401 или 403Ключ доступа истёк
404 при чтенииФайл не найден
Остальное при чтенииНе удалось прочитать
Остальное при записиНе удалось записать

Временные доступы ​

СвойствоЗначение
Что этоПодпись HMAC-SHA256 над идентификаторами чата, пользователя и временем истечения
Как передаётсяПараметр запроса token
Время жизни15 минут по умолчанию
Когда выдаётсяОдин раз на сообщение пользователя
Как попадает в сервисТолько внутри init_eva_session

Долгие задачи могут не успеть

Ключ выдаётся один раз на сообщение, а не при каждой привязке сессии. Расшифровка длинной записи или распознавание большого документа могут идти дольше остатка срока. Тогда работа выполнится полностью, а на самой последней операции, записи результата, придёт ошибка истёкшего ключа. Ни один сервис не перечитывает доступы в середине задачи.

Изоляция чатов ​

Проверок пять, в двух местах.

На стороне сервиса:

  1. При привязке сессии префикс обязан совпадать с sessions/<chatId>/.
  2. При каждом обращении ключ проверяется на выход за префикс и на ...

На стороне платформы:

  1. Чат в ключе доступа должен совпадать с чатом в ключе объекта, иначе 403.
  2. При запросе списка префикс должен начинаться с префикса своего чата, иначе 403.
  3. Обращение к другой корзине даёт 404.

Дополнительно при выдаче ключа проверяется, что пользователь действительно имеет доступ к этому чату.

Ограничения ​

ОграничениеЗначение
Предел размера на стороне платформы1 ГиБ
Предел на входе Doc Worker50 МиБ
Предел на входе Transcript500 МиБ
Предел на входе OCRОтсутствует
Таймаут обращения к хранилищу20 секунд у большинства сервисов

Ответ на запись ​

Платформа приводит имя файла к безопасному виду и сообщает получившееся имя в заголовках ответа: ключ объекта и имя файла, оба закодированы по правилам URL.

Сервисы не читают этот ответ

Все сервисы отбрасывают ответ на запись и сообщают модели то имя, которое придумали сами. Для русских имён и имён, изменённых при приведении, получается расхождение: имя, которое модель называет пользователю, не совпадает с именем реально сохранённого файла.

Сервис может обойти это, приведя имя к латинице заранее, но делают так не все.

Полный путь одного вызова ​

модель вызывает чтение документа с именем файла
  общая обёртка
    получение доступа:
      проверка привязанной сессии
      сборка доступов из сохранённых данных
      создание клиента хранилища
    чтение:
      разбор имени в полный ключ и проверка префикса
      проверка срока действия ключа доступа
      GET по адресу с ключом доступа
      разбор кода ответа в понятную ошибку
    работа над файлом
    запись:
      сборка ключа результата
      PUT с типом содержимого, при 415 повтор
  ответ модели: имя файла, ключ, размер, контрольная сумма

Модель при этом передала только имя файла и формат.

Документация платформы EVA