community: remove premium protocols and streaming surface
This commit is contained in:
@@ -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 на стенде отсутствуют:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`
|
||||
|
||||
Назначение:
|
||||
|
||||
|
||||
@@ -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 в системе должен иметь отдельный адаптер и отдельную конфигурационную модель.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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 вызова.
|
||||
@@ -361,11 +361,6 @@ where
|
||||
- mapping rule helpers;
|
||||
- execution helpers.
|
||||
|
||||
### В `crank-proto`
|
||||
|
||||
- metadata conversion helpers;
|
||||
- descriptor lookup helpers.
|
||||
|
||||
### В `crank-registry`
|
||||
|
||||
- service methods, а не методы на доменных структурах;
|
||||
|
||||
@@ -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.
|
||||
@@ -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. только потом переходить дальше.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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`
|
||||
@@ -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. Техническая стратегия
|
||||
|
||||
Reference in New Issue
Block a user