# 14. Внутренности ядра

⚫ Документ для тех, кто пишет или меняет сам код ядра. Полная спецификация —
в `SPEC.md` (англ., источник истины); здесь — краткая карта. Семантика — из
исходников `agent_os_core`.

---

## 14.1 Модель

Ядро — это **один async-рантайм (Tokio)** с событийным циклом, который:

1. хранит **таблицу процессов** (`DashMap<Pid, AgentProcess>`);
2. каждый тик зовёт **планировщик** (`schedule() → ScheduleDecision`);
3. диспатчит **ходы** (`run_turn(pid)`), вызывая провайдера и выполняя цикл
   tool-call'ов;
4. **ограничивает ресурсы** (бюджеты, группы, лимит конкурентности) до диспатча;
5. маршрутизирует **IPC**;
6. посредничает в **каждом** tool-вызове;
7. эмитит **события** слушателям;
8. управляет **сессиями** (`SessionRegistry`).

Ядро держит опциональные сервисные ручки, подключаемые один раз при загрузке
хостом (`message_store`, `state_store`, `cron_service`, `workflow_service`,
`provider`, `pricing`) — если ручка не подключена, соответствующие syscall'ы
отвечают «не настроено».

Цикл загрузки:

```
loop {
    decision = schedule()
    match decision {
        Run(pid)       → run_turn(pid)
        Idle           → sleep(50ms)
        AtConcurrencyLimit → sleep(50ms)
        Shutdown       → break
    }
}
```

---

## 14.2 Основные абстракции

| Понятие ОС | Эквивалент | Модуль |
|---|---|---|
| Процесс | `AgentProcess` — PID, машина состояний, контекст, инструменты, бюджет | `process.rs` |
| Ядро | `Kernel` — событийный цикл | `kernel.rs` |
| CPU | `InferenceProvider` — подключаемый LLM | `provider.rs` |
| RAM | `ContextWindow` — память с вытеснением | `context.rs` |
| Устройство I/O | `Tool` | `tool.rs` |
| cgroups/ulimits | `TokenBudget` / `BudgetGroup` | `budget.rs` |
| Системный вызов | `Syscall` | `syscall.rs` |
| Сигнал | `Signal` | `ipc.rs` |
| fork() | `fork()` — COW-контекст, наследование группы | `process.rs` |
| Таблица процессов | `DashMap<Pid, AgentProcess>` | `kernel.rs` |
| Драйвер | `ToolHandler` | `tool.rs` |

### Машина состояний процесса

```
spawn → Created → (init) → Ready ⇄ Running → (exit) → Terminated
                              │
                              └→ Blocked{reason} → (unblock) → Ready
```

- **Created** — выделен, не инициализирован.
- **Ready** — ждёт планировщика (`is_runnable()`).
- **Running** — потребляет инференс.
- **Blocked { reason }** — ждёт внешнее событие (tool-результат, IPC, ввод).
- **Terminated { exit_code }** — завершён (0) или убит (≠0).

### Ход и цикл tool-call'ов

1. Ядро выбирает процесс P.
2. Отправляет контекст P + последние tool-результаты провайдеру.
3. Провайдер стримит токены.
4. Если LLM просит tool-call, ядро **ставит стрим на паузу**, **валидирует**
   вызов, **выполняет** обработчик (с дедлайном), **добавляет** результат как
   сообщение `tool` и **возобновляет** инференс.
5. Ход завершается, когда агент yield'ится, блокируется, истекает квант или
   исчерпан бюджет.

Конкурентность метрится `Semaphore` только вокруг `provider.stream` — tool-вызовы
и хуки идут без пермита, поэтому медленный инструмент не «голодает» другие сессии.

### Контекстное окно

`ContextWindow { max_tokens, messages, eviction, summary }`. Политики вытеснения:
`Fifo` (дроп старых), `SummaryFirst { keep }` (свернуть старые в summary, по
умолчанию keep=8), `SlidingWindow { n }`. Вытеснение чистит и осиротевшие
tool-результаты, чей родительский assistant-сообщение удалён.

