community: remove premium protocols and streaming surface

This commit is contained in:
a.tolmachev
2026-05-07 20:44:58 +00:00
parent 202c886793
commit 29f971c22d
78 changed files with 21 additions and 8838 deletions
-4
View File
@@ -74,8 +74,6 @@ just staging-note-block <domain> <deploy-sha> "codex + operator"
- `/usage`
- `/workspace-setup`
- `/settings`
- `/stream-sessions`
- `/async-jobs`
- `/wizard/`
Для каждой страницы зафиксировать:
@@ -142,8 +140,6 @@ just staging-note-block <domain> <deploy-sha> "codex + operator"
- `window` tool;
- `session` tool;
- `async_job` tool;
- `/stream-sessions`;
- `/async-jobs`.
Если WebSocket/SOAP upstream на стенде отсутствуют:
+3 -6
View File
@@ -53,7 +53,6 @@
- `crates/crank-core`
- `crates/crank-schema`
- `crates/crank-mapping`
- `crates/crank-proto`
- `crates/crank-registry`
- `crates/crank-runtime`
- `crates/crank-adapter-rest`
@@ -129,11 +128,9 @@
Основные блокеры:
1. Root workspace все еще содержит premium adapter crates.
2. `admin-api` и `mcp-server` test/dev wiring все еще используют premium crates.
3. UI build все еще включает premium wizard modules и premium step templates.
4. `workspace-setup`, `settings`, `catalog`, `usage`, `agents` и `i18n` все еще содержат premium protocol surface.
5. `examples/` и часть docs все еще содержат premium protocol materials.
1. `admin-api` и `mcp-server` test/dev wiring еще не полностью очищены от legacy streaming/premium references.
2. `workspace-setup`, `settings`, `catalog`, `usage`, `agents` и `i18n` все еще содержат отдельные premium protocol strings и copy.
3. часть docs все еще требует final Community pass после физического удаления premium crates и standalone streaming pages.
## 6. Порядок очистки перед public import
-5
View File
@@ -152,8 +152,6 @@ curl -I https://<domain>/html/wizard/
- `/usage`
- `/workspace-setup`
- `/settings`
- `/stream-sessions`
- `/async-jobs`
- `/wizard/`
Для каждой страницы:
@@ -209,9 +207,6 @@ Smoke считается успешным, если:
На deployed стенде проверить:
- `window` tool выполняется и не возвращает бесконечный поток;
- `session` tool создает записи в `/stream-sessions`;
- `async_job` tool создает записи в `/async-jobs`;
- UI pages `/stream-sessions` и `/async-jobs` не пустые после вызовов.
Если есть real upstream:
-8
View File
@@ -26,10 +26,7 @@ flowchart LR
CORE[crank-core]
SCHEMA[crank-schema]
MAP[crank-mapping]
PROTO[crank-proto]
REST[adapter-rest]
GQL[adapter-graphql]
GRPC[adapter-grpc]
DB[(PostgreSQL)]
STORE[(Artifact Storage)]
OBS[(Usage and Logs)]
@@ -39,7 +36,6 @@ flowchart LR
MCP --> RUN
ADMIN --> REG
ADMIN --> RUN
ADMIN --> PROTO
REG --> DB
REG --> CORE
REG --> SCHEMA
@@ -48,10 +44,6 @@ flowchart LR
RUN --> SCHEMA
RUN --> MAP
RUN --> REST
RUN --> GQL
RUN --> GRPC
GRPC --> PROTO
PROTO --> STORE
ADMIN --> STORE
REG --> OBS
ADMIN --> OBS
+6 -29
View File
@@ -29,13 +29,8 @@
crank-registry/
crank-runtime/
crank-adapter-rest/
crank-adapter-graphql/
crank-adapter-grpc/
crank-adapter-websocket/
crank-adapter-soap/
crank-mapping/
crank-schema/
crank-proto/
```
Поверх существующих crates должны появиться новые логические поддомены:
@@ -87,15 +82,7 @@
- input/output mapping;
- draft inference из samples.
### 4.4. `crank-proto`
Назначение:
- работа с `.proto` и descriptor set;
- извлечение services, methods и message schemas;
- преобразование protobuf metadata во внутренние типы.
### 4.5. `crank-registry`
### 4.4. `crank-registry`
Назначение:
@@ -109,7 +96,7 @@
- logs и usage aggregates;
- metadata по sample artifacts и descriptors.
### 4.6. `crank-runtime`
### 4.5. `crank-runtime`
Назначение:
@@ -124,23 +111,13 @@
- `crank-runtime` должен собираться как `REST-only` base даже без premium adapter crates;
- premium protocol adapters подключаются через feature seams, а не как безусловная зависимость Community runtime.
### 4.7. Protocol adapters
### 4.6. Protocol adapters
- `crank-adapter-rest`
- `crank-adapter-graphql`
- `crank-adapter-grpc`
- `crank-adapter-websocket`
- `crank-adapter-soap`
Каждый adapter знает только свой протокол.
Community runtime в этом репозитории поддерживает только `REST`.
Для open-core split это означает:
- `crank-adapter-rest` остается обязательной частью Community runtime;
- `crank-adapter-graphql`, `crank-adapter-grpc`, `crank-adapter-websocket`, `crank-adapter-soap`
должны подключаться как отделяемые protocol modules.
### 4.8. `apps/admin-api`
### 4.7. `apps/admin-api`
Должен содержать сервисные группы:
@@ -156,7 +133,7 @@
- `usage`
- `streaming`
### 4.9. `apps/mcp-server`
### 4.8. `apps/mcp-server`
Назначение:
-109
View File
@@ -1,109 +0,0 @@
# GraphQL
## 1. Роль протокола в проекте
GraphQL поддерживается как отдельный тип интеграции, но на слое MCP намеренно ограничивается. Цель платформы не в том, чтобы дать LLM универсальный доступ ко всему GraphQL endpoint, а в том, чтобы превратить конкретный GraphQL-запрос в узкий и предсказуемый MCP tool.
## 2. Что поддерживается в целевом продукте
- `query`
- `mutation`
- один GraphQL endpoint на operation
- фиксированный `query_template`
- фиксированный `selection set`
- загрузка примера выходного `JSON`
- схема переменных
- variables mapping
- response extraction из `data`
- разбор `errors`
- auth и headers
- автогенерация чернового mapping
- ручная донастройка через `JSONPath`
- тестовый вызов перед публикацией
## 3. Что отложено
- `subscription`
- универсальный GraphQL explorer для LLM
- передача произвольного GraphQL-документа от LLM
- визуальный конструктор сложных selection set
- обязательная зависимость от introspection
- автоматическое построение любого запроса по полной GraphQL schema
`subscription` допускается только как future scope после появления отдельного websocket/subscription adapter и controlled streaming lifecycle.
## 4. Ключевое архитектурное ограничение
Платформа не должна публиковать в MCP общий GraphQL tool, который умеет получать любые поля и принимать любые параметры в зависимости от намерения LLM.
Правильная модель только одна:
- один tool;
- один конкретный `query` или `mutation`;
- один заранее зафиксированный `selection set`;
- фиксированный набор входных параметров;
- один предсказуемый формат ответа.
Иными словами, на MCP-слое GraphQL сознательно сужается до модели, близкой к RPC или REST operation. Это делается потому, что LLM должен работать с понятным контрактом, а не конструировать произвольный GraphQL-запрос на лету.
## 5. Внутренняя модель GraphQL operation
GraphQL operation должна включать:
- `endpoint`
- `operation_type`
- `operation_name`
- `query_template`
- `variables_schema`
- `input_mapping`
- `response_path`
- `error_policy`
- `headers`
- `auth_profile`
## 6. Как оператор настраивает GraphQL operation
1. Указывает GraphQL endpoint.
2. Выбирает `query` или `mutation`.
3. Задает имя операции.
4. Вставляет готовый шаблон запроса.
5. Описывает переменные, которые разрешено передавать в эту операцию.
6. При необходимости загружает пример JSON-ответа.
7. Система строит черновую схему ответа и стартовый mapping.
8. Настраивает маппинг `MCP input -> GraphQL variables`.
9. Указывает `response_path`, по которому извлекается полезный результат из `data`.
10. При необходимости уточняет mapping через `JSONPath`.
11. Выполняет тест.
12. Публикует operation как MCP tool.
## 7. Поведение runtime
При выполнении GraphQL operation runtime должен:
1. Валидировать вход по фиксированной схеме переменных.
2. Применить input mapping.
3. Собрать GraphQL payload вида `query + variables`.
4. Выполнить HTTP request.
5. Отдельно разобрать `data` и `errors`.
6. Применить output mapping или `response_path`.
7. Вернуть нормализованный результат.
## 8. Критические нюансы
- HTTP `200 OK` не означает успешное выполнение, если в теле присутствует `errors`.
- структура ответа зависит от `selection set`, значит она должна быть фиксирована заранее;
- GraphQL endpoint обычно один, поэтому операция определяется не URL, а телом запроса;
- variables должны быть строго ограничены, иначе один tool станет слишком широким и плохо управляемым;
- `subscription` не входит в текущий scope, потому что требует отдельной lifecycle-модели, близкой к `session` mode, и отдельного transport adapter.
- `JSONPath` используется для точечного извлечения вложенных данных из `data` и для управления структурой итогового ответа.
## 9. Почему GraphQL не считается "почти REST"
GraphQL похож на REST только тем, что часто передается по HTTP. Но с точки зрения платформы это другой тип контракта:
- смысл операции задается не endpoint, а запросом;
- ответ зависит от `selection set`;
- ошибки живут в теле ответа, а не только в HTTP status;
- одна и та же точка входа может обслуживать много операций.
Поэтому GraphQL в системе должен иметь отдельный адаптер и отдельную конфигурационную модель.
-110
View File
@@ -1,110 +0,0 @@
# gRPC
## 1. Роль протокола в проекте
gRPC поддерживается как третий основной протокол платформы в управляемой форме. Цель состоит не в том, чтобы покрыть все возможности gRPC, а в том, чтобы представить unary и bounded server-streaming методы как MCP tools с предсказуемым жизненным циклом.
## 2. Что поддерживается в целевом продукте
- unary RPC
- bounded server-streaming через execution modes `window`, `session`, `async_job`
- загрузка `.proto`
- загрузка descriptor set
- загрузка примеров JSON для MCP input/output при необходимости
- извлечение `services`, `methods`, request/response messages
- отображение входных и выходных параметров в UI
- mapping `MCP input -> protobuf request`
- mapping `protobuf response -> MCP output`
- автогенерация чернового mapping
- ручная донастройка через `JSONPath`
- вызов метода по descriptor metadata
- auth/transport settings на уровне соединения
- тестовый вызов перед публикацией
## 3. Что отложено
- `client streaming`
- `bidirectional streaming`
- обязательная поддержка server reflection
- генерация нового Rust-кода под каждый загруженный `.proto`
- сложные сценарии с долгоживущими сессиями вызовов
## 4. Ключевое архитектурное ограничение
В проекте поддерживаются unary-методы и bounded server-streaming, потому что MCP tool в этой архитектуре должен оставаться управляемым.
Это означает:
- один request message;
- один bounded response или управляемая session/job-семантика;
- явно ограниченный lifecycle stream-сессии.
Streaming gRPC не публикуется как бесконечный raw stream. Он допускается только там, где runtime умеет bounded-ить, агрегировать и завершать результат.
## 5. Внутренняя модель gRPC operation
gRPC operation должна включать:
- `server_addr`
- `package`
- `service`
- `method`
- `descriptor_ref`
- `descriptor_set_b64`
- `input_schema`
- `output_schema`
- `input_mapping`
- `output_mapping`
- `execution_config`
- `tool_description`
## 6. Как оператор настраивает gRPC operation
1. Загружает `.proto` или descriptor set.
2. Система извлекает список services и methods.
3. Оператор выбирает конкретный unary- или server-streaming метод.
4. UI показывает структуру request message и response message.
5. При необходимости загружает примеры JSON для MCP input/output.
6. Система строит черновую схему, стартовый mapping и runtime-ready snapshot descriptor set для выбранного метода.
7. Оператор задает или уточняет входные MCP-параметры.
8. Настраивает маппинг во входные protobuf fields.
9. Настраивает маппинг из response fields в MCP output.
10. При необходимости уточняет mapping через `JSONPath`.
11. Выполняет тест.
12. Публикует operation как MCP tool.
## 7. Поведение runtime
При выполнении gRPC operation runtime должен:
1. Валидировать MCP input по нормализованной схеме.
2. Применить input mapping.
3. Построить protobuf request message из JSON.
4. Для unary выполнить unary RPC вызов.
5. Для server-streaming собрать bounded окно или session step.
6. Преобразовать protobuf response или stream items в нормализованный JSON.
7. Применить output mapping.
8. Вернуть итоговый результат.
## 8. Критические нюансы
- `.proto` и descriptor handling должны быть отделены от runtime-вызова;
- protobuf discovery не должен жить внутри gRPC adapter;
- runtime использует сохраненный `descriptor_set_b64`, а не исходный `.proto`;
- `oneof`, `enum`, `repeated`, `map` и well-known types требуют отдельной нормализации;
- `map` на слое нормализованной schema модели представляется как `array` объектов вида `{ key, value }`;
- `oneof` на слое нормализованной schema модели представляется как `oneof` с вариантами-объектами, каждый из которых содержит одно допустимое поле;
- схема сообщения должна быть представлена в UI как обычная форма полей, а не как сырой protobuf descriptor;
- пользователь не должен видеть внутреннюю сложность protobuf-контракта больше, чем это нужно для настройки operation.
- `JSONPath` используется как единый способ точечной адресации вложенных полей при настройке mapping поверх нормализованной JSON-модели.
## 9. Почему gRPC ограничивается controlled streaming
Причина не только в сложности реализации. Главное ограничение архитектурное:
- MCP tool моделируется как завершенный вызов;
- LLM работает с запросом и конечным ответом;
- UI платформы построен вокруг формы входа и формы выхода;
- streaming требует отдельной session-модели, buffering, cancellation и состояния.
Поэтому поддержка gRPC в Crank ограничивается unary и bounded server-streaming. Client-streaming и bidi остаются вне scope до появления полноценной interactive session model.
-162
View File
@@ -1,162 +0,0 @@
# SOAP
## 1. Роль протокола в проекте
SOAP поддерживается как enterprise-oriented upstream protocol для интеграций с системами, где REST уже не является стандартом де-факто.
Типичные домены:
- ERP;
- banking;
- insurance;
- government and B2B gateways;
- legacy enterprise systems;
- ESB-oriented internal APIs.
## 2. Что поддерживается в целевом продукте
- SOAP 1.1 и SOAP 1.2;
- WSDL upload/import;
- выбор `service`, `port` и `operation`;
- document/literal first;
- XML schema extraction из WSDL/XSD;
- input/output schema generation;
- mapping `MCP JSON -> SOAP body`;
- mapping `SOAP response -> normalized JSON`;
- SOAP headers config;
- basic auth, bearer auth и auth profiles;
- test run;
- publish as MCP tool.
## 3. Что не входит в текущий продуктовый scope
- полный стек WS-* расширений;
- MTOM attachments;
- arbitrary XML transformation engine;
- full schema authoring inside UI;
- server-side SOAP hosting.
## 4. Ключевое архитектурное ограничение
SOAP не является просто HTTP POST с XML body.
Для платформы SOAP operation определяется:
- WSDL model;
- service/port/operation binding;
- envelope structure;
- namespaces;
- optional SOAPAction;
- fault model;
- XML schema contract.
Поэтому SOAP должен иметь отдельный adapter и отдельную конфигурационную модель.
## 5. Типовые use cases
- enterprise CRM/ERP operations;
- payment and settlement integrations;
- policy and claims systems;
- regulated B2B data exchange;
- legacy internal service contracts.
## 6. Внутренняя модель SOAP operation
SOAP operation должна включать:
- `wsdl_ref`
- `service_name`
- `port_name`
- `operation_name`
- `endpoint_override`
- `soap_version`
- `soap_action`
- `input_schema`
- `output_schema`
- `input_mapping`
- `output_mapping`
- `header_config`
- `execution_config`
- `tool_description`
Code-level model:
- `crank_core::SoapTarget`
- `crank_core::SoapProtocolOptions`
- `crank_core::SoapVersion`
- `crank_core::SoapBindingStyle`
- `crank_core::SoapHeaderConfig`
- `crank_core::SoapFaultContract`
- `crank_core::SoapOperationMetadata`
- `crank_schema::XmlNodeKind`
- `crank_schema::XmlQualifiedName`
- `crank_schema::XmlSchemaBinding`
Execution constraints:
- `Protocol::Soap` поддерживает только `unary` и `async_job`;
- `window` и `session` для SOAP не поддерживаются;
- runtime foundation поддерживает `unary` SOAP request-response execution;
- `window` и `session` execution по-прежнему отклоняются как unsupported mode.
## 7. Как оператор настраивает SOAP operation
1. Загружает WSDL.
2. При необходимости загружает supporting XSD.
3. Система извлекает services, ports и operations из WSDL.
4. Оператор выбирает service, port и operation.
5. UI показывает input/output schema в JSON-oriented виде.
6. Оператор настраивает mapping `MCP input -> SOAP body`.
7. При необходимости задает SOAP headers и auth profile.
8. Настраивает output mapping и fault handling.
9. Выполняет test run.
10. Публикует operation как MCP tool.
Foundation routes:
- `POST /operations/{operation_id}/descriptors/wsdl`
- `POST /operations/{operation_id}/descriptors/xsd`
- `GET /operations/{operation_id}/soap/services`
Current UI foundation:
- protocol selection card on wizard step 1;
- dedicated SOAP step 3 panel;
- WSDL upload;
- optional XSD upload;
- backend-driven inspection of `service -> port -> operation`;
- applying selected binding metadata into the operation draft target.
## 8. Поведение runtime
При выполнении SOAP operation runtime должен:
1. Валидировать MCP input.
2. Построить XML envelope.
3. Подставить namespaces, `Content-Type` и `SOAPAction`.
4. Выполнить HTTP request.
5. Разобрать SOAP response и SOAP Fault.
6. Нормализовать XML result в JSON.
7. Применить output mapping.
8. Вернуть итоговый результат.
## 9. Критические нюансы
- WSDL import должен быть отделен от runtime call;
- XML namespaces должны быть first-class частью конфигурации;
- SOAP Fault нельзя сводить только к HTTP error;
- input/output schema должны отображаться в UI как нормализованные поля, а не как raw XML;
- auth и headers должны настраиваться отдельно от body mapping.
## 10. Почему SOAP должен входить в product scope
Если Crank позиционируется как enterprise integration platform, отсутствие SOAP оставляет большую часть legacy и regulated environments вне продукта.
Поэтому SOAP должен быть частью общей protocol strategy наравне с:
- REST
- GraphQL
- gRPC
- WebSocket
Но при этом он должен оставаться request-response oriented adapter, а не ломать общую execution model.
-159
View File
@@ -1,159 +0,0 @@
# WebSocket
## 1. Роль протокола в проекте
WebSocket поддерживается как полноценный upstream protocol для realtime, push-oriented и stateful integrations. Он не заменяет downstream MCP transport, а работает за Crank proxy.
Иными словами:
- downstream: MCP `Streamable HTTP`;
- upstream: WebSocket;
- Crank нормализует WebSocket lifecycle в bounded MCP tool semantics.
## 2. Что поддерживается в целевом продукте
- клиентское WebSocket подключение к внешнему upstream;
- custom headers и auth profiles;
- handshake config;
- optional subprotocol selection;
- subscription payload или start message;
- bounded `window` mode;
- `session` mode с `start/poll/stop`;
- `async_job` mode для control-plane и progress channels;
- JSON message parsing;
- text-frame based event collection;
- mapping `MCP input -> subscribe payload`;
- mapping `WebSocket message -> normalized JSON`;
- heartbeat/keepalive config;
- reconnect policy для controlled session modes.
## 3. Что не входит в текущий продуктовый scope
- raw binary frame passthrough в LLM;
- arbitrary bidirectional conversation tunnel;
- full message bus semantics;
- generic browser-like socket inspector;
- guaranteed resumability across arbitrary upstream websocket providers.
## 4. Ключевое архитектурное ограничение
WebSocket не публикуется как "живой канал в чат". Он должен быть выражен в одной из execution models:
- `window`
- `session`
- `async_job`
Недопустимо:
- бесконечно проксировать frames напрямую в MCP client;
- скрывать жизненный цикл сокета за одним неопределенным tool call;
- смешивать downstream SSE transport и upstream WebSocket semantics в одну абстракцию.
## 5. Типовые use cases
### 5.1. Monitoring and telemetry
- realtime метрики;
- device telemetry;
- market data;
- anomaly events.
### 5.2. Event subscriptions
- alert streams;
- queue events;
- workflow transitions;
- security events.
### 5.3. Stateful control channels
- rollout progress;
- remote task status;
- infrastructure control plane updates;
- long-running remote sessions.
## 6. Внутренняя модель WebSocket operation
WebSocket operation должна включать:
- `url`
- `headers`
- `subprotocols`
- `subscribe_message_template`
- `unsubscribe_message_template`
- `input_mapping`
- `output_mapping`
- `execution_config`
- `tool_description`
Protocol-specific runtime tuning хранится отдельно в `ProtocolOptions.websocket`:
- `heartbeat_interval_ms`
- `reconnect_max_attempts`
- `reconnect_backoff_ms`
## 7. Как оператор настраивает WebSocket operation
1. Указывает URL WebSocket upstream.
2. При необходимости выбирает auth profile и headers.
3. Указывает subprotocol или оставляет пустым.
4. Выбирает execution mode: `window`, `session` или `async_job`.
5. Настраивает subscribe payload.
6. Указывает правила извлечения items, status и cursor.
7. Настраивает aggregation limits.
8. Выполняет test run.
9. Публикует operation как MCP tool или tool family.
## 7.1. Текущий UI foundation
Текущий wizard support для WebSocket уже включает:
- выбор `WebSocket` как protocol family на шаге 1;
- step 2 reuse общего upstream/auth selector;
- отдельный step 3 для:
- socket path override;
- subprotocol list;
- subscribe message template;
- unsubscribe message template;
- `heartbeat_interval_ms`;
- `reconnect_max_attempts`;
- `reconnect_backoff_ms`.
На текущем этапе wizard сериализует:
- `Target::Websocket`
- `ExecutionConfig.protocol_options.websocket`
Это дает оператору usable foundation для `window`, `session` и `async_job` flows even before deeper inspection/test-run polish.
## 8. Поведение runtime
При выполнении WebSocket operation runtime должен:
1. Валидировать MCP input.
2. Построить subscribe payload.
3. Открыть WebSocket connection.
4. Пройти handshake и auth.
5. Отправить subscribe message.
6. Собрать bounded window или session step.
7. Нормализовать messages в JSON.
8. Применить output mapping.
9. Закрыть соединение или сохранить session state.
## 9. Критические нюансы
- upstream WebSocket может быть stateful и требовать explicit unsubscribe;
- heartbeat и reconnect должны быть управляемыми через config, а не захардкоженными;
- session state должен хранить cursor, last_event и subscription metadata;
- disconnect downstream MCP client не означает cancel upstream session;
- runtime обязан уметь cleanly завершать orphaned connections.
## 10. Почему WebSocket должен быть отдельным adapter
WebSocket нельзя свести к "почти SSE" или "почти HTTP", потому что:
- transport двунаправленный;
- lifecycle connection stateful;
- есть handshake, heartbeat и reconnect;
- подписка часто задается сообщением, а не URL;
- semantics событий и прогресса отличаются от request-response вызова.
-5
View File
@@ -361,11 +361,6 @@ where
- mapping rule helpers;
- execution helpers.
### В `crank-proto`
- metadata conversion helpers;
- descriptor lookup helpers.
### В `crank-registry`
- service methods, а не методы на доменных структурах;
-641
View File
@@ -1,641 +0,0 @@
# Streaming Admin API
## 1. Назначение документа
Этот документ фиксирует точные HTTP-контракты для потоковой модели Crank.
Он дополняет:
- [admin-api.md](/home/a.tolmachev/code/rust/mcpaas/docs/admin-api.md)
- [streaming-mcp-plan.md](/home/a.tolmachev/code/rust/mcpaas/docs/streaming-mcp-plan.md)
- [streaming-ui-contract.md](/home/a.tolmachev/code/rust/mcpaas/docs/streaming-ui-contract.md)
- [streaming-runtime-design.md](/home/a.tolmachev/code/rust/mcpaas/docs/streaming-runtime-design.md)
Цель документа:
- зафиксировать DTO;
- зафиксировать route groups;
- зафиксировать валидацию;
- зафиксировать expected error model;
- зафиксировать page-to-endpoint contract для streaming configuration и test-runs.
## 2. Общие принципы
- все ресурсы являются `workspace-scoped`;
- streaming configuration является частью `operation version`;
- `session` и `async_job` state не редактируются напрямую из UI;
- test-runs могут создавать временные sessions и jobs, но не публикуют их как runtime resources;
- transport errors и validation errors разделяются;
- лимиты и safety-параметры валидируются на сервере, а не только в UI.
Базовый префикс:
```text
/api/admin/workspaces/{workspace_id}
```
## 3. Основные ресурсы
- `streaming-presets`
- `streaming-validation`
- `stream-test-runs`
- `stream-sessions`
- `async-jobs`
- `protocol-capabilities`
## 4. Общие DTO
### 4.1. `ExecutionMode`
```json
{
"mode": "unary"
}
```
Допустимые значения:
- `unary`
- `window`
- `session`
- `async_job`
### 4.2. `StreamingConfig`
```json
{
"mode": "window",
"transport_behavior": "server_stream",
"window_duration_ms": 5000,
"poll_interval_ms": 2000,
"upstream_timeout_ms": 10000,
"idle_timeout_ms": 30000,
"max_session_lifetime_ms": 300000,
"max_items": 200,
"max_bytes": 131072,
"aggregation_mode": "summary_plus_samples",
"summary_path": "$.summary",
"items_path": "$.items",
"cursor_path": "$.cursor",
"status_path": "$.status",
"done_path": "$.done",
"redacted_paths": [
"$.items[*].token",
"$.summary.secret"
],
"truncate_item_fields": true,
"max_field_length": 512,
"drop_duplicates": true,
"sampling_rate": 1.0,
"tool_family": {
"start_tool_name": "cluster_events_start",
"poll_tool_name": "cluster_events_poll",
"stop_tool_name": "cluster_events_stop",
"status_tool_name": "deploy_status",
"result_tool_name": "deploy_result",
"cancel_tool_name": "deploy_cancel"
}
}
```
### 4.3. `StreamingValidationError`
```json
{
"code": "streaming_validation_error",
"message": "Streaming configuration is invalid",
"details": [
{
"field": "window_duration_ms",
"reason": "must_be_positive"
},
{
"field": "max_items",
"reason": "must_not_exceed_workspace_limit"
}
]
}
```
### 4.4. `ProtocolCapability`
```json
{
"protocol": "grpc",
"supports_execution_modes": [
"unary",
"window",
"session",
"async_job"
],
"supports_transport_behaviors": [
"request_response",
"server_stream"
],
"supports_auth_kinds": [
"none",
"bearer",
"basic",
"api_key_header",
"api_key_query"
],
"supports_upload_artifacts": [
"proto",
"descriptor_set"
],
"supports_cursor_path": true,
"supports_done_path": true,
"supports_aggregation_mode": [
"raw_items",
"summary_only",
"summary_plus_samples",
"stats",
"latest_state"
]
}
```
## 5. Capabilities endpoints
### `GET /api/admin/workspaces/{workspace_id}/protocol-capabilities`
Назначение:
- отдать UI полную capability matrix;
- убрать protocol-specific hardcode из frontend.
Ответ:
```json
{
"items": [
{
"protocol": "rest",
"supports_execution_modes": ["unary", "window", "session", "async_job"],
"supports_transport_behaviors": ["request_response", "server_stream"],
"supports_auth_kinds": ["none", "bearer", "basic", "api_key_header", "api_key_query"],
"supports_upload_artifacts": [],
"supports_cursor_path": true,
"supports_done_path": true,
"supports_aggregation_mode": ["raw_items", "summary_only", "summary_plus_samples", "stats", "latest_state"]
}
]
}
```
## 6. Streaming validation endpoints
### `POST /api/admin/workspaces/{workspace_id}/streaming/validate`
Назначение:
- проверить streaming config до сохранения operation;
- вернуть protocol-aware ошибки.
Тело:
```json
{
"protocol": "websocket",
"target": {},
"execution_config": {
"streaming": {}
}
}
```
Успех:
```json
{
"valid": true,
"warnings": [
{
"field": "max_bytes",
"code": "may_truncate_large_event_payloads",
"message": "Large event payloads may be truncated"
}
]
}
```
Ошибка:
```json
{
"valid": false,
"errors": [
{
"field": "transport_behavior",
"code": "unsupported_transport_behavior"
}
]
}
```
## 7. Streaming presets endpoints
### `GET /api/admin/workspaces/{workspace_id}/streaming-presets`
Назначение:
- отдать рекомендованные UI presets.
Ответ:
```json
{
"items": [
{
"preset_id": "logs_window_5s",
"display_name": "Logs Window 5s",
"protocols": ["rest", "grpc", "websocket"],
"streaming": {
"mode": "window",
"window_duration_ms": 5000,
"max_items": 100,
"max_bytes": 65536,
"aggregation_mode": "summary_plus_samples"
}
}
]
}
```
## 8. Streaming operation test-runs
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/test-runs`
Назначение:
- выполнить `unary`, `window`, `session` или `async_job` test-run для draft version;
- показать оператору runtime behavior до publish.
Тело:
```json
{
"version": 4,
"input": {
"service": "billing",
"level": "error"
},
"version": 4,
"input": {
"service": "billing",
"level": "error"
}
}
```
Успех для `unary`:
```json
{
"ok": true,
"mode": "unary",
"request_preview": {
"service": "billing",
"level": "error"
},
"response_preview": {
"summary": "completed"
},
"errors": [],
"window": null,
"stream_session": null,
"async_job": null
}
```
Успех для `window`:
```json
{
"ok": true,
"mode": "window",
"request_preview": {
"service": "billing",
"level": "error"
},
"response_preview": {
"summary": {},
"items": []
},
"errors": [],
"window": {
"window_complete": true,
"truncated": false,
"has_more": false,
"cursor": null
},
"stream_session": null,
"async_job": null
}
```
Успех для `session`:
```json
{
"ok": true,
"mode": "session",
"request_preview": {
"service": "billing",
"level": "error"
},
"response_preview": {
"summary": {},
"items": []
},
"errors": [],
"window": null,
"stream_session": {
"session_id": "sess_01j0stream",
"status": "running",
"expires_at": "2026-04-06T12:05:00Z",
"poll_after_ms": 2000,
"preview": {
"summary": {},
"items": []
}
},
"async_job": null
}
```
Успех для `async_job`:
```json
{
"ok": true,
"mode": "async_job",
"request_preview": {
"service": "billing",
"level": "error"
},
"response_preview": {
"job": "started"
},
"errors": [],
"window": null,
"stream_session": null,
"async_job": {
"job_id": "job_01j0deploy",
"status": "running",
"progress": {
"pct": 12
}
}
}
```
Ошибка:
```json
{
"ok": false,
"mode": "window",
"request_preview": {
"service": "billing",
"level": "error"
},
"response_preview": null,
"errors": [
{
"code": "runtime_test_failure",
"message": "upstream timeout"
}
],
"window": null,
"stream_session": null,
"async_job": null
}
```
Примечания:
- endpoint не использует отдельные `stream-test-runs/*` subresources;
- session и async-job test-runs создают обычные runtime resources в `stream_sessions` и `async_jobs`;
- дальнейшее наблюдение идет через `GET /stream-sessions`, `GET /stream-sessions/{session_id}`, `POST /stream-sessions/{session_id}/stop`, `GET /async-jobs`, `GET /async-jobs/{job_id}`, `GET /async-jobs/{job_id}/result`, `POST /async-jobs/{job_id}/cancel`.
## 9. Runtime session resources
### `GET /api/admin/workspaces/{workspace_id}/stream-sessions`
Назначение:
- список активных и недавних session resources для observability/debug UI.
Query params:
- `operation_id`
- `agent_id`
- `status`
- `page`
- `page_size`
Ответ:
```json
{
"items": [
{
"id": "sess_01j0stream",
"operation_id": "op_01j0",
"agent_id": "agent_01j0",
"mode": "session",
"status": "running",
"expires_at": "2026-04-06T12:05:00Z",
"last_poll_at": "2026-04-06T12:00:10Z",
"created_at": "2026-04-06T12:00:00Z"
}
],
"page": 1,
"page_size": 20,
"total": 1
}
```
### `GET /api/admin/workspaces/{workspace_id}/stream-sessions/{session_id}`
Назначение:
- detail session metadata;
- без возврата полного raw state.
### `POST /api/admin/workspaces/{workspace_id}/stream-sessions/{session_id}/stop`
Назначение:
- административно остановить runtime session.
### `DELETE /api/admin/workspaces/{workspace_id}/stream-sessions/{session_id}`
Назначение:
- hard cleanup завершенной session;
- доступен только для `stopped`, `failed`, `expired`.
## 10. Async job resources
### `GET /api/admin/workspaces/{workspace_id}/async-jobs`
Назначение:
- список активных и недавних job resources.
### `GET /api/admin/workspaces/{workspace_id}/async-jobs/{job_id}`
Назначение:
- status/progress/result metadata.
### `POST /api/admin/workspaces/{workspace_id}/async-jobs/{job_id}/cancel`
Назначение:
- административная отмена long-running job.
### `GET /api/admin/workspaces/{workspace_id}/async-jobs/{job_id}/result`
Назначение:
- получить финальный нормализованный результат.
## 11. Integration into operation contracts
`streaming` не является отдельным top-level resource для опубликованной операции. Он живет внутри:
- `OperationVersionDocument.execution_config.streaming`
и входит в:
- `POST /operations`
- `PATCH /operations/{operation_id}`
- `POST /operations/{operation_id}/versions`
- `GET /operations/{operation_id}/versions/{version}`
### 11.1. `OperationVersionDocument.execution_config.streaming`
```json
{
"execution_config": {
"timeout_ms": 10000,
"retries": 0,
"auth_profile_ref": "auth_profile_01j0",
"streaming": {
"mode": "window",
"transport_behavior": "server_stream",
"window_duration_ms": 5000,
"upstream_timeout_ms": 10000,
"max_items": 100,
"max_bytes": 65536,
"aggregation_mode": "summary_plus_samples",
"summary_path": "$.summary",
"items_path": "$.items",
"cursor_path": "$.cursor",
"status_path": "$.status",
"done_path": "$.done",
"redacted_paths": [],
"truncate_item_fields": true,
"max_field_length": 512,
"drop_duplicates": true,
"sampling_rate": 1.0,
"tool_family": {}
}
}
}
```
## 12. Validation rules
### 12.1. Общие
- `mode=unary` запрещает `tool_family`;
- `max_items` > 0;
- `max_bytes` > 0;
- `window_duration_ms` > 0 для `window`;
- `idle_timeout_ms` обязателен для `session`;
- `max_session_lifetime_ms` обязателен для `session`;
- `tool_family.start_tool_name/poll_tool_name/stop_tool_name` обязательны для `session`;
- `tool_family.start_tool_name/status_tool_name/result_tool_name/cancel_tool_name` обязательны для `async_job`.
### 12.2. Protocol-aware
REST:
- `transport_behavior=server_stream` допустим только при streaming-capable target.
GraphQL:
- `window`, `session`, `async_job` пока запрещены;
- `subscription` невалиден как target type.
gRPC:
- `transport_behavior=server_stream` допустим только для server-streaming method.
WebSocket:
- `mode=unary` запрещен;
- требуется `subscribe_message_template` для `session` и `window`.
SOAP:
- `mode=session` запрещен в первой волне;
- `mode=window` допустим только при наличии polling-style status operation family;
- `mode=async_job` требует status/result contract.
## 13. Error model
Коды:
- `streaming_validation_error`
- `unsupported_execution_mode`
- `unsupported_transport_behavior`
- `stream_window_timeout`
- `stream_window_truncated`
- `stream_session_expired`
- `stream_session_not_found`
- `async_job_not_found`
- `async_job_not_ready`
- `async_job_cancelled`
- `protocol_capability_mismatch`
### 13.1. Ошибка несовместимого protocol mode
```json
{
"code": "protocol_capability_mismatch",
"message": "websocket target does not support unary execution mode",
"details": [
{
"field": "execution_config.streaming.mode",
"reason": "unsupported_for_protocol"
}
]
}
```
## 14. Route-to-service mapping
Ожидаемые service handlers в `apps/admin-api`:
- `list_protocol_capabilities`
- `list_streaming_presets`
- `validate_streaming_config`
- `start_stream_test_run`
- `poll_stream_test_run`
- `stop_stream_test_run`
- `get_stream_test_result`
- `list_stream_sessions`
- `get_stream_session`
- `stop_stream_session`
- `delete_stream_session`
- `list_async_jobs`
- `get_async_job`
- `cancel_async_job`
- `get_async_job_result`
Это не route names, а service-level функции orchestration.
-584
View File
@@ -1,584 +0,0 @@
# Streaming Implementation Specification
## 1. Назначение документа
Этот документ переводит streaming architecture в execution-oriented plan, пригодный для агентной разработки.
Он отвечает на вопросы:
- в каком порядке реализовывать фичи;
- какие файлы менять в каждом срезе;
- какие новые модули создавать;
- какие тесты обязательны;
- какие риски и зависимости есть между срезами;
- какой Definition of Done нужен для каждого шага.
Документ дополняет:
- [streaming-mcp-plan.md](/home/a.tolmachev/code/rust/mcpaas/docs/streaming-mcp-plan.md)
- [streaming-admin-api.md](/home/a.tolmachev/code/rust/mcpaas/docs/streaming-admin-api.md)
- [streaming-runtime-design.md](/home/a.tolmachev/code/rust/mcpaas/docs/streaming-runtime-design.md)
- [streaming-ui-contract.md](/home/a.tolmachev/code/rust/mcpaas/docs/streaming-ui-contract.md)
- [protocol-capability-matrix.md](/home/a.tolmachev/code/rust/mcpaas/docs/protocol-capability-matrix.md)
## 2. Принципы агентной реализации
- один vertical slice на ветку;
- docs first, code second;
- не смешивать transport alignment, core model, registry, runtime и UI в одном срезе;
- каждый срез должен быть протестирован отдельно;
- stateful streaming нельзя вводить через скрытые side effects;
- session/job lifecycle должен появляться в коде и API явно.
## 3. Dependency graph
Порядок реализации:
1. `feat/mcp-streamable-http-alignment`
2. `feat/streaming-core-model`
3. `feat/stream-session-store`
4. `feat/runtime-window-mode`
5. `feat/rest-sse-adapter`
6. `feat/grpc-server-streaming-adapter`
7. `feat/session-and-job-tools`
8. `feat/streaming-ui-config`
9. `feat/streaming-e2e`
10. `feat/websocket-upstream-adapter`
11. `feat/soap-architecture-and-core-model`
12. `feat/soap-adapter-foundation`
Почему именно так:
- сначала transport correctness;
- потом core types;
- потом persistence;
- потом bounded runtime;
- потом protocol adapters;
- потом MCP tool publishing;
- потом UI;
- потом e2e;
- потом расширение protocol platform.
## 4. Slice 1: `feat/mcp-streamable-http-alignment`
### 4.1. Цель
Довести `apps/mcp-server` до полного и явного соответствия MCP `Streamable HTTP`.
### 4.2. Файлы
Изменить:
- [apps/mcp-server/src/app.rs](/home/a.tolmachev/code/rust/mcpaas/apps/mcp-server/src/app.rs)
- [apps/mcp-server/src/jsonrpc.rs](/home/a.tolmachev/code/rust/mcpaas/apps/mcp-server/src/jsonrpc.rs)
- [apps/mcp-server/src/session.rs](/home/a.tolmachev/code/rust/mcpaas/apps/mcp-server/src/session.rs)
- [apps/mcp-server/src/main.rs](/home/a.tolmachev/code/rust/mcpaas/apps/mcp-server/src/main.rs)
Добавить при необходимости:
- `apps/mcp-server/src/transport.rs`
- `apps/mcp-server/src/sse.rs`
### 4.3. Что должно быть сделано
- parse `Accept` корректно для `application/json` и `text/event-stream`;
- `GET` endpoint перестает быть `405` и становится SSE-capable transport stream;
- `POST` может отвечать JSON или SSE в зависимости от negotiated transport;
- `Mcp-Session-Id` создается, читается и валидируется явно;
- `MCP-Protocol-Version` валидируется и возвращается явно;
- `DELETE` корректно завершает transport session;
- disconnect не трактуется как cancel operation.
### 4.4. Тесты
Обязательно добавить:
- initialize через JSON response;
- initialize через SSE response;
- `GET` SSE handshake;
- повторное использование `Mcp-Session-Id`;
- invalid protocol version;
- invalid accept header;
- session close through `DELETE`.
### 4.5. DoD
- `mcp-server` ведет себя согласно spec;
- transport tests зелёные;
- docs и code names совпадают.
## 5. Slice 2: `feat/streaming-core-model`
### 5.1. Цель
Ввести доменные типы streaming execution.
### 5.2. Файлы
Изменить:
- [crates/crank-core/src/lib.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-core/src/lib.rs)
- [crates/crank-core/src/operation.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-core/src/operation.rs)
- [crates/crank-core/src/ids.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-core/src/ids.rs)
- [crates/crank-core/src/protocol.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-core/src/protocol.rs)
Добавить:
- `crates/crank-core/src/streaming.rs`
- `crates/crank-core/src/stream_session.rs`
### 5.3. Что должно быть сделано
- добавить `ExecutionMode`;
- добавить `TransportBehavior`;
- добавить `AggregationMode`;
- добавить `StreamingConfig`;
- добавить `StreamSessionId`, `AsyncJobId`;
- добавить `StreamSession`, `AsyncJobHandle`, `StreamStatus`, `JobStatus`;
- вшить `streaming: Option<StreamingConfig>` в `ExecutionConfig`.
### 5.4. Тесты
- serde roundtrip для `StreamingConfig`;
- validation rules для `ExecutionMode`;
- protocol-aware validation helpers.
### 5.5. DoD
- core types стабильны;
- экспортированы через `lib.rs`;
- naming не спорит с docs.
## 6. Slice 3: `feat/stream-session-store`
### 6.1. Цель
Добавить persistent store для `stream_sessions` и `async_jobs`.
### 6.2. Файлы
Изменить:
- [crates/crank-registry/src/lib.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-registry/src/lib.rs)
- [crates/crank-registry/src/model.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-registry/src/model.rs)
- [crates/crank-registry/src/migrations.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-registry/src/migrations.rs)
- [crates/crank-registry/src/postgres.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-registry/src/postgres.rs)
### 6.3. Что должно быть сделано
- таблицы `stream_sessions`, `async_jobs`;
- record types;
- create/get/update/close/list/delete-expired methods;
- filters and paging;
- optimistic transitions для state updates.
### 6.4. Тесты
- migration test;
- create/get/update/close session;
- create/get/update/cancel async job;
- cleanup expired rows;
- invalid transition rejection.
### 6.5. DoD
- storage API соответствует runtime design;
- transitions не допускают silent corruption.
## 7. Slice 4: `feat/runtime-window-mode`
### 7.1. Цель
Ввести bounded `window` mode до session/job complexity.
### 7.2. Файлы
Изменить:
- [crates/crank-runtime/src/lib.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-runtime/src/lib.rs)
- [crates/crank-runtime/src/model.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-runtime/src/model.rs)
- [crates/crank-runtime/src/executor.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-runtime/src/executor.rs)
- [crates/crank-runtime/src/error.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-runtime/src/error.rs)
Добавить:
- `crates/crank-runtime/src/streaming.rs`
- `crates/crank-runtime/src/aggregation.rs`
- `crates/crank-runtime/src/redaction.rs`
### 7.3. Что должно быть сделано
- `execute_window_operation`;
- bounded item/byte limiting;
- `truncated`, `window_complete`, `has_more`;
- summary building;
- redaction and truncation;
- observability write.
### 7.4. Тесты
- raw items mode;
- summary only mode;
- summary plus samples;
- max item truncation;
- max byte truncation;
- redaction;
- timeout handling.
### 7.5. DoD
- unary execution не ломается;
- window mode работает для synthetic adapter-level fixtures.
## 8. Slice 5: `feat/rest-sse-adapter`
### 8.1. Цель
Добавить bounded REST SSE support.
### 8.2. Файлы
Изменить:
- текущий crate [crates/crank-adapter-rest](/home/a.tolmachev/code/rust/mcpaas/crates/crank-adapter-rest)
- [crates/crank-runtime/src/executor.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-runtime/src/executor.rs)
Ожидаемые файлы:
- `src/lib.rs`
- `src/error.rs`
- `src/client.rs`
- `src/sse.rs`
### 8.3. Что должно быть сделано
- SSE connect;
- event parsing;
- bounded collect window;
- session start/poll/stop hooks, если adapter slice сразу включает stateful mode;
- proper close.
### 8.4. Тесты
- local SSE upstream fixture;
- collect N events;
- timeout without events;
- malformed event handling;
- reconnect not enabled by default.
## 9. Slice 6: `feat/grpc-server-streaming-adapter`
### 9.1. Цель
Добавить bounded gRPC server-streaming.
### 9.2. Файлы
Изменить:
- [crates/crank-adapter-grpc](/home/a.tolmachev/code/rust/mcpaas/crates/crank-adapter-grpc)
- [crates/crank-proto](/home/a.tolmachev/code/rust/mcpaas/crates/crank-proto)
- [crates/crank-runtime/src/executor.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-runtime/src/executor.rs)
### 9.3. Что должно быть сделано
- identify unary vs server-streaming method from descriptors;
- invoke server stream;
- collect bounded window;
- decode stream items to normalized JSON;
- integrate with window mode.
### 9.4. Тесты
- local grpc fixture with server-streaming;
- descriptor-backed invocation;
- bounded collection;
- timeout;
- malformed item handling.
## 10. Slice 7: `feat/session-and-job-tools`
### 10.1. Цель
Ввести `session` и `async_job` как first-class runtime and MCP constructs.
### 10.2. Файлы
Изменить:
- [crates/crank-runtime/src/executor.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-runtime/src/executor.rs)
- [apps/mcp-server/src/app.rs](/home/a.tolmachev/code/rust/mcpaas/apps/mcp-server/src/app.rs)
- [apps/mcp-server/src/catalog.rs](/home/a.tolmachev/code/rust/mcpaas/apps/mcp-server/src/catalog.rs)
- [apps/mcp-server/src/session.rs](/home/a.tolmachev/code/rust/mcpaas/apps/mcp-server/src/session.rs)
- [crates/crank-registry/src/postgres.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-registry/src/postgres.rs)
### 10.3. Что должно быть сделано
- runtime methods for start/poll/stop and start/status/result/cancel;
- MCP tool-family generation;
- binding-level tool-name derivation;
- JSON-RPC call routing for tool families;
- session/job observability.
### 10.4. Тесты
- tool listing shows generated family;
- `session start -> poll -> stop`;
- `async_job start -> status -> result -> cancel`;
- invalid session id;
- expired session;
- result before ready.
## 11. Slice 8: `feat/streaming-ui-config`
### 11.1. Цель
Добавить UI для streaming configuration.
### 11.2. Файлы
Изменить:
- `apps/ui/html/wizard/*.html`
- `apps/ui/js/wizard.js`
- `apps/ui/js/api.js`
- `apps/ui/js/i18n.js`
- CSS файлы wizard/settings/pages по необходимости
Добавить:
- `apps/ui/js/streaming-form.js`
- `apps/ui/js/stream-test-run.js`
- `apps/ui/html/stream-sessions.html`
- `apps/ui/html/async-jobs.html`
### 11.3. Что должно быть сделано
- protocol capabilities fetch;
- execution mode selector;
- protocol-specific field visibility;
- validation wiring;
- test-run UX for window/session/async job;
- sessions/jobs views;
- localization.
### 11.4. Тесты
- Playwright:
- configure REST window;
- configure gRPC streaming;
- validation error render;
- session test flow;
- async job test flow.
## 12. Slice 9: `feat/streaming-e2e`
### 12.1. Цель
Зафиксировать end-to-end behavior на живом тестовом стеке.
### 12.2. Что должно быть сделано
- добавить local fixtures:
- REST SSE server
- gRPC server-streaming server
- WebSocket event server
- SOAP fixture, если adapter уже готов
- добавить smoke scenarios;
- включить их в CI.
### 12.3. Тесты
- tool call end-to-end through mcp-server;
- usage/logging on streaming calls;
- session cleanup;
- async job cleanup.
## 13. Slice 10: `feat/websocket-upstream-adapter`
### 13.1. Файлы
Добавить:
- `crates/crank-adapter-websocket/Cargo.toml`
- `crates/crank-adapter-websocket/src/lib.rs`
- `crates/crank-adapter-websocket/src/error.rs`
- `crates/crank-adapter-websocket/src/client.rs`
- `crates/crank-adapter-websocket/src/session.rs`
Изменить:
- [crates/crank-core/src/protocol.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-core/src/protocol.rs)
- [crates/crank-core/src/operation.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-core/src/operation.rs)
- [crates/crank-runtime/src/executor.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-runtime/src/executor.rs)
### 13.2. DoD
- bounded WebSocket window;
- session support;
- reconnect and heartbeat policy;
- capability matrix exposed in admin-api and UI.
## 14. Slice 11: `feat/soap-architecture-and-core-model`
### 14.1. Файлы
Изменить:
- [crates/crank-core/src/protocol.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-core/src/protocol.rs)
- [crates/crank-core/src/operation.rs](/home/a.tolmachev/code/rust/mcpaas/crates/crank-core/src/operation.rs)
- [crates/crank-schema](/home/a.tolmachev/code/rust/mcpaas/crates/crank-schema)
Добавить:
- `crates/crank-core/src/soap.rs`
### 14.2. DoD
- SOAP target model;
- WSDL/XSD-derived metadata model;
- XML normalization strategy documented in code-level types.
## 15. Slice 12: `feat/soap-adapter-foundation`
### 15.1. Файлы
Добавить:
- `crates/crank-adapter-soap/Cargo.toml`
- `crates/crank-adapter-soap/src/lib.rs`
- `crates/crank-adapter-soap/src/error.rs`
- `crates/crank-adapter-soap/src/wsdl.rs`
- `crates/crank-adapter-soap/src/xml.rs`
- `crates/crank-adapter-soap/src/client.rs`
Изменить:
- `apps/admin-api`
- `apps/ui`
- `crates/crank-runtime`
### 15.2. DoD
- WSDL import;
- service/port/operation selection;
- SOAP request-response execution;
- fault normalization;
- UI test-run support.
## 16. State transition tables
## 16.1. `StreamSession`
Allowed:
- `created -> running`
- `running -> running`
- `running -> stopped`
- `running -> expired`
- `running -> failed`
- `stopped -> deleted`
- `expired -> deleted`
- `failed -> deleted`
Forbidden:
- `stopped -> running`
- `expired -> running`
- `deleted -> *`
## 16.2. `AsyncJob`
Allowed:
- `created -> running`
- `running -> running`
- `running -> completed`
- `running -> failed`
- `running -> cancelled`
- `completed -> expired`
- `failed -> expired`
- `cancelled -> expired`
Forbidden:
- `completed -> running`
- `cancelled -> running`
## 17. Sequence outlines
## 17.1. Window
1. MCP client calls tool.
2. `mcp-server` resolves tool binding.
3. `runtime.execute_window_operation`.
4. adapter collects bounded upstream data.
5. runtime aggregates and truncates.
6. `mcp-server` returns final JSON-RPC result.
## 17.2. Session
1. MCP client calls `{tool}_start`.
2. runtime starts upstream session and persists `StreamSession`.
3. client calls `{tool}_poll`.
4. runtime loads session and collects next bounded chunk.
5. client calls `{tool}_stop`.
6. runtime closes upstream and marks session stopped.
## 17.3. Async Job
1. MCP client calls `{tool}_start`.
2. runtime starts long-running job and persists `AsyncJob`.
3. client calls `{tool}_status`.
4. runtime returns current progress.
5. client calls `{tool}_result`.
6. runtime returns final normalized result if ready.
## 18. Acceptance checklist per slice
Перед merge каждого slice агент обязан проверить:
- docs updated if contract changed;
- `just fmt-check`
- `just check`
- `just clippy`
- `just test`
- relevant Playwright/e2e if UI touched;
- no hidden feature flags without docs;
- no unsupported combinations exposed in UI.
## 19. Branch and commit policy
Ожидаемые branch names:
- `feat/mcp-streamable-http-alignment`
- `feat/streaming-core-model`
- `feat/stream-session-store`
- `feat/runtime-window-mode`
- `feat/rest-sse-adapter`
- `feat/grpc-server-streaming-adapter`
- `feat/session-and-job-tools`
- `feat/streaming-ui-config`
- `feat/streaming-e2e`
- `feat/websocket-upstream-adapter`
- `feat/soap-architecture-and-core-model`
- `feat/soap-adapter-foundation`
Ожидаемые commit classes:
- `docs: ...`
- `feat: ...`
- `test: ...`
- `refactor: ...`
- `fix: ...`
## 20. Practical rule for agents
Агент не должен брать следующий slice, пока не выполнены DoD и тесты предыдущего slice.
Если slice требует новый contract:
1. обновить docs;
2. обновить tests;
3. обновить code;
4. только потом переходить дальше.
-702
View File
@@ -1,702 +0,0 @@
# Streaming MCP Plan
## 1. Назначение документа
Этот документ фиксирует целевую архитектуру потоковой обработки в Crank. Он описывает:
- какие transport- и upstream-протоколы поддерживаются;
- какие streaming-сценарии считаются допустимыми;
- какие ограничения обязательны для безопасности и управляемости;
- какие сущности, API, UI-поля и runtime-механизмы нужно добавить;
- в каком порядке это реализовывать.
Документ синхронизирован с MCP transport specification `2025-06-18`, где `Streamable HTTP` определен как основной HTTP transport, а SSE допускается как часть `POST`-response и как отдельный `GET`-stream.
## 2. Базовое архитектурное решение
Crank поддерживает streaming не как бесконечный текстовый поток в чат, а как управляемую инструментальную модель поверх MCP tools.
Принцип:
- transport может быть long-lived;
- tool contract обязан оставаться ограниченным и управляемым;
- upstream stream всегда преобразуется в bounded result, session poll или async job;
- оператор в UI настраивает не "трубу", а режим сбора, агрегации и завершения.
## 3. Поддерживаемые transport- и upstream-протоколы
### 3.1. Downstream MCP transport
Поддерживается:
- `Streamable HTTP` как канонический network transport;
- HTTP `POST` с ответом `application/json` или `text/event-stream`;
- HTTP `GET` для server-to-client SSE stream;
- несколько SSE streams одновременно в рамках одного MCP session;
- `Mcp-Session-Id` и `MCP-Protocol-Version` headers;
- resumable SSE streams как опциональная возможность.
Не является текущим приоритетом:
- `stdio` как обязательная часть продукта;
- собственные нестандартные transport-режимы поверх MCP.
### 3.2. Upstream protocols
Поддерживаются:
- REST unary;
- REST SSE в bounded режимах;
- GraphQL `query` и `mutation`;
- gRPC unary;
- gRPC server-streaming в bounded режимах;
- WebSocket в bounded режимах.
Отложено:
- GraphQL `subscription`;
- gRPC client-streaming;
- gRPC bidirectional streaming;
- arbitrary websocket passthrough;
- raw infinite stream forwarding в MCP client.
### 3.3. Protocol capability matrix
| Protocol | Unary | Window | Session | Async Job | Notes |
| --- | --- | --- | --- | --- | --- |
| REST | Yes | Yes | Limited | Yes | SSE and long-poll sources are supported in controlled form |
| GraphQL | Yes | No | No | Limited | `query` and `mutation` only; `subscription` is future scope |
| gRPC | Yes | Yes | Yes | Yes | server-streaming only; client/bidi deferred |
| WebSocket | No | Yes | Yes | Yes | upstream adapter only; not downstream MCP transport |
| SOAP | Yes | Limited | Limited | Yes | primarily request-response enterprise workflows |
## 4. Поддерживаемые streaming modes
Crank поддерживает четыре режима выполнения operation.
### 4.1. `unary`
Обычный request-response вызов.
Подходит для:
- REST;
- GraphQL `query` и `mutation`;
- gRPC unary;
- SOAP.
### 4.2. `window`
Runtime открывает upstream stream или repeatedly polls upstream source, собирает данные в пределах окна и возвращает один bounded ответ.
Параметры:
- `window_duration_ms`
- `max_items`
- `max_bytes`
- `upstream_timeout_ms`
- `aggregation_mode`
Подходит для:
- логи за период;
- метрики за период;
- event window;
- SSE stream snapshot;
- gRPC server-stream window;
- WebSocket event window.
### 4.3. `session`
Runtime создает stream session, после чего данные читаются по шагам через session-oriented tool family.
Обязательные операции:
- `start`
- `poll`
- `stop`
Подходит для:
- follow logs;
- telemetry follow;
- alert/event feed;
- контроль длительных stream-подписок;
- WebSocket subscriptions.
### 4.4. `async_job`
Runtime запускает long-running upstream operation и возвращает `job_id`.
Обязательные операции:
- `start`
- `status`
- `result`
- `cancel`
Подходит для:
- import/export;
- deploy/reindex;
- batch processing;
- инфраструктурные control-plane действия;
- SOAP workflows with deferred status polling.
## 5. Бизнес-кейсы
### 5.1. Logs Window
LLM запрашивает:
- ошибки сервиса за последние `30s`;
- top errors за последние `100` записей;
- логи по конкретному `correlation_id`.
Runtime:
- собирает bounded окно;
- агрегирует counts, уровни, sample lines;
- возвращает summary плюс ограниченный список items.
### 5.2. Metrics Window
LLM запрашивает:
- latency/error summary по сервису;
- CPU/memory snapshot;
- anomaly summary за окно.
Runtime:
- читает поток метрик;
- агрегирует min/max/avg/p95 или anomaly set;
- возвращает компактный JSON.
### 5.3. Event Feed
LLM запрашивает:
- audit events за период;
- queue events по фильтру;
- security alerts за окно.
Runtime:
- фильтрует events;
- ограничивает количество;
- возвращает items plus cursor.
### 5.4. Long-running Operation Status
LLM запускает:
- reindex;
- import job;
- rollout;
- repair task.
Runtime:
- создает job handle;
- возвращает `job_id`;
- позволяет дальше получать status/result/cancel.
### 5.5. Control Plane Follow
LLM инициирует:
- reboot;
- rollout;
- node drain;
- workflow transition.
Runtime:
- стартует действие;
- пишет progress в session/job state;
- возвращает snapshots по `poll`.
### 5.6. WebSocket Realtime Feeds
LLM запрашивает:
- realtime alert snapshot;
- device telemetry window;
- market data slice;
- status feed по subscription channel.
Runtime:
- открывает upstream WebSocket;
- подписывается на channel;
- собирает bounded окно или session step;
- возвращает summary и limited items.
### 5.7. SOAP Enterprise Operations
LLM запрашивает:
- создание/поиск сущности в ERP;
- запуск enterprise workflow;
- получение статуса batch operation;
- B2B request через SOAP gateway.
Runtime:
- строит SOAP envelope из MCP input;
- вызывает enterprise endpoint;
- нормализует XML response или SOAP Fault;
- возвращает JSON-oriented output.
## 6. Функциональные требования
### 6.1. Общие
- operation должна явно указывать `execution_mode`;
- streaming operation обязана быть bounded;
- runtime обязан поддерживать timeout, max items и max bytes;
- tool output обязан иметь предсказуемую схему;
- stream/session/job state должен быть наблюдаемым и логируемым;
- cancel/stop должен быть явной операцией, а не побочным эффектом disconnect.
### 6.2. Для `window`
- задать размер окна;
- задать лимит items;
- задать лимит bytes;
- выбрать aggregation mode;
- вернуть `truncated` и `window_complete` flags;
- поддерживать optional cursor для следующего окна.
### 6.3. Для `session`
- создать `session_id`;
- поддерживать `poll`;
- поддерживать `stop`;
- хранить курсор и session status;
- иметь `idle_timeout`;
- иметь `max_session_lifetime`;
- удалять expired sessions.
### 6.4. Для `async_job`
- создать `job_id`;
- хранить progress, status и final result metadata;
- поддерживать `cancel`;
- поддерживать retrieval последнего готового результата.
## 7. Нефункциональные требования
### 7.1. Безопасность
- никакого неограниченного passthrough потока;
- обязательные лимиты по времени, items и bytes;
- обязательный redact layer для secret-bearing полей;
- audit trail на `start`, `poll`, `stop`, `cancel`;
- session и job identifiers должны быть криптографически стойкими.
### 7.2. Производительность
- bounded memory per session;
- bounded upstream read buffer;
- ограничение числа параллельных sessions и jobs на workspace и agent;
- backpressure при медленных клиентах;
- возможность early cut-off после достижения лимита.
### 7.3. Надежность
- TTL и cleanup для sessions/jobs;
- устойчивость к disconnect downstream client;
- poll должен быть идемпотентным;
- long-running upstream action не должен считаться отмененным из-за SSE disconnect;
- resumability для downstream SSE допускается как следующая волна, но не является обязательной в первой реализации.
### 7.4. UX
- оператор должен видеть, что operation является `unary`, `window`, `session` или `async_job`;
- UI должен явно показывать все лимиты и режим агрегации;
- результат тестового вызова должен показывать `truncated`, `window_complete`, `has_more`, `status`.
## 8. UI contract
### 8.1. Новый блок `Execution mode`
Поля:
- `mode`: `unary | window | session | async_job`
- `transport_behavior`: `request_response | server_stream`
### 8.2. Блок `Collection limits`
Поля:
- `window_duration_ms`
- `poll_interval_ms`
- `upstream_timeout_ms`
- `idle_timeout_ms`
- `max_session_lifetime_ms`
- `max_items`
- `max_bytes`
### 8.3. Блок `Aggregation`
Поля:
- `aggregation_mode`: `raw_items | summary_only | summary_plus_samples | stats | latest_state`
- `summary_path`
- `items_path`
- `cursor_path`
- `status_path`
- `done_path`
### 8.4. Блок `Safety`
Поля:
- `truncate_item_fields`
- `max_field_length`
- `redacted_paths`
- `drop_duplicates`
- `sampling_rate`
### 8.5. Block `Tool family`
Для `session`:
- `start_tool_name`
- `poll_tool_name`
- `stop_tool_name`
Для `async_job`:
- `start_tool_name`
- `status_tool_name`
- `result_tool_name`
- `cancel_tool_name`
## 9. Domain model changes
### 9.1. `ExecutionMode`
Новый enum:
- `Unary`
- `Window`
- `Session`
- `AsyncJob`
### 9.2. `StreamingConfig`
Новая часть `execution_config`:
- `mode`
- `window_duration_ms`
- `poll_interval_ms`
- `upstream_timeout_ms`
- `idle_timeout_ms`
- `max_session_lifetime_ms`
- `max_items`
- `max_bytes`
- `aggregation_mode`
- `items_path`
- `summary_path`
- `cursor_path`
- `status_path`
- `done_path`
- `redacted_paths`
### 9.3. `StreamSession`
Новая runtime/store сущность:
- `id`
- `workspace_id`
- `agent_id`
- `operation_id`
- `protocol`
- `mode`
- `status`
- `cursor`
- `state_json`
- `expires_at`
- `last_poll_at`
- `created_at`
- `closed_at`
### 9.4. `AsyncJobHandle`
Новая runtime/store сущность:
- `id`
- `workspace_id`
- `agent_id`
- `operation_id`
- `status`
- `progress_json`
- `result_json`
- `error_json`
- `expires_at`
- `created_at`
- `updated_at`
- `finished_at`
## 10. MCP publishing model for streaming tools
### 10.1. Unary and Window
`unary` и `window` публикуются как один MCP tool:
- один input contract;
- один bounded result;
- transport может использовать `application/json` или SSE response stream до финального JSON-RPC response.
### 10.2. Session
`session` публикуется как tool family:
- `{tool}_start`
- `{tool}_poll`
- `{tool}_stop`
Причина:
- lifecycle становится явным;
- LLM получает контролируемую state machine;
- runtime не скрывает долговременное состояние за одним "магическим" вызовом.
### 10.3. Async Job
`async_job` публикуется как tool family:
- `{tool}_start`
- `{tool}_status`
- `{tool}_result`
- `{tool}_cancel`
## 11. Module decomposition and responsibilities
### 11.1. `crank-core`
Новые модули:
- `streaming`
- `stream_session`
Новые типы:
- `ExecutionMode`
- `StreamingConfig`
- `AggregationMode`
- `StreamSession`
- `AsyncJobHandle`
- `StreamStatus`
- `JobStatus`
### 11.2. `crank-registry`
Новые обязанности:
- хранение `stream_sessions`;
- хранение `async_jobs`;
- cleanup expired rows;
- optimistic updates on poll/stop/cancel.
Ожидаемые функции:
- `create_stream_session`
- `get_stream_session`
- `advance_stream_session`
- `close_stream_session`
- `create_async_job`
- `get_async_job`
- `update_async_job_status`
- `cancel_async_job`
- `delete_expired_stream_sessions`
### 11.3. `crank-runtime`
Новые orchestration функции:
- `execute_unary_operation`
- `execute_window_operation`
- `start_stream_session`
- `poll_stream_session`
- `stop_stream_session`
- `start_async_job`
- `get_async_job_status`
- `get_async_job_result`
- `cancel_async_job`
### 11.4. Protocol adapters
REST:
- unary HTTP;
- bounded SSE collection;
- bounded long-poll collection.
GraphQL:
- `query` и `mutation`;
- `subscription` отложен на отдельную protocol wave.
gRPC:
- unary;
- bounded server-stream collection;
- client/bidi отложены на отдельную protocol wave.
WebSocket:
- bounded event collection;
- subscribe/poll/stop orchestration;
- heartbeat and reconnect policy.
SOAP:
- WSDL-driven request/response adapter;
- XML normalization;
- SOAP Fault normalization;
- future WS-Security expansion.
### 11.5. `apps/mcp-server`
Новые обязанности:
- корректно вести `Streamable HTTP` lifecycle;
- принимать `POST` с `Accept: application/json, text/event-stream`;
- отдавать `application/json` или `text/event-stream`;
- поддерживать `GET` SSE stream для server-to-client messages и notifications;
- вести `Mcp-Session-Id`;
- публиковать tool families для `session` и `async_job`.
### 11.6. `apps/admin-api`
Новые обязанности:
- CRUD и versioning для streaming config;
- тестовые window/session/job runs;
- UI-oriented validation ошибок для streaming fields.
### 11.7. `apps/ui`
- конфиг execution mode;
- конфиг limits/aggregation/safety;
- test-run screen для bounded window/session/job behavior;
- отдельные предупреждения про truncation и timeouts.
## 12. Границы текущей продуктовой волны
В первой продуктовой волне входит:
- `Streamable HTTP` и SSE на MCP transport;
- `window` mode;
- `async_job` mode;
- REST SSE;
- gRPC server streaming;
- tool family generation;
- bounded session/job state.
Во второй продуктовой волне:
- WebSocket upstream adapter;
- SOAP adapter foundation;
- richer session tooling;
- expanded protocol smoke suite.
Отложено:
- GraphQL subscriptions;
- gRPC client streaming;
- gRPC bidirectional streaming;
- raw infinite stream passthrough;
- guaranteed resumability across all stream types;
- generic websocket proxy mode.
## 13. Порядок реализации
### 13.1. `feat/streaming-mcp-architecture`
- зафиксировать docs;
- обновить protocol support matrix;
- синхронизировать `TASKS.md`.
### 13.2. `feat/mcp-streamable-http-alignment`
- довести `mcp-server` до полного соответствия `Streamable HTTP`;
- session headers;
- GET SSE;
- protocol version header validation;
- explicit cancel behavior.
### 13.3. `feat/streaming-core-model`
- ввести `ExecutionMode`, `StreamingConfig`, `StreamSession`, `AsyncJobHandle`.
### 13.4. `feat/stream-session-store`
- таблицы `stream_sessions` и `async_jobs`;
- cleanup;
- optimistic state transitions.
### 13.5. `feat/runtime-window-mode`
- bounded collection для `window`;
- `truncated`, `window_complete`, `has_more`.
### 13.6. `feat/rest-sse-adapter`
- поддержка REST SSE upstream.
### 13.7. `feat/grpc-server-streaming-adapter`
- поддержка bounded gRPC server-streaming.
### 13.8. `feat/session-and-job-tools`
- генерация tool families;
- `start/poll/stop`;
- `start/status/result/cancel`.
### 13.9. `feat/websocket-upstream-adapter`
- bounded WebSocket collection;
- subscribe/unsubscribe templates;
- heartbeat/reconnect policy;
- session integration.
### 13.10. `feat/soap-architecture-and-core-model`
- WSDL/XSD-driven domain model;
- SOAP execution config;
- XML normalization strategy.
### 13.11. `feat/soap-adapter-foundation`
- runtime SOAP adapter;
- envelope builder;
- fault normalization;
- test-run support.
### 13.12. `feat/streaming-ui-config`
- новый execution mode selector;
- limits/aggregation/safety blocks;
- test-run UX.
### 13.13. `feat/streaming-e2e`
- публичные smoke targets;
- e2e сценарии;
- manual regression plan.
## 14. Практический итог
Crank должен поддерживать streaming как полнофункциональный MCP proxy, но в управляемой форме:
- transport-level SSE и `Streamable HTTP` поддерживаются;
- upstream streaming поддерживается там, где его можно bounded-ить;
- tool contract остается контролируемым;
- UI настраивает лимиты, aggregation и lifecycle;
- платформа не превращается в бесконечную data pipe.
-580
View File
@@ -1,580 +0,0 @@
# Streaming Runtime Design
## 1. Назначение документа
Этот документ фиксирует, как потоковая модель должна быть разложена по crates, traits, services и функциям.
Цель:
- избежать god-services;
- зафиксировать boundaries между `core`, `registry`, `runtime`, protocol adapters и `mcp-server`;
- расписать ожидаемые функции и их ответственность до уровня инженерной спецификации.
## 2. Общая схема слоев
### 2.1. `crank-core`
Отвечает за:
- типы `ExecutionMode`, `StreamingConfig`, `AggregationMode`;
- типы `StreamSession`, `AsyncJobHandle`, `StreamStatus`, `JobStatus`;
- validation helpers без инфраструктуры.
### 2.2. `crank-registry`
Отвечает за:
- persistence session/job state;
- optimistic transitions;
- cleanup expired state.
### 2.3. `crank-runtime`
Отвечает за:
- orchestration execution modes;
- dispatch в protocol adapter;
- bounded collection;
- aggregation;
- state transitions;
- invocation logging.
### 2.4. Protocol adapters
Отвечают за:
- protocol-specific upstream behavior;
- connect/request/collect/close;
- преобразование upstream payload в нормализованный JSON.
### 2.5. `apps/mcp-server`
Отвечает за:
- downstream MCP transport;
- tool-family generation;
- JSON-RPC lifecycle;
- transport/session routing.
### 2.6. `apps/admin-api`
Отвечает за:
- config CRUD;
- test-runs;
- validation;
- UI-oriented metadata and previews.
## 3. Core domain types
## 3.1. `ExecutionMode`
```rust
pub enum ExecutionMode {
Unary,
Window,
Session,
AsyncJob,
}
```
Методы:
- `fn is_stateful(&self) -> bool`
- `fn requires_tool_family(&self) -> bool`
## 3.2. `AggregationMode`
```rust
pub enum AggregationMode {
RawItems,
SummaryOnly,
SummaryPlusSamples,
Stats,
LatestState,
}
```
Методы:
- `fn needs_items(&self) -> bool`
- `fn needs_summary(&self) -> bool`
## 3.3. `StreamingConfig`
```rust
pub struct StreamingConfig {
pub mode: ExecutionMode,
pub transport_behavior: TransportBehavior,
pub window_duration_ms: Option<u64>,
pub poll_interval_ms: Option<u64>,
pub upstream_timeout_ms: Option<u64>,
pub idle_timeout_ms: Option<u64>,
pub max_session_lifetime_ms: Option<u64>,
pub max_items: Option<u32>,
pub max_bytes: Option<u32>,
pub aggregation_mode: AggregationMode,
pub summary_path: Option<String>,
pub items_path: Option<String>,
pub cursor_path: Option<String>,
pub status_path: Option<String>,
pub done_path: Option<String>,
pub redacted_paths: Vec<String>,
pub truncate_item_fields: bool,
pub max_field_length: Option<u32>,
pub drop_duplicates: bool,
pub sampling_rate: Option<f64>,
pub tool_family: ToolFamilyConfig,
}
```
Методы:
- `fn validate_common(&self) -> Result<(), StreamingConfigError>`
- `fn validate_for_protocol(&self, protocol: Protocol) -> Result<(), StreamingConfigError>`
- `fn effective_max_items(&self, limits: &StreamingLimits) -> u32`
- `fn effective_max_bytes(&self, limits: &StreamingLimits) -> u32`
- `fn effective_timeout(&self, defaults: &StreamingDefaults) -> Duration`
## 3.4. `StreamSession`
```rust
pub struct StreamSession {
pub id: StreamSessionId,
pub workspace_id: WorkspaceId,
pub agent_id: Option<AgentId>,
pub operation_id: OperationId,
pub protocol: Protocol,
pub mode: ExecutionMode,
pub status: StreamStatus,
pub cursor: Option<Value>,
pub state: Value,
pub expires_at: DateTime<Utc>,
pub last_poll_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
pub closed_at: Option<DateTime<Utc>>,
}
```
Методы:
- `fn is_expired(&self, now: DateTime<Utc>) -> bool`
- `fn can_poll(&self, now: DateTime<Utc>) -> bool`
- `fn mark_polled(&mut self, now: DateTime<Utc>)`
- `fn mark_closed(&mut self, now: DateTime<Utc>)`
## 3.5. `AsyncJobHandle`
```rust
pub struct AsyncJobHandle {
pub id: AsyncJobId,
pub workspace_id: WorkspaceId,
pub agent_id: Option<AgentId>,
pub operation_id: OperationId,
pub status: JobStatus,
pub progress: Value,
pub result: Option<Value>,
pub error: Option<Value>,
pub expires_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub finished_at: Option<DateTime<Utc>>,
}
```
Методы:
- `fn is_finished(&self) -> bool`
- `fn can_cancel(&self) -> bool`
- `fn mark_finished(&mut self, now: DateTime<Utc>, result: Value)`
- `fn mark_failed(&mut self, now: DateTime<Utc>, error: Value)`
## 4. Registry contracts
## 4.1. `StreamSessionRepository`
```rust
#[async_trait]
pub trait StreamSessionRepository {
async fn create_stream_session(&self, session: NewStreamSession) -> Result<StreamSession, RegistryError>;
async fn get_stream_session(&self, id: &StreamSessionId) -> Result<Option<StreamSession>, RegistryError>;
async fn update_stream_session_state(&self, update: StreamSessionStateUpdate) -> Result<StreamSession, RegistryError>;
async fn close_stream_session(&self, id: &StreamSessionId, now: DateTime<Utc>) -> Result<(), RegistryError>;
async fn list_stream_sessions(&self, filter: StreamSessionFilter) -> Result<Page<StreamSession>, RegistryError>;
async fn delete_expired_stream_sessions(&self, now: DateTime<Utc>) -> Result<u64, RegistryError>;
}
```
## 4.2. `AsyncJobRepository`
```rust
#[async_trait]
pub trait AsyncJobRepository {
async fn create_async_job(&self, job: NewAsyncJob) -> Result<AsyncJobHandle, RegistryError>;
async fn get_async_job(&self, id: &AsyncJobId) -> Result<Option<AsyncJobHandle>, RegistryError>;
async fn update_async_job_status(&self, update: AsyncJobStatusUpdate) -> Result<AsyncJobHandle, RegistryError>;
async fn cancel_async_job(&self, id: &AsyncJobId, now: DateTime<Utc>) -> Result<(), RegistryError>;
async fn list_async_jobs(&self, filter: AsyncJobFilter) -> Result<Page<AsyncJobHandle>, RegistryError>;
async fn delete_expired_async_jobs(&self, now: DateTime<Utc>) -> Result<u64, RegistryError>;
}
```
## 4.3. Storage rules
- update methods должны использовать optimistic concurrency, если state transitions конфликтуют;
- `poll` не должен silently reopen closed session;
- cleanup job должен быть отдельным service;
- session/job state не должен хранить необрезанные raw payloads без лимитов.
## 5. Runtime contracts
## 5.1. `ProtocolAdapter`
Базовый trait не должен пытаться описать все streaming cases в одном методе.
```rust
#[async_trait]
pub trait ProtocolAdapter {
async fn execute_unary(&self, ctx: UnaryExecutionContext) -> Result<NormalizedResponse, AdapterError>;
async fn execute_window(&self, ctx: WindowExecutionContext) -> Result<WindowExecutionResult, AdapterError>;
async fn start_session(&self, ctx: SessionStartContext) -> Result<SessionStartResult, AdapterError>;
async fn poll_session(&self, ctx: SessionPollContext) -> Result<SessionPollResult, AdapterError>;
async fn stop_session(&self, ctx: SessionStopContext) -> Result<(), AdapterError>;
async fn start_async_job(&self, ctx: AsyncJobStartContext) -> Result<AsyncJobStartResult, AdapterError>;
async fn get_async_job_status(&self, ctx: AsyncJobStatusContext) -> Result<AsyncJobStatusResult, AdapterError>;
async fn get_async_job_result(&self, ctx: AsyncJobResultContext) -> Result<NormalizedResponse, AdapterError>;
async fn cancel_async_job(&self, ctx: AsyncJobCancelContext) -> Result<(), AdapterError>;
}
```
Не каждый adapter обязан поддерживать все методы. Capability mismatch должен проверяться выше.
## 5.2. `OperationExecutor`
Главная orchestration точка в `crank-runtime`.
Ожидаемые функции:
- `execute_unary_operation`
- `execute_window_operation`
- `start_stream_session`
- `poll_stream_session`
- `stop_stream_session`
- `start_async_job`
- `get_async_job_status`
- `get_async_job_result`
- `cancel_async_job`
### `execute_unary_operation`
Отвечает за:
- schema validation;
- auth resolution;
- adapter dispatch;
- output mapping;
- observability write.
### `execute_window_operation`
Отвечает за:
- schema validation;
- auth resolution;
- adapter dispatch в `execute_window`;
- aggregation;
- truncation flags;
- observability write.
### `start_stream_session`
Отвечает за:
- schema validation;
- auth resolution;
- adapter `start_session`;
- registry `create_stream_session`;
- initial preview result;
- observability write.
### `poll_stream_session`
Отвечает за:
- load session from registry;
- expiration check;
- adapter `poll_session`;
- registry `update_stream_session_state`;
- output mapping;
- observability write.
### `stop_stream_session`
Отвечает за:
- load session;
- adapter `stop_session`;
- registry close;
- observability write.
### `start_async_job`
Отвечает за:
- schema validation;
- adapter `start_async_job`;
- registry `create_async_job`;
- observability write.
### `get_async_job_status`
Отвечает за:
- registry load;
- adapter `get_async_job_status`, если upstream status is live;
- registry update;
- normalized status result.
### `get_async_job_result`
Отвечает за:
- job readiness check;
- adapter `get_async_job_result`, если result lazy-loaded;
- output mapping;
- observability write.
### `cancel_async_job`
Отвечает за:
- adapter cancel;
- registry cancel transition;
- observability write.
## 5.3. Aggregation services
Нужно отделить aggregation от adapters.
Отдельные services:
- `WindowAggregator`
- `SummaryBuilder`
- `CursorTracker`
- `PayloadLimiter`
- `RedactionService`
### `WindowAggregator`
Функции:
- `collect_items`
- `apply_item_limit`
- `apply_byte_limit`
- `mark_truncated`
### `SummaryBuilder`
Функции:
- `build_summary`
- `build_stats_summary`
- `build_latest_state_summary`
- `build_summary_plus_samples`
### `PayloadLimiter`
Функции:
- `truncate_item_fields`
- `truncate_bytes`
- `enforce_max_items`
### `RedactionService`
Функции:
- `redact_paths`
- `redact_object`
- `redact_item`
## 6. Adapter responsibilities
## 6.1. REST adapter
Функции:
- `execute_rest_unary`
- `execute_rest_window`
- `start_rest_session`
- `poll_rest_session`
- `stop_rest_session`
- `start_rest_async_job`
- `get_rest_async_job_status`
- `get_rest_async_job_result`
- `cancel_rest_async_job`
Дополнительные helpers:
- `open_sse_stream`
- `collect_sse_window`
- `parse_sse_event`
- `close_sse_stream`
## 6.2. GraphQL adapter
Функции:
- `execute_graphql_unary`
Отдельно отложено:
- `execute_graphql_subscription_window`
- `start_graphql_subscription_session`
## 6.3. gRPC adapter
Функции:
- `execute_grpc_unary`
- `execute_grpc_window`
- `start_grpc_session`
- `poll_grpc_session`
- `stop_grpc_session`
- `start_grpc_async_job`
- `get_grpc_async_job_status`
- `get_grpc_async_job_result`
- `cancel_grpc_async_job`
Helpers:
- `invoke_unary_method`
- `open_server_stream`
- `collect_server_stream_window`
- `decode_stream_item`
## 6.4. WebSocket adapter
Функции:
- `execute_websocket_window`
- `start_websocket_session`
- `poll_websocket_session`
- `stop_websocket_session`
- `start_websocket_async_job`
- `get_websocket_async_job_status`
- `cancel_websocket_async_job`
Helpers:
- `connect_websocket`
- `send_subscribe_message`
- `send_unsubscribe_message`
- `read_next_frame`
- `decode_text_frame`
- `heartbeat_tick`
- `reconnect_if_needed`
## 6.5. SOAP adapter
Функции:
- `execute_soap_unary`
- `start_soap_async_job`
- `get_soap_async_job_status`
- `get_soap_async_job_result`
- `cancel_soap_async_job`
Helpers:
- `render_soap_envelope`
- `render_soap_headers`
- `parse_soap_envelope`
- `parse_soap_fault`
- `normalize_xml_value`
## 7. MCP server design
## 7.1. Route handlers
Ожидаемые handlers:
- `handle_initialize`
- `handle_notifications_initialized`
- `handle_ping`
- `handle_tools_list`
- `handle_tools_call`
- `handle_get_sse_stream`
- `handle_delete_session`
## 7.2. Tool-family generation
Функции:
- `build_unary_tool_definition`
- `build_window_tool_definition`
- `build_session_tool_family`
- `build_async_job_tool_family`
Для `session`:
- `build_session_start_tool`
- `build_session_poll_tool`
- `build_session_stop_tool`
Для `async_job`:
- `build_async_job_start_tool`
- `build_async_job_status_tool`
- `build_async_job_result_tool`
- `build_async_job_cancel_tool`
## 7.3. Transport session management
Функции:
- `ensure_protocol_version`
- `resolve_transport_mode`
- `ensure_mcp_session`
- `attach_session_headers`
- `stream_sse_event`
- `close_transport_session`
## 8. Admin API service design
Ожидаемые service функции:
- `validate_streaming_config`
- `list_protocol_capabilities`
- `list_streaming_presets`
- `start_stream_test_run`
- `poll_stream_test_run`
- `stop_stream_test_run`
- `get_stream_test_result`
- `list_stream_sessions`
- `get_stream_session`
- `stop_stream_session`
- `delete_stream_session`
- `list_async_jobs`
- `get_async_job`
- `cancel_async_job`
- `get_async_job_result`
## 9. Cleanup jobs
Отдельные jobs:
- `expire_stream_sessions`
- `expire_async_jobs`
- `reap_orphaned_transport_sessions`
- `compact_stream_payloads`, если будет нужен storage optimization layer
## 10. Design rules
- adapters не агрегируют product-level summaries;
- runtime не знает деталей transport framing;
- `mcp-server` не знает про upstream protocols;
- `admin-api` не управляет live protocol connections напрямую;
- session/job lifecycle должен быть явным в names и contracts;
- cancellation не должна зависеть от TCP disconnect;
- bounded limits должны применяться раньше, чем payload попадет в final result.
-442
View File
@@ -1,442 +0,0 @@
# Streaming UI Contract
## 1. Назначение документа
Этот документ фиксирует точный UI-контракт для настройки потоковых операций.
Цель:
- определить экраны и блоки wizard;
- перечислить все поля;
- перечислить валидации;
- определить protocol-specific visibility rules;
- зафиксировать UX states, warnings и system messages.
## 2. Основные экраны
Потоковая конфигурация живет в:
- `Operations Wizard`
- `Operation Detail`
- `Test Run`
- `Agent Tool Preview`
- `Logs` / `Usage` observability surfaces
Дополнительно админские страницы:
- `Stream Sessions`
- `Async Jobs`
Для test-run UX:
- wizard status block должен различать `unary`, `window`, `session`, `async_job`;
- `window` показывает bounded flags `window_complete`, `truncated`, `has_more`;
- `session` показывает `session_id`, `poll_after_ms` и переводит оператора к странице `Stream Sessions`;
- `async_job` показывает `job_id` и переводит оператора к странице `Async Jobs`;
- request/response preview textareas остаются общими для всех режимов.
## 3. Wizard information architecture
## 3.1. Shared wizard structure
Шаги:
1. `Protocol`
2. `Upstream`
3. `Request / Subscription`
4. `Execution Mode`
5. `Input Schema`
6. `Output / Aggregation`
7. `Safety and Limits`
8. `Tool Family`
9. `Test Run`
10. `Publish`
## 3.2. Step `Execution Mode`
Поля:
- `Mode`
- `Unary`
- `Window`
- `Session`
- `Async Job`
- `Transport behavior`
- `Request / response`
- `Server stream`
Подсказки:
- `Unary` для обычных request-response integrations.
- `Window` для bounded snapshots из stream или feed.
- `Session` для follow-style tools с `start/poll/stop`.
- `Async Job` для long-running operations с `status/result/cancel`.
Валидации:
- `Transport behavior=server_stream` не может использоваться с protocol, который его не поддерживает.
- `WebSocket` не может быть `Unary`.
- `SOAP` в первой волне не может быть `Session`.
## 3.3. Step `Input Schema`
Поля:
- `Input schema source`
- manual
- sample-derived
- descriptor/wsdl-derived
- `Input fields`
- `Required fields`
- `Defaults`
- `Mapping preview`
## 3.4. Step `Output / Aggregation`
Поля:
- `Aggregation mode`
- `Raw items`
- `Summary only`
- `Summary + samples`
- `Stats`
- `Latest state`
- `Items path`
- `Summary path`
- `Cursor path`
- `Status path`
- `Done path`
- `Output mapping`
Валидации:
- `Items path` обязателен для `Raw items` и `Summary + samples`.
- `Summary path` обязателен для `Summary only`, `Summary + samples`, `Stats`, `Latest state`.
- `Done path` обязателен для `Async Job`, если upstream status не выражается отдельным field set.
## 3.5. Step `Safety and Limits`
Поля:
- `Window duration`
- `Poll interval`
- `Upstream timeout`
- `Idle timeout`
- `Session lifetime`
- `Max items`
- `Max bytes`
- `Max field length`
- `Drop duplicates`
- `Sampling rate`
- `Redacted paths`
Валидации:
- `Window duration` обязателен для `Window`.
- `Poll interval` обязателен для `Session`.
- `Idle timeout` обязателен для `Session`.
- `Session lifetime` обязателен для `Session`.
- `Max items` > 0.
- `Max bytes` > 0.
- `Sampling rate` > 0 and <= 1.
## 3.6. Step `Tool Family`
Показывается только для:
- `Session`
- `Async Job`
Для `Session`:
- `Start tool name`
- `Poll tool name`
- `Stop tool name`
Для `Async Job`:
- `Start tool name`
- `Status tool name`
- `Result tool name`
- `Cancel tool name`
Валидации:
- имена обязательны;
- имена должны быть уникальны в пределах agent;
- имена не должны конфликтовать с already bound tools.
## 4. Protocol-specific UI
## 4.1. REST
Поля:
- `Base URL`
- `HTTP method`
- `Path template`
- `Headers`
- `Query mapping`
- `Body mapping`
- `SSE enabled`
- `SSE event filter`
Visibility:
- `SSE enabled` показывается только если method/endpoint допускают stream use case;
- `Window` и `Session` доступны, если оператор включает stream behavior.
## 4.2. GraphQL
Поля:
- `Endpoint`
- `Operation type`
- `Operation name`
- `Query template`
- `Variables schema`
- `Response path`
Visibility:
- `Window`, `Session`, `Async Job` скрыты в текущей продуктовой волне;
- `Subscription` UI не показывается.
## 4.3. gRPC
Поля:
- `Server address`
- `Package`
- `Service`
- `Method`
- `Descriptor source`
- `Stream kind`
- `Unary`
- `Server streaming`
Visibility:
- `Window`, `Session`, `Async Job` доступны только для `Server streaming`;
- `Client streaming` и `Bidirectional` не показываются вообще.
## 4.4. WebSocket
Поля:
- `WebSocket URL`
- `Subprotocols`
- `Connect timeout`
- `Heartbeat interval`
- `Subscribe message template`
- `Unsubscribe message template`
- `Message envelope path`
Visibility:
- `Unary` не показывается;
- `Window`, `Session`, `Async Job` доступны всегда;
- `Subscribe message template` обязательно для `Window` и `Session`.
## 4.5. SOAP
Поля:
- `WSDL source`
- `Service`
- `Port`
- `Operation`
- `SOAP version`
- `SOAPAction`
- `Endpoint override`
- `Header config`
Visibility:
- `Session` скрыт;
- `Window` скрыт по умолчанию и включается только для polling-style enterprise workflows;
- `Unary` и `Async Job` доступны.
## 5. Test Run UX
## 5.1. Window
UI должен показывать:
- `Status`
- `Duration`
- `Items count`
- `Bytes count`
- `Window complete`
- `Truncated`
- `Has more`
- `Summary`
- `Items preview`
- `Cursor`
Кнопки:
- `Run window test`
- `Repeat`
- `Save config`
## 5.2. Session
UI должен показывать:
- `Session id`
- `Status`
- `Expires at`
- `Poll after`
- `Summary preview`
- `Items preview`
Кнопки:
- `Start session`
- `Poll next chunk`
- `Stop session`
## 5.3. Async Job
UI должен показывать:
- `Job id`
- `Status`
- `Progress`
- `Started at`
- `Finished at`
- `Result preview`
Кнопки:
- `Start job`
- `Refresh status`
- `Get result`
- `Cancel job`
## 6. Page-level states
Каждый streaming-aware экран обязан поддерживать:
- `idle`
- `validating`
- `saving`
- `testing`
- `running`
- `completed`
- `failed`
- `stopped`
- `expired`
## 7. Warnings and messages
## 7.1. Validation warnings
- `This mode will truncate responses above the configured byte limit.`
- `Current protocol does not support the selected execution mode.`
- `Session lifetime is shorter than idle timeout.`
- `Aggregation mode summary_only hides raw items from the final tool output.`
- `WebSocket reconnect may duplicate events if upstream does not provide cursor semantics.`
- `SOAP async mode requires a separate status/result contract.`
## 7.2. Confirmations
- `Stop current session?`
- `Cancel running job?`
- `Switching execution mode will reset protocol-specific fields.`
## 7.3. Errors
- `Streaming configuration is invalid.`
- `Test session expired.`
- `Upstream did not return any messages within the configured window.`
- `The collected stream payload was truncated by size limits.`
- `This protocol does not support the selected execution mode.`
## 8. Stream Sessions page
Колонки:
- `Session ID`
- `Operation`
- `Agent`
- `Mode`
- `Status`
- `Created`
- `Last poll`
- `Expires`
Actions:
- `Open`
- `Stop`
- `Delete`
Detail view:
- `Session metadata`
- `Cursor preview`
- `State summary`
- `Recent events summary`
## 9. Async Jobs page
Колонки:
- `Job ID`
- `Operation`
- `Agent`
- `Status`
- `Progress`
- `Created`
- `Updated`
- `Finished`
Actions:
- `Open`
- `Cancel`
- `Get result`
Detail view:
- `Job metadata`
- `Progress payload`
- `Result preview`
- `Error preview`
## 10. Exact frontend adapters
Ожидаемые frontend modules:
- `streaming-form.js`
- `streaming-validation.js`
- `stream-test-run.js`
- `stream-sessions.js`
- `async-jobs.js`
Ожидаемые frontend functions:
- `loadProtocolCapabilities()`
- `applyStreamingPreset()`
- `validateStreamingConfig()`
- `serializeStreamingConfig()`
- `deserializeStreamingConfig()`
- `startWindowTest()`
- `startSessionTest()`
- `pollSessionTest()`
- `stopSessionTest()`
- `startAsyncJobTest()`
- `refreshAsyncJobStatus()`
- `loadAsyncJobResult()`
## 11. Shared UI rules
- UI никогда не должен предлагать unsupported mode;
- UI должен строить availability по `protocol-capabilities`, а не по hardcoded if-else;
- UI должен явно объяснять, почему поле скрыто или disabled;
- UI должен всегда показывать итоговую tool topology:
- `1 tool`
- `3 tools start/poll/stop`
- `4 tools start/status/result/cancel`
+2 -12
View File
@@ -19,7 +19,6 @@
- `crank-schema`
- `crank-mapping`
- `crank-proto`
- небольшие части `crank-core`
Что проверять:
@@ -28,8 +27,6 @@
- `JSONPath` parsing;
- применение input/output mapping;
- генерацию чернового mapping;
- protobuf -> schema normalization;
- JSON -> protobuf и protobuf -> JSON conversion.
### 2.2. Integration tests
@@ -50,11 +47,9 @@
### 2.3. Adapter tests
Отдельно для каждого протокола:
Отдельно для Community-протокола:
- REST adapter;
- GraphQL adapter;
- gRPC unary adapter.
Что проверять:
@@ -68,8 +63,6 @@
Минимально нужны сценарии:
- создать REST operation -> протестировать -> опубликовать -> вызвать как MCP tool;
- создать GraphQL operation -> протестировать -> опубликовать -> вызвать как MCP tool;
- загрузить `.proto` или descriptor set -> создать gRPC unary operation -> протестировать -> опубликовать -> вызвать как MCP tool.
## 3. Что должно быть покрыто обязательно
@@ -83,10 +76,8 @@
### Обязательно до первого демо
- хотя бы один end-to-end сценарий для каждого из трех протоколов;
- хотя бы один end-to-end сценарий для REST;
- negative tests на invalid `JSONPath`;
- negative tests на invalid protobuf descriptor;
- negative tests на GraphQL errors при HTTP `200`.
## 4. Формат тестовых данных
@@ -94,7 +85,6 @@
- JSON fixtures для sample input/output;
- YAML golden files для export/import;
- `.proto` и descriptor fixtures для gRPC;
- snapshot tests для generated draft.
## 5. Техническая стратегия