docs: add detailed streaming specifications

This commit is contained in:
a.tolmachev
2026-04-06 02:35:00 +03:00
parent 7f15b2db9e
commit dbc57a0419
8 changed files with 1775 additions and 4 deletions
+4
View File
@@ -49,6 +49,10 @@ Crank - платформа для публикации внешних API в в
- `docs/public-smoke-targets.md` - готовые публичные upstream-сервисы и payload-ы для smoke-проверки MCP.
- `docs/secrets-auth-plan.md` - целевая модель upstream secrets, auth profiles и пошаговый план реализации.
- `docs/streaming-mcp-plan.md` - целевая модель MCP transport streaming, upstream streaming и поэтапный план реализации.
- `docs/streaming-admin-api.md` - точные HTTP-контракты и DTO для streaming configuration, sessions и jobs.
- `docs/streaming-runtime-design.md` - функция-за-функцией разложенная streaming runtime architecture.
- `docs/streaming-ui-contract.md` - точный UI-контракт для streaming configuration и test flows.
- `docs/protocol-capability-matrix.md` - capability matrix по всем protocol families и execution modes.
- `docs/rust-design.md` - правила распределения поведения в Rust.
- `docs/development-rules.md` - правила разработки и workflow.
- `docs/rust-code-rules.md` - Rust-specific coding rules.
+7 -4
View File
@@ -2,14 +2,14 @@
## Current
### `feat/full-protocol-platform-architecture`
### `feat/streaming-detailed-specs`
Status: completed
DoD:
- Product scope covers REST, GraphQL, gRPC, WebSocket and SOAP
- Execution model is documented independently from protocol families
- Core docs and protocol docs are synchronized around full protocol platform scope
- Streaming API, runtime, UI and capability docs exist as separate detailed specs
- Function-level responsibilities are documented
- Field-level UI contract and validation rules are documented
## Next
@@ -30,6 +30,9 @@ DoD:
- `feat/soap-adapter-foundation`
- `feat/streaming-ui-config`
- `feat/streaming-e2e`
- `feat/websocket-upstream-adapter`
- `feat/soap-architecture-and-core-model`
- `feat/soap-adapter-foundation`
- `feat/auth-profile-secret-resolution`
- `feat/runtime-upstream-auth`
- `feat/secrets-ui`
+8
View File
@@ -4,6 +4,10 @@
Этот документ фиксирует целевые HTTP-контракты административного API, через которое UI управляет workspace, operations, agents, platform access и observability.
Для потоковой модели детальные HTTP DTO вынесены отдельно в:
- `docs/streaming-admin-api.md`
## 2. Общие правила API
- все payload по умолчанию в `JSON`;
@@ -205,6 +209,10 @@
- gRPC descriptor upload и discovery.
- upstream auth selector;
- quick-create secret / auth profile modal.
- execution mode selector;
- streaming config blocks;
- stream test-runs;
- tool family preview.
Детальные DTO и response shapes для экранов `Operations` и `Wizard` зафиксированы отдельно в:
+12
View File
@@ -175,3 +175,15 @@ DoD:
- runtime умеет строить SOAP envelopes и нормализовать SOAP Faults;
- operator может выбрать service, port и operation;
- test-run, publish и observability работают так же, как для остальных протоколов.
## 15. Этап 14. Detailed streaming specs
Цель:
- довести streaming-docs до function-level и field-level design спецификации.
DoD:
- есть отдельные docs для streaming admin-api, runtime, UI и capability matrix;
- protocol docs не противоречат общей execution model;
- roadmap и `TASKS.md` синхронизированы с full-detail architecture.
+123
View File
@@ -0,0 +1,123 @@
# Protocol Capability Matrix
## 1. Назначение документа
Этот документ фиксирует capability matrix по всем protocol families и execution modes.
Он нужен как source of truth для:
- UI availability rules;
- admin-api validation;
- runtime dispatch;
- roadmap planning.
## 2. Matrix by protocol and execution mode
| Protocol | Unary | Window | Session | Async Job | Notes |
| --- | --- | --- | --- | --- | --- |
| REST | Yes | Yes | Yes | Yes | window/session используют SSE или bounded polling |
| GraphQL | Yes | No | No | Limited | async job только как явная status/result workflow model |
| gRPC | Yes | Yes | Yes | Yes | только unary и server-streaming |
| WebSocket | No | Yes | Yes | Yes | upstream-only adapter |
| SOAP | Yes | Limited | No | Yes | request-response first, async через separate workflow contract |
## 3. Matrix by protocol and transport behavior
| Protocol | Request/Response | Server Stream | Stateful Session |
| --- | --- | --- | --- |
| REST | Yes | Yes | Limited |
| GraphQL | Yes | No | No |
| gRPC | Yes | Yes | Yes |
| WebSocket | No | Yes | Yes |
| SOAP | Yes | Limited | No |
## 4. Matrix by protocol and artifact requirements
| Protocol | Sample JSON | Descriptor | WSDL/XSD | Query Template | Subscribe Template |
| --- | --- | --- | --- | --- | --- |
| REST | Optional | No | No | No | Optional |
| GraphQL | Optional | No | No | Yes | No |
| gRPC | Optional | Yes | No | No | No |
| WebSocket | Optional | No | No | No | Yes |
| SOAP | Optional | No | Yes | No | No |
## 5. Matrix by protocol and auth support
| Protocol | None | Bearer | Basic | API Key Header | API Key Query | WS-Security |
| --- | --- | --- | --- | --- | --- | --- |
| REST | Yes | Yes | Yes | Yes | Yes | No |
| GraphQL | Yes | Yes | Yes | Yes | Limited | No |
| gRPC | Yes | Yes | Yes | Limited | No | No |
| WebSocket | Yes | Yes | Yes | Yes | Limited | No |
| SOAP | Yes | Yes | Yes | Limited | Limited | Future |
## 6. Matrix by protocol and UI blocks
| UI Block | REST | GraphQL | gRPC | WebSocket | SOAP |
| --- | --- | --- | --- | --- | --- |
| Endpoint URL | Yes | Yes | No | Yes | Optional |
| Method selector | Yes | No | No | No | No |
| Query template | No | Yes | No | No | No |
| Descriptor upload | No | No | Yes | No | No |
| WSDL upload | No | No | No | No | Yes |
| Subscribe template | Optional | No | No | Yes | No |
| Subprotocol list | No | No | No | Yes | No |
| SOAP headers | No | No | No | No | Yes |
| Stream kind selector | Optional | No | Yes | Yes | Limited |
## 7. Validation rules matrix
## 7.1. Unsupported combinations
- `GraphQL + Window`
- `GraphQL + Session`
- `WebSocket + Unary`
- `SOAP + Session`
- `gRPC + Session` для non-server-streaming method
- `REST + Server Stream` без stream-capable target model
## 7.2. Conditionally supported combinations
- `GraphQL + Async Job`
Требует отдельного status/result workflow contract.
- `SOAP + Window`
Допускается только для polling-style workflow, а не для native stream.
- `SOAP + Async Job`
Требует отдельной operation family для status/result.
## 8. Product-wave grouping
### Wave 1
- REST
- GraphQL query/mutation
- gRPC unary
- Streamable HTTP downstream
- Window/session/job core model
### Wave 2
- REST SSE
- gRPC server-streaming
- session/job tool families
- streaming UI
### Wave 3
- WebSocket upstream adapter
- richer streaming observability
### Wave 4
- SOAP foundation
- WSDL/XSD tooling
- SOAP UI flow
### Wave 5
- GraphQL subscriptions
- gRPC client-streaming
- gRPC bidi
- advanced enterprise security stacks
+607
View File
@@ -0,0 +1,607 @@
# 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}/stream-test-runs`
Назначение:
- выполнить `window`, `session` или `async_job` test-run для draft version;
- показать оператору runtime behavior до publish.
Тело:
```json
{
"version": 4,
"input": {
"service": "billing",
"level": "error"
},
"test_mode": "window",
"overrides": {
"streaming": {
"window_duration_ms": 3000,
"max_items": 50
}
}
}
```
Успех для `window`:
```json
{
"run_id": "strun_01j0test",
"mode": "window",
"status": "completed",
"window_complete": true,
"truncated": false,
"has_more": false,
"summary": {},
"items": [],
"cursor": null,
"duration_ms": 2871
}
```
Успех для `session`:
```json
{
"run_id": "strun_01j0test",
"mode": "session",
"status": "running",
"session": {
"session_id": "sess_01j0stream",
"expires_at": "2026-04-06T12:05:00Z",
"poll_after_ms": 2000
},
"preview": {
"summary": {},
"items": []
}
}
```
Успех для `async_job`:
```json
{
"run_id": "strun_01j0test",
"mode": "async_job",
"status": "running",
"job": {
"job_id": "job_01j0deploy",
"status": "running",
"progress": {
"pct": 12
}
}
}
```
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/stream-test-runs/{run_id}/poll`
Назначение:
- продолжить session-oriented test-run.
Тело:
```json
{
"session_id": "sess_01j0stream"
}
```
Ответ:
```json
{
"run_id": "strun_01j0test",
"mode": "session",
"status": "running",
"window_complete": false,
"truncated": false,
"has_more": true,
"summary": {},
"items": [],
"cursor": "next_cursor"
}
```
### `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/stream-test-runs/{run_id}/stop`
Назначение:
- остановить test session.
### `GET /api/admin/workspaces/{workspace_id}/operations/{operation_id}/stream-test-runs/{run_id}/result`
Назначение:
- получить финальный результат async-job test-run.
## 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.
+580
View File
@@ -0,0 +1,580 @@
# 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.
+434
View File
@@ -0,0 +1,434 @@
# 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`
## 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`