Add architecture package and application skeleton

This commit is contained in:
2026-07-03 21:09:47 +03:00
parent 7d6cc1c83e
commit ce2b263e52
47 changed files with 2377 additions and 53 deletions
+65
View File
@@ -0,0 +1,65 @@
# ADR 001: Runtime Stack
## Status
Accepted
## Context
AI Orchestrator должен быть:
- независимым от Local LLM Platform;
- пригодным для долгоживущих task runtime;
- удобным для строгой типизации контрактов;
- удобным для async I/O: models, MCP, worker connections, event streams;
- запускаемым без Docker на локальной машине;
- переносимым на удаленное окружение, включая `docker-test`.
## Decision
Основной стек:
- язык: Python 3.13+;
- HTTP API: FastAPI;
- конфиги и схемы запроса/ответа: Pydantic v2;
- app settings: `pydantic-settings`;
- конфиги проекта: YAML;
- event streaming для UI: SSE как основной transport;
- worker transport: WebSocket;
- structured logging: JSON lines через стандартный logging layer и event envelopes;
- тесты: `pytest` + `pytest-asyncio`;
- runtime packaging: стандартный `pyproject.toml`.
## Why This Stack
Python хорошо подходит для orchestration-heavy систем, где важнее:
- строгое моделирование состояния;
- быстрая интеграция с внешними AI/MCP endpoint;
- асинхронный I/O;
- прозрачные схемы данных;
- простая локальная разработка без контейнеров.
FastAPI выбран как delivery adapter, а не как центр архитектуры.
Доменные модели и application services не должны зависеть от FastAPI.
## Consequences
Плюсы:
- быстрый путь к строгим контрактам;
- хорошая ergonomics для async adapters;
- удобный локальный запуск без Docker;
- понятный переход к PostgreSQL и production deployment.
Минусы:
- нужен дисциплинированный layering, чтобы не “утонуть” в framework-driven code;
- CPU-heavy задачи должны оставаться вне основного request loop.
## Non-Goals
- локальный Docker как обязательный dev path;
- тяжелая зависимость от конкретной ORM на уровне domain;
- framework-first архитектура.
+46
View File
@@ -0,0 +1,46 @@
# ADR 002: Storage And Persistence Model
## Status
Accepted
## Context
Проект не должен начинаться с чисто временного `in-memory` мышления, иначе потом придется переделывать:
- task lifecycle;
- event log;
- confirmations;
- worker session tracking;
- replay и audit.
## Decision
Хранилище проектируется как persistent-first:
- production target: PostgreSQL;
- local development fallback: SQLite без Docker;
- repository interfaces определяются в application/domain boundary;
- materialized current state хранится отдельно от append-only event log;
- критические переходы состояний должны логироваться как события.
## Data Model Principles
1. `tasks`, `task_nodes`, `confirmations`, `worker_sessions` хранят текущее состояние.
2. `task_events` хранит audit trail и feed для replay/debugging.
3. Вызовы моделей, MCP и worker сохраняются как отдельные invocation records.
4. Артефакты хранят metadata в БД, а payload может лежать во внешнем файловом хранилище.
## Consequences
Плюсы:
- можно строить UI progress и audit без догадок;
- проще реализовать replay/resume;
- нет боли миграции с “простых dict” на реальную БД.
Минусы:
- немного более сложный старт;
- нужно заранее аккуратно продумать схему.
+40
View File
@@ -0,0 +1,40 @@
# ADR 003: User Event Stream Transport
## Status
Accepted
## Context
UI требует поток событий по task execution:
- `task_started`
- `node_started`
- `node_completed`
- `confirmation_required`
- `task_completed`
- `task_failed`
В исходных документах упомянуты `SSE/WebSocket`, но как основной transport нужно выбрать один.
## Decision
Основной transport для пользовательского event stream: Server-Sent Events.
WebSocket не исключается, но считается вторичным adapter для будущих realtime-потребностей.
## Rationale
SSE проще для:
- однонаправленного server-to-client прогресса;
- проксирования;
- reconnect semantics;
- дебага и совместимости с обычными HTTP-инструментами.
WebSocket нужен не UI в первую очередь, а local worker transport.
## Consequences
`GET /tasks/{id}/events` фиксируется как SSE endpoint.
+33
View File
@@ -0,0 +1,33 @@
# ADR 004: Local Worker Transport
## Status
Accepted
## Context
Local Worker работает на машине пользователя и должен:
- сам инициировать соединение;
- не требовать входящего порта на пользовательском ПК;
- поддерживать прогресс, heartbeat и dispatch commands.
## Decision
Основной transport для worker gateway: outbound WebSocket session от worker к серверу.
## Required Semantics
- registration handshake;
- capability advertisement;
- heartbeat;
- command dispatch;
- progress events;
- result envelope;
- cancellation;
- reconnect with new session id.
## Consequences
Worker transport остается отдельным delivery/infrastructure adapter и не врастает в orchestration core.
+55
View File
@@ -0,0 +1,55 @@
# ADR 005: Policy Evaluation Model
## Status
Accepted
## Context
Ключевой принцип проекта: без hardcoded bans.
Система должна принимать решения через policy engine, а не через встроенные запреты по имени tool или по содержимому команды.
## Decision
Policy engine работает в 4 шага:
1. request/action нормализуется в `ActionDescriptor`;
2. descriptor классифицируется по `resource` и `risk_level`;
3. policy evaluator находит эффективное правило;
4. возвращается `PolicyDecision`.
## Core Types
`resource`:
- `filesystem`
- `shell`
- `sql`
- `mcp`
- `external_models`
- `desktop`
- `browser`
- `network`
- `cost`
- `system`
`risk_level`:
- `safe`
- `write`
- `destructive`
- `system`
- `cost`
`decision`:
- `allow`
- `confirm`
- `manual`
- `disabled_by_config`
## Important Rule
Policy engine не получает “tool name only” как источник истины.
Он должен опираться на action classification и metadata от tool/model/worker adapters.
+42
View File
@@ -0,0 +1,42 @@
# ADR 006: Event Taxonomy And Correlation
## Status
Accepted
## Context
Оркестратор должен быть отлаживаемым и воспроизводимым.
Для этого все значимые переходы должны иметь единый event model.
## Decision
Все события включают:
- `event_id`
- `event_type`
- `occurred_at`
- `task_id`
- `conversation_id` when available
- `node_id` when available
- `correlation_id`
- `causation_id`
- `payload`
## Event Families
1. Task lifecycle
2. Node lifecycle
3. Policy decisions
4. Confirmation lifecycle
5. Model invocation lifecycle
6. Tool invocation lifecycle
7. Worker session lifecycle
8. Worker command lifecycle
9. Finalizer/result lifecycle
10. System warnings/errors
## Consequences
UI, audit log, replay tooling и debugging должны читать одну и ту же taxonomy, а не разрозненные лог-сообщения.
+32
View File
@@ -0,0 +1,32 @@
# ADR 007: Model Router Fallback Semantics
## Status
Accepted
## Context
В проекте уже зафиксирована идея:
- сначала weak;
- затем retry weak;
- затем strong fallback;
- external models не запрещаются кодом, а регулируются конфигом и policy.
## Decision
Fallback pipeline:
1. slot resolution выбирает provider и model для requested slot;
2. weak model вызывается первой;
3. если ответ невалиден по output contract, выполняется ограниченный retry weak;
4. если weak исчерпан, router проверяет доступность strong;
5. если strong разрешен config+policy, выполняется strong fallback;
6. если strong недоступен, возвращается structured degraded result.
## Notes
- “невалиден” означает нарушение response schema, parser failure или явный quality rejection;
- fallback trail сохраняется в invocation log;
- внешняя strong model не вызывается, если `allow_external_models=false` или policy запрещает.
+112
View File
@@ -0,0 +1,112 @@
# Доменная модель
## Слои
### Domain
Чистые сущности, value objects, state machines, классификация рисков, события.
### Application
Use cases:
- create_task
- submit_chat_message
- plan_task
- execute_ready_nodes
- request_confirmation
- approve_confirmation
- reject_confirmation
- register_worker
- ingest_worker_result
### Infrastructure
- storage adapters
- config loader
- event publisher
- model providers
- MCP transport
- worker gateway
- artifact persistence
### Delivery
- HTTP API
- SSE task events
- worker WebSocket session endpoint
## Главные сущности
### ProjectConfig
Описывает:
- model slots
- policy modes
- execution limits
- enabled MCP servers
- worker access rules
### Conversation
Контейнер пользовательского диалога и связанных задач.
### Task
Единица выполнения пользовательской цели.
Поля:
- `id`
- `project_id`
- `conversation_id`
- `goal`
- `inputs`
- `status`
- `requested_mode`
- `effective_mode`
- `created_at`
- `updated_at`
- `result_summary`
### ExecutionGraph
Набор node definitions и execution dependencies для конкретной task.
### Node
Типы:
- `planner`
- `model_call`
- `tool_call`
- `local_worker_call`
- `reviewer`
- `finalizer`
- `confirmation`
### ConfirmationRequest
Отдельная сущность для действий, требующих подтверждения.
### WorkerSession
Онлайн-сессия thin local worker.
### ModelInvocation
Record вызова model router/provider.
### ToolInvocation
Record вызова MCP tool или worker command.
### Artifact
Материализованный результат: patch, file diff, report, log bundle.
### Event
Audit и UI-событие в единой taxonomy.
+66
View File
@@ -0,0 +1,66 @@
# State Machines
## TaskStatus
```text
created
-> planned
-> running
-> waiting_confirmation
-> waiting_manual
-> completed
-> failed
-> cancelled
```
Правила:
- `created -> planned`: planner graph создан;
- `planned -> running`: есть готовые к исполнению nodes;
- `running -> waiting_confirmation`: execution остановлен на pending approval;
- `running -> waiting_manual`: policy/manual gate остановил автостарт;
- `running -> completed`: finalizer сформировал итог;
- `running -> failed`: unrecoverable error;
- `waiting_confirmation -> running`: approval получен;
- `waiting_manual -> running`: пользователь вручную продолжил выполнение.
## NodeStatus
```text
pending
-> ready
-> running
-> waiting_confirmation
-> completed
-> failed
-> skipped
-> cancelled
```
## ConfirmationStatus
```text
pending
-> approved
-> rejected
-> expired
-> cancelled
```
## WorkerSessionStatus
```text
connecting
-> online
-> busy
-> stale
-> disconnected
```
## Retry Principles
- retry выполняется только для явно retryable failures;
- retry history фиксируется в node attempts и event log;
- confirmation-required state не считается failure;
- idempotency must be explicit for side-effecting nodes.
@@ -0,0 +1,57 @@
# Internal Interfaces
## Orchestrator Application Ports
### TaskRepository
- create task
- update task
- get task by id
- list active tasks
### GraphRepository
- save graph
- get graph
- update node state
- list ready nodes
### ConfirmationRepository
- create confirmation
- get confirmation
- resolve confirmation
### WorkerRepository
- register session
- update heartbeat
- assign command
- complete command
### EventStore
- append event
- list events by task
### PolicyEvaluator
- evaluate action descriptor against project policy
### ModelRouter
- execute model request and return structured invocation result
### ToolGateway
- call MCP tool and return normalized result
### WorkerGateway
- dispatch command to worker and receive normalized result
## Design Rule
Application services зависят только от этих портов.
Ни один use case не должен напрямую импортировать HTTP handlers, DB session objects или конкретный MCP/WebSocket client.
+34
View File
@@ -0,0 +1,34 @@
# Error Model
## Error Families
### ValidationError
Некорректный вход, schema mismatch, invalid command envelope.
### PolicyError
Действие запрещено текущей конфигурацией или требует manual/confirm остановки.
### RetryableInfrastructureError
Временная ошибка транспорта, timeout, transient upstream failure.
### NonRetryableInfrastructureError
Постоянная ошибка конфигурации, unsupported capability, broken contract.
### ExecutionError
Ошибка бизнес-исполнения конкретного node.
### CancellationError
Task или node остановлены по explicit cancel.
## User-Facing Behavior
- validation и policy ошибки должны быть ясными и краткими;
- infra ошибки должны сохранять technical details в logs/events;
- task итог должен различать `failed` и `waiting for action`.
+74
View File
@@ -0,0 +1,74 @@
# Execution Model
## Базовый цикл
1. Пользователь создает `Task`.
2. Planner materializes `ExecutionGraph`.
3. Graph engine отмечает `ready` узлы.
4. Orchestrator выбирает runner для каждого ready node.
5. Перед side-effecting action выполняется policy evaluation.
6. Если нужен `confirm`, создается `ConfirmationRequest` и graph останавливается.
7. Если action разрешен, runner выполняет node.
8. Node результат сохраняется как output + event trail + optional artifacts.
9. Reviewer может валидировать промежуточный результат.
10. Finalizer формирует user-facing result и cards.
## Node Families
### Planner
Создает или пересобирает graph. Не выполняет side effects.
### Model Call
Использует `ModelRouter`.
Может инициировать fallback, но только внутри router contract.
### Tool Call
Использует `ToolGateway` для MCP.
### Local Worker Call
Использует `WorkerGateway` для thin executor.
### Reviewer
Системный шаг quality gate:
- schema validation
- semantic validation
- retry recommendation
- escalate to strong model
### Finalizer
Преобразует execution result в user result:
- message text
- cards
- artifacts metadata
- summary
## Execution Rules
- workers не создают новые workers;
- model/router adapters не меняют graph напрямую;
- только orchestrator меняет task/node state;
- side effects всегда проходят через policy decision;
- event log пишется на каждом значимом переходе.
## Manual And Resume
`manual` означает, что orchestrator не стартует следующий шаг автоматически.
Task остается в `waiting_manual` до явного resume action.
## Replay
Replay не означает повтор side effects автоматически.
Replay должен уметь:
- восстанавливать graph state из persisted state;
- переиздавать progress view;
- запускать retry только для разрешенных retryable nodes.
+60
View File
@@ -0,0 +1,60 @@
# Execution Backlog
## Package A: Architecture Freeze
- [x] runtime ADR
- [x] storage ADR
- [x] event stream ADR
- [x] worker transport ADR
- [x] policy evaluation ADR
- [x] event taxonomy ADR
- [x] model fallback ADR
- [x] domain model
- [x] state machines
- [x] storage schema draft
- [x] internal interfaces
- [x] error model
- [x] execution model
## Package B: Core Hardening
- [ ] graph scheduler service
- [ ] node runner abstraction
- [ ] reviewer contract
- [ ] finalizer contract
- [ ] resume/cancel use cases
- [ ] idempotency policy
- [ ] retry policy matrix
## Package C: Persistence
- [ ] SQLAlchemy models
- [ ] repositories for PostgreSQL/SQLite
- [ ] migrations
- [ ] artifact metadata persistence
- [ ] event store queries with pagination
## Package D: Integrations
- [ ] model router providers
- [ ] MCP transport adapter
- [ ] worker WebSocket gateway
- [ ] heartbeat monitor
- [ ] capability-aware dispatch
## Package E: Delivery
- [ ] typed worker registration schema
- [ ] task event DTO normalization
- [ ] confirmation cards
- [ ] progress cards
- [ ] artifact cards
- [ ] error cards
## Package F: Validation
- [ ] contract tests
- [ ] scenario tests
- [ ] smoke suite
- [ ] static checks in CI
+21 -1
View File
@@ -59,7 +59,9 @@
## GET /tasks/{task_id}/events
SSE/WebSocket stream событий:
Primary transport: SSE stream событий.
WebSocket может быть добавлен как secondary adapter, но contract-first путь для UI: SSE.
```json
{
@@ -87,6 +89,24 @@ SSE/WebSocket stream событий:
}
```
## GET /workers
Список известных worker sessions.
```json
{
"workers": [
{
"session_id": "wrk_1",
"worker_id": "worker_home_pc",
"name": "Home PC",
"status": "online",
"capabilities": ["file.read", "command.run"]
}
]
}
```
## POST /workers/register
Local worker регистрируется на сервере.
+158
View File
@@ -0,0 +1,158 @@
# Persistent Storage Schema Draft
## Database Target
- production: PostgreSQL
- local development: SQLite
## Tables
### projects
- `project_id` pk
- `name`
- `config_blob`
- `created_at`
- `updated_at`
### conversations
- `conversation_id` pk
- `project_id`
- `title`
- `created_at`
- `updated_at`
### messages
- `message_id` pk
- `conversation_id`
- `role`
- `content`
- `attachments_json`
- `created_at`
### tasks
- `task_id` pk
- `project_id`
- `conversation_id`
- `goal`
- `inputs_json`
- `status`
- `requested_mode`
- `effective_mode`
- `current_node_id`
- `result_summary_json`
- `created_at`
- `updated_at`
### task_graphs
- `task_id` pk
- `graph_version`
- `graph_metadata_json`
- `created_at`
### task_nodes
- `node_id` pk
- `task_id`
- `node_type`
- `status`
- `input_json`
- `output_json`
- `dependencies_json`
- `assigned_runner`
- `attempts`
- `retryable`
- `timeout_ms`
- `created_at`
- `updated_at`
### task_events
- `event_id` pk
- `task_id`
- `conversation_id`
- `node_id`
- `event_type`
- `correlation_id`
- `causation_id`
- `payload_json`
- `occurred_at`
### confirmations
- `confirmation_id` pk
- `task_id`
- `node_id`
- `status`
- `scope`
- `decision_json`
- `preview_json`
- `comment`
- `created_at`
- `resolved_at`
### worker_sessions
- `session_id` pk
- `worker_id`
- `name`
- `machine`
- `os`
- `version`
- `status`
- `capabilities_json`
- `last_heartbeat_at`
- `current_task_id`
- `connected_at`
- `disconnected_at`
### model_invocations
- `invocation_id` pk
- `task_id`
- `node_id`
- `slot`
- `provider`
- `model`
- `status`
- `request_json`
- `response_json`
- `usage_json`
- `fallback_from_invocation_id`
- `created_at`
### tool_invocations
- `invocation_id` pk
- `task_id`
- `node_id`
- `source_type`
- `source_id`
- `tool_name`
- `status`
- `request_json`
- `response_json`
- `created_at`
### artifacts
- `artifact_id` pk
- `task_id`
- `node_id`
- `artifact_type`
- `storage_uri`
- `metadata_json`
- `created_at`
## Required Indexes
- `tasks(status, updated_at)`
- `task_nodes(task_id, status)`
- `task_events(task_id, occurred_at)`
- `confirmations(status, created_at)`
- `worker_sessions(status, last_heartbeat_at)`
+36
View File
@@ -0,0 +1,36 @@
# Testing Strategy
## Layers
### Unit Tests
- state transitions
- policy evaluation
- graph readiness
- fallback logic
### Contract Tests
- API schemas
- worker envelopes
- MCP result normalization
- model router output contracts
### Integration Tests
- repository implementations
- event streaming
- config loader
- storage adapters
### Scenario Tests
- create task -> plan -> execute -> finalize
- confirm flow
- weak retry then strong fallback
- worker result ingestion
### Smoke Tests
Обязательный список зафиксирован в [tests/smoke/SMOKE_TESTS.md](/Z:/codex/ai_orchestrator/tests/smoke/SMOKE_TESTS.md).