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 запрещает.