feat: complete Epic 1 production foundation

This commit is contained in:
2026-08-25 01:24:11 +03:00
parent 767428436d
commit 182bde8ac0
298 changed files with 35719 additions and 5299 deletions
+43 -3
View File
@@ -34,6 +34,13 @@ Authorization: Bearer <agent_api_key>
Для операций с подтверждением человеком нужен отдельный ключ подтверждения. Его тоже выдают в разделе **API ключи**, но в режиме **Подтверждения**. Такой ключ нельзя передавать LLM или MCP-клиенту. Он нужен только вашему внешнему интерфейсу, где пользователь нажимает «Подтвердить» или «Отклонить».
Ключи разных типов не взаимозаменяемы: `mcp_client` не принимается на approval
endpoints, а `approval` не принимается для `initialize`, `tools/list` и
`tools/call`. Revocation проверяется через PostgreSQL source of truth и начинает
действовать без restart, включая уже существующие MCP session. Для approval keys
может быть задан список `allowed_origins`; если HTTP `Origin` присутствует и не
совпадает с разрешённым origin, запрос отклоняется до выполнения side effect.
## Поддерживаемые методы
MCP methods:
@@ -76,6 +83,21 @@ MCP-Session-Id: <session_id>
Если клиент передает `MCP-Protocol-Version`, он должен совпадать с версией, согласованной при инициализации.
## Авторитетное evidence первого вызова
Getting Started засчитывает первый вызов только после полной публичной
последовательности `initialize``notifications/initialized``tools/list`
успешный `tools/call` с тем же активным `mcp_client` key. Одного discovery,
failed call, success через другой key или external verifier credential
недостаточно. Invocation History сохраняет exact key ID вместе с Agent,
immutable Operation Version, tool, UTC timestamp, Request ID и Trace ID.
Admin UI может безопасно сослаться на соответствующую history row и correlation
IDs, но не показывает input arguments, payload, bearer value или upstream body.
Если key отозван/deleted, Agent/Operation archive либо binding/revision больше
не подтверждаются authoritative source of truth, onboarding возвращается в
actionable state; старый raw key не восстанавливается.
## Пример `initialize`
```bash
@@ -131,7 +153,9 @@ call_tool
`search_tools` принимает текст задачи, необязательные идентификаторы разделов и предел результатов. Ответ содержит полные входные схемы найденных инструментов и `catalog_revision`.
`call_tool` принимает имя найденного инструмента, его аргументы и полученную `catalog_revision`. Если за время между поиском и вызовом опубликована новая версия агента, вызов отклоняется с кодом `catalog_revision_changed`: клиент должен повторить поиск.
`call_tool` принимает имя найденного инструмента, его аргументы и полученную `catalog_revision`. Если за время между поиском и вызовом опубликована новая версия агента, вызов отклоняется с кодом `agent_catalog_result_stale`: клиент должен повторить поиск.
`catalog_revision` берётся из immutable Published Agent catalog. Он не является user-controlled label и не заменяет Request/Trace ID; это bounded revision token для защиты пары `search_tools → call_tool` от stale results.
## Пример `tools/call`
@@ -161,6 +185,12 @@ Crank выполнит REST-запрос:
GET https://api.frankfurter.dev/v1/latest?base=USD&symbols=EUR
```
Ошибка `tools/call` сохраняет существующие JSON-RPC/`isError` semantics и
добавляет в structured content поля `error_code`, `stage`, `retryability`,
`outcome_certainty`, `request_id` и `trace_id`. Значение `manual_reconcile` вместе
с `outcome_unknown` означает, что автоматический повтор небезопасен. Raw upstream
body, URL, headers и внутренний текст ошибки не возвращаются.
## Операции с подтверждением человеком
Если в мастере операции включено **Подтверждение человеком**, первый `tools/call` не выполняет REST-запрос сразу. Вместо этого Crank создает ожидающий запрос на подтверждение и возвращает MCP-клиенту структурированный результат:
@@ -185,6 +215,14 @@ GET https://api.frankfurter.dev/v1/latest?base=USD&symbols=EUR
`approval_url` в ответе является путем на MCP-сервере. Если вы публикуете MCP через префикс `/mcp`, внешний URL будет начинаться с `/mcp/v1/...`.
Approval identity считается по полному scope: workspace, Agent, immutable
Operation Version и canonical JSON аргументы. Служебные поля Crank, например
`_crank_confirmation_token`, не входят в fingerprint и не создают дубликаты.
Активный pending request с тем же scope возвращается повторно. В metadata и
`payload_preview` хранится только bounded safe summary: secret-like поля
редактируются, raw approval key/auth headers/control tokens не сохраняются и не
отдаются клиенту.
Внешний интерфейс подтверждения работает отдельным ключом подтверждения:
```bash
@@ -217,8 +255,10 @@ curl https://crank.example.com/mcp/v1/default/sales/approvals/<approval_id>/appr
идемпотентности: универсальный HTTP-клиент не может гарантировать ровно одно внешнее
побочное действие при падении процесса между ответом upstream и записью результата.
Повторный `tools/call` с теми же агентом, операцией, версией и JSON-аргументами
возвращает уже существующую активную заявку вместо создания дубликата.
Повторный `tools/call` с теми же агентом, операцией, версией и canonical
JSON-аргументами возвращает уже существующую активную заявку вместо создания
дубликата. Повторный approve/deny terminal заявки возвращает текущий status и не
запускает второй side effect.
Отклонение: