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

⚫ Документ для тех, кто пишет или меняет сам код ядра. Полная спецификация — в 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, provider, pricing и др.) — если ручка не подключена, соответствующие syscall'ы отвечают «не настроено».

Модульность. Фичи (cron, workflow, connectors, memory, model_router, каналы, …) вынесены из ядра в модули и подключаются как host-порты. Вместо типизированных полей cron_service/workflow_service/connector_service у Kernel теперь один нейтральный шов kernel::KernelServices, который хост заполняет из портов agent_os.Cron / agent_os.Workflow / agent_os.Connectors (kernel.services().set_*). Ядро не зависит ни от одной фичи; подробности — docs/27-core-modularization.md §5 и 32-building-a-module.

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

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

Ход и цикл 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), before_tool_call (rewrite args / deny / short-circuit), after_tool_result (redact/transform), before_inference (мутация запроса; deny → блокировка, response → синтетический ответ), before_retry (разрешить/запретить ретрай + backoff), before_syscall (фильтр syscall/IPC, deny), after_turn, after_assistant_message (output-guardrail), on_token (стриминговая модерация), before_context_evict (кастомная компакция), after_loop, on_spawn/on_terminate/on_error, on_session_created/on_session_closed, on_budget_threshold. Плюс merge_user (слияние идентичностей), memory_inspect (инспекция), apply_feedback (like/dislike).

Композиция: Hook.priority (выше — раньше), enabled, условия активации when { templates, agents, users, sessions }, global (каталог config/hooks/*.yaml). Каждый вызов проходит через Kernel::run_hook (catch_unwind + таймаут hook_secs) и учитывается в HookMetric на пару (hook, point) (GET /v1/hooks/metrics). 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 Провайдер инференса

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/team)
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 Карта исходников

Забота Модуль
Ядро, цикл хода crates/kernel/src/kernel.rs
Процесс, spec, fork crates/kernel/src/process.rs
Машина состояний crates/kernel/src/state.rs
Контекст, вытеснение crates/kernel/src/context.rs
Бюджеты, группы, стоимость crates/kernel/src/budget.rs
Планировщик crates/kernel/src/scheduler.rs
Провайдер (trait) crates/kernel/src/provider.rs
OpenAI-провайдер crates/kernel/src/openai_provider.rs
Инструменты crates/kernel/src/tool.rs
Хуки crates/kernel/src/hook.rs, hooks/
IPC, сигналы crates/kernel/src/ipc.rs
Syscall'ы crates/kernel/src/syscall.rs
State store crates/kernel/src/state_store.rs
Message store crates/kernel/src/message_store.rs
События, слушатели crates/kernel/src/event.rs, listener.rs
Event DB crates/kernel/src/event_db.rs
Чекпоинты crates/kernel/src/checkpoint.rs
JSONL-логгер crates/kernel/src/jsonl_logger.rs
Субагенты crates/kernel/src/subagent.rs
Cron crates/kernel/src/cron.rs
Воркфлоу crates/kernel/src/workflow.rs
Прайсинг crates/kernel/src/pricing.rs
Метрики (Prometheus /metrics) crates/kernel/src/metrics.rs
Идемпотентность сайд-эффектов crates/kernel/src/side_effect.rs
Durable-сессии (opt-in персистентность) crates/kernel/src/durable.rs
Durable pending (approvals/ввод/await_event) crates/kernel/src/pending.rs
Загрузчик конфига crates/kernel/src/config.rs
Скриптовые рантаймы crates/kernel/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-боты, загрузчик конфига. Бинарник — единый CLI agent-os
cargo build                       # debug-сборка всех бинарников
cargo run --bin agent-os -- serve # запуск сервера (грузит 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 не нужен. Интеграционные тесты crates/host/tests/ требуют живой ключ LLM и по умолчанию не запускаются.