### Бюджеты

`TokenBudget { max_per_turn, bucket: TokenBucket, max_total, … }`.
`TokenBucket` — классический leaky bucket (`capacity` + `refill_rate`). Группа
`BudgetGroup` добавляет два опциональных слоя: **per-user** (под-ведро на
`user_id`) и **per-session**. Проверка до диспатча: **группа → per-user →
per-session** (`can_consume_for`); исчерпанный слой — `BudgetLevel::{Group,User,Session}`.

### IPC и syscall'ы

`MessagePayload`: `Text`, `Json`, `Signal` (Terminate/Pause/Resume/Interrupt),
`SpawnRequest`, `SpawnResult`.

Syscall'ы: `Spawn`, `Fork`, `Kill`, `Yield`, `Send`/`Recv`, `ToolCall`,
`SetState`/`GetState`/`DeleteState`, `Checkpoint`/`Restore`.

### Хуки

`HookHandler` с точками `before_user_message` (transform/inject/suppress/reply/
notice), `after_turn` (пост-ходовое notice), `after_loop`. Плюс `merge_user`
(слияние идентичностей), `memory_inspect` (инспекция), `apply_feedback`
(like/dislike). `HookOutcome { inject, replace_message, reply, notice, suppress }`.

---

## 14.3 Планировщик

`SchedulingPolicy`: `RoundRobin` (по умолч.), `PriorityPreemptive`,
`FairShare`, `DeadlineDriven`. `Scheduler { policy, time_slice, max_concurrent }`.
`ScheduleDecision`: `Run(pid) | Idle | AtConcurrencyLimit | Shutdown`.

---

## 14.4 Провайдер инференса

```rust
trait InferenceProvider {
    fn provider_type(&self) -> &str;
    async fn stream(&self, request) -> Result<Box<dyn Stream<Item=Result<InferenceEvent, InferenceError>>>>;
}
enum InferenceEvent { Token(String), ToolCall(ToolCallRequest), Done(InferenceStats) }
```

Конкретная реализация — `OpenAiProvider` (reqwest + SSE). `Pricing` оценивает
стоимость из статистики.

---

## 14.5 Подсистемы хранения

| Слой | Где | Источник истины для |
|---|---|---|
| Текстовые логи (tracing) | stdout → `agent_os.log` | операционный просмотр |
| Event store (`EventDb`) | `logs/events.db` | аудит (одна строка на событие) |
| Message store | `logs/messages.db` | транскрипты + FAQ-кэш, полнотекстовый поиск |
| JSONL-трейсы | `logs/process-{pid}.jsonl` | сырой поток событий процесса |
| State store | `logs/state.db` | scoped key-value (session/user/agent) |
| Checkpoints | `CheckpointStore` | восстановление/миграция |

---

## 14.6 События и слушатели

Ядро эмитит типизированные `ProcessEvent` через шину: `TurnStart`, `Token`,
`ToolCall`, `ToolResult`, `ToolProgress`, `TurnEnd`, `StateChange`, `Error`,
`Spawned`, `Terminated`, `BudgetConsumed`, `BudgetExhausted`, `RateLimited`,
`ScheduleBlocked`, события жизненного цикла сессий, `Cost`, шаги воркфлоу.
Слушатели реализуют `ProcessListener` (все методы no-op по умолчанию).

---

## 14.7 Загрузка

1. Хост грузит конфиг и строит `Kernel`.
2. `ToolRegistry` регистрирует встроенные и пользовательские инструменты;
   `HookRegistry` — хуки.
3. `InferenceProvider` подключается к LLM.
4. Подключаются сервисные ручки (`message_store`, `state_store`, `cron_service`,
   `workflow_service`, `pricing`).
5. Грузятся шаблоны агентов (встроенные + YAML).
6. Bootstrap-агенты спавнятся (или лениво по первому запросу сессии).
7. Стартует цикл планировщика.
8. Хост слушает внешние запросы (HTTP + SSE).

---

## 14.8 Дизайн-решения

1. **Кооперативная многозадачность по умолчанию; вытеснение опционально.**
2. **`spawn` и `fork`** — оба поддержаны; `fork` всегда наследует бюджетную группу.
3. **Учёт стоимости на уровне инструментов** — каждый `ToolResult` несёт `ToolCost`.
4. **I/O через ядро** — агенты никогда не зовут инструменты напрямую.
5. **Opt-in подсистемы** — при неподключении отвечают «не настроено», а не падают.

## 14.9 Не-цели

Мультитенантность (один инстанс = один тенант), распределённый планировщик,
fine-tuning, graph-воркфлоу в ядре (это серверный слой), real-time гарантии.

---

## 14.10 Карта исходников

| Забота | Модуль |
|---|---|
| Ядро, цикл хода | `agent_os_core/src/kernel.rs` |
| Процесс, spec, fork | `agent_os_core/src/process.rs` |
| Машина состояний | `agent_os_core/src/state.rs` |
| Контекст, вытеснение | `agent_os_core/src/context.rs` |
| Бюджеты, группы, стоимость | `agent_os_core/src/budget.rs` |
| Планировщик | `agent_os_core/src/scheduler.rs` |
| Провайдер (trait) | `agent_os_core/src/provider.rs` |
| OpenAI-провайдер | `agent_os_core/src/openai_provider.rs` |
| Инструменты | `agent_os_core/src/tool.rs` |
| Хуки | `agent_os_core/src/hook.rs`, `hooks/` |
| IPC, сигналы | `agent_os_core/src/ipc.rs` |
| Syscall'ы | `agent_os_core/src/syscall.rs` |
| State store | `agent_os_core/src/state_store.rs` |
| Message store | `agent_os_core/src/message_store.rs` |
| События, слушатели | `agent_os_core/src/event.rs`, `listener.rs` |
| Event DB | `agent_os_core/src/event_db.rs` |
| Чекпоинты | `agent_os_core/src/checkpoint.rs` |
| JSONL-логгер | `agent_os_core/src/jsonl_logger.rs` |
| Субагенты | `agent_os_core/src/subagent.rs` |
| Cron | `agent_os_core/src/cron.rs` |
| Воркфлоу | `agent_os_core/src/workflow.rs` |
| Прайсинг | `agent_os_core/src/pricing.rs` |
| Загрузчик конфига | `agent_os_core/src/config.rs` |
| Скриптовые рантаймы | `agent_os_core/src/script_engine/`, `js_runtime/` |

---

## 14.11 Сборка и тесты

Cargo-воркспейс из трёх крейтов:

| Крейт | Назначение |
|---|---|
| `agent_os_core` | ядро: процессы, планировщик, бюджеты, события, провайдер-абстракция, хуки, message store. Без HTTP и конкретного провайдера |
| `agent_os_tools` | реализации инструментов (скраперы, архив, RSS, PDF, JSON, скрипты) и встроенные |
| `agent_web_bot` | HTTP-сервер (axum), OpenAI-провайдер, виджет, админ-UI, прокси, Telegram-боты, загрузчик конфига |

```bash
cargo build                       # debug-сборка всех бинарников
cargo run --bin agent_web_bot     # запуск сервера (грузит config/server.yaml)

cargo test -p agent_os_core       # юнит-тесты ядра/инструментов/хуков
cargo test -p agent_web_bot       # тесты сервера, auth, proxy, login, sessions
cargo test -p agent_web_bot --lib # HTTP-слой (роутинг, auth, login, access-лог)
```

Виджет в `widget/` собирается автоматически `build.rs` у `agent_web_bot` (через
npm) — отдельный `npm run build` не нужен. Интеграционные тесты
`agent_web_bot/tests/` требуют живой ключ LLM и по умолчанию не запускаются.
