3. Конфигурация сервера
🔵 Платформу настраивают два файла: config/server.yaml (ядро, провайдер,
логирование, auth, виджет) и config/budgets.yaml (бюджетные группы и
привязка шаблонов). Расписания — в config/cron.yaml, слежение за изменениями —
в config/monitors.yaml, воркфлоу — в config/workflows/. Секреты — только в
.env.
3.1 Источник конфига — локальная папка или git-репозиторий
Всё дерево конфига (server.yaml, agents/, web/, workflows/,
budgets.yaml, cron.yaml, monitors.yaml) грузится из одного корня. По
умолчанию это локальная ./config; вместо неё можно клонировать git-репозиторий,
чтобы конфиг версионировался и ревьюировался отдельно от бинарника.
Приоритет: CLI-флаг → переменная окружения → локальный ./config.
| CLI-флаг | Переменная | Значение по умолчанию | Что делает |
|---|---|---|---|
--config-repo <url> |
AGENT_OS_CONFIG_REPO |
— | клонировать конфиг из git (иначе — локальная папка) |
--config-ref <ref> |
AGENT_OS_CONFIG_REF |
main |
ветка / тег / коммит, на который фиксируется конфиг |
--config-dir <path> |
AGENT_OS_CONFIG_DIR |
./config |
локальная папка конфига (игнорируется в git-режиме) |
--config-poll <secs> |
AGENT_OS_CONFIG_POLL |
off | периодически git pull + hot-reload конфига |
AGENT_OS_CONFIG_REPO=https://github.com/org/agent-config \
AGENT_OS_CONFIG_REF=v1.2.0 \
./agent_web_bot
Репозиторий клонируется (shallow) в ~/.agent-os/configs/<repo>-<ref> и
фиксируется на разрешённом коммите; SHA коммита пишется в лог при старте и
виден на /health в поле config. Секреты в конфиг-репозитории не хранятся —
только ссылки на имена переменных из .env.
3.2 config/server.yaml
provider — LLM
provider:
base_url: "https://api.deepseek.com" # любой OpenAI-совместимый endpoint
model: "deepseek-v4-flash"
api_key: "" # опционально; предпочтительно .env
pricing: # оценка стоимости инференса
prompt_per_million: 0.14
cached_per_million: 0.014
completion_per_million: 0.28
| Поле | По умолчанию | Описание |
|---|---|---|
base_url |
https://api.deepseek.com |
базовый URL OpenAI-совместимого провайдера |
model |
deepseek-v4-flash |
имя модели |
api_key |
пусто | ключ; пустое значение → берётся из env |
pricing.prompt_per_million |
0.14 |
$ за 1M prompt-токенов |
pricing.cached_per_million |
0.014 |
$ за 1M кэшированных prompt-токенов |
pricing.completion_per_million |
0.28 |
$ за 1M completion-токенов |
Порядок выбора ключа: provider.api_key → AGENT_OS_API_KEY →
DEEPSEEK_API_KEY. Пусто везде → агенты отвечают симулированными ответами.
models — именованные модели
Дополнительные конфиги моделей: каждый становится отдельным провайдером со
своим base_url / api_key / model / pricing. Шаблон агента выбирает нужную
полем model: в своём agent.yaml. provider: выше — это дефолт (он же
регистрируется как "default").
models:
cheap:
base_url: "https://api.deepseek.com"
model: "deepseek-chat"
strong:
base_url: "https://api.openai.com/v1"
model: "gpt-4o"
api_key: ""
kernel — планировщик и сессии
kernel:
scheduler: round_robin
concurrency_limit: 3
live_reload: true
session_ttl_secs: 300
session_cleanup_interval_secs: 60
| Поле | По умолчанию | Описание |
|---|---|---|
scheduler |
round_robin |
политика планирования (сейчас реализован только round_robin) |
concurrency_limit |
3 |
максимум одновременно выполняющихся процессов |
live_reload |
true |
hot-reload config/agents/** и config/web/** |
session_ttl_secs |
300 |
максимум простоя сессии (сек), после которого она убивается |
session_cleanup_interval_secs |
60 |
как часто (сек) запускается чистильщик сессий |
logging — логи и хранилища
logging:
filter: "agent_os=debug"
jsonl_dir: "logs"
duckdb_path: "logs/events.db"
messages_db_path: "logs/messages.db"
messages_retention_days: 30
state_db_path: "logs/state.db"
temp_dir: "logs/temp"
access_db_path: "logs/access.db"
cron_db_path: "logs/cron.db"
user_db_path: "logs/users.db"
monitor_db_path: "logs/monitors.db"
workflow_db_path: "logs/workflows.db"
bench_db_path: "logs/bench.db"
| Поле | По умолчанию | Описание |
|---|---|---|
filter |
agent_os=debug |
фильтр уровня логирования (tracing) |
jsonl_dir |
logs |
папка JSONL-логов (process-*.jsonl, access.jsonl) |
duckdb_path |
logs/events.db |
событийное хранилище DuckDB (пустая строка = выкл) |
messages_db_path |
logs/messages.db |
общий message store: транскрипты + FAQ-кэш (пусто = выкл) |
messages_retention_days |
30 |
сколько дней хранить транскрипты до очистки |
state_db_path |
logs/state.db |
scoped state store (session / user / agent); пусто = выкл |
temp_dir |
logs/temp |
scratch-хранилище сессий для файлов-генераторов; file_tool читает оттуда (пусто = выкл) |
access_db_path |
logs/access.db |
DuckDB-лог HTTP-запросов (пусто = выкл) |
cron_db_path |
logs/cron.db |
cron: динамические задания + история запусков (пусто = динамические задания не переживают рестарт) |
user_db_path |
logs/users.db |
реестр канонических пользователей: канальные id → один user id (пусто = выкл) |
monitor_db_path |
logs/monitors.db |
курсоры change-мониторов (пусто = курсоры не персистятся) |
workflow_db_path |
logs/workflows.db |
история запусков воркфлоу (пусто = выкл) |
bench_db_path |
logs/bench.db |
история бенчмарков и снапшоты (пусто = история не пишется) |
auth — админ-API и web-логин
auth:
admin_token_env: "" # имя env-переменной с токенами (опционально)
admin_tokens: # карта имя → токен (или { token, templates })
admin: "<token>"
drom-op:
token: "<token>"
templates: [drom-agent]
users: # web-логин: логин → пароль (или { password, templates })
admin: "<password>"
drom-viewer:
password: "<password>"
templates: [drom-agent]
web_user_secret_env: "" # env с HMAC-секретом для токенов конечных пользователей
admin_tokens— картаимя → токен. Имя пишется в access-лог (для аудита), сам токен никогда не логируется. Значение — либо голый токен (полный доступ), либо объект{ token, templates }, ограничивающий принципала перечисленными шаблонами.admin_token_env(опционально) — имя env-переменной, чьё значение может быть списком через запятую /;/ перевод строки, каждый элементимя=токенлибо голый токен (имя выводится из отпечатка). Такие токены — всегда полный доступ.users— карталогин → парольдля страницы/login; выдаёт session-cookie для админ-UI (/sessions,/budgets). CookieHttpOnly, живёт 12 часов, имя пользователя пишется в access-лог. Значение — голый пароль или{ password, templates }.- Пустые карты + пустой env = auth выключен (админ-API открыт — только для dev).
- Auth настроен, но ни один токен/пользователь не разрешается → админ-API fails closed (401).
web_user_secret_env — имя env-переменной с HMAC-секретом для подписи токенов
идентичности конечных пользователей (POST /v1/user-ticket). Если пусто, сервер
сам генерирует и хранит секрет в data/web_user_secret — идентичность
подписывается HMAC по умолчанию. Подробности — в 08-http-api.
Админ-эндпоинты принимают либо Authorization: Bearer <токен>, либо cookie
agentos_session.
widget — встраиваемый виджет
widget:
default_model: "drom-agent" # агент по умолчанию
Единственная серверная настройка — default_model: агент, к которому виджет
обращается, когда модель не задана явно. Полный разбор виджета (встраивание,
порядок выбора модели, демо, визуальные блоки) — в §19.
proxy — ограничения HTTP-прокси
proxy:
allow_hosts: [] # пусто = любой публичный хост
/proxy и /proxy/content всегда блокируют приватные, loopback, link-local и
reserved-диапазоны (включая 169.254.169.254) на каждом редиректе.
allow_hosts дополнительно ограничивает по хосту (точное совпадение или
поддомен).
inbound — входящий webhook
inbound:
token_env: "" # env с bearer-токеном для POST /v1/inbound/:template (пусто = открыто, dev)
POST /v1/inbound/:template — внешние системы запускают один ход агента
синхронно. См. 08-http-api.
3.3 config/budgets.yaml
budget_groups:
- name: my-shared
refill_per_sec: 50
max_bucket: 50000
max_total: 5000000 # null/отсутствует = без лимита
per_user: # опционально
refill_per_sec: 20
max_bucket: 20000
max_total: 500000
per_session: # опционально
refill_per_sec: 30
max_bucket: 10000
max_total: 200000
agents:
- template: my-agent # перекрывает budget_group / budget из agent.yaml
group: my-shared
budget: # опционально
refill_per_sec: 10
max_bucket: 200
max_total: 1000
- Группы создаются сразу при старте (не лениво) и видны на
/budgets. agents:привязывает шаблон (поname) к группе и/или перекрывает его бюджет.- Перекрытия из
budgets.yamlвыигрывают у значений изagent.yaml. - Проверяются при каждом входе в тёрн сверху вниз: группа → per_user →
per_session. Исчерпанный уровень показывается сообщением из
budget_messages.*агента.
Поля бюджета
| Поле | Описание |
|---|---|
refill_per_sec |
пополнение ведра, токенов/сек |
max_bucket |
ёмкость ведра (burst) |
max_total |
жёсткий лимит за всю жизнь (отсутствует = без лимита) |
3.4 Запланированные задания (config/cron.yaml)
Cron запускает шаблон агента по расписанию. Задаются в двух местах, оба hot-reload'ятся:
- на агента — список
cron:вconfig/agents/<agent>/agent.yaml(templateпо умолчанию = сам агент); - глобально —
config/cron.yaml, где каждое задание явно называетtemplate:
jobs:
- name: morning-digest
template: rss
schedule: "0 0 9 * * *" # sec min hour dom month dow (UTC)
prompt: "Резюмируй сегодняшние новости."
notify: [{ type: log }]
Каждое задание задаёт ровно одно из schedule / interval_secs / oneshot_at
и доставляет результат в список notify-sink'ов (log, webhook, telegram,
messages_db, agent, email, workflow). История — в logs/cron.db,
эндпоинт GET /v1/cron. Полный справочник — 11-cron-jobs.
3.5 Change-мониторы (config/monitors.yaml)
Монитор — это pull-триггер: следит за внешним источником и запускает ход
агента только при появлении новых элементов (в отличие от cron, который
стреляет по расписанию независимо). Источник изменений подключаемый (сейчас —
rss).
monitors:
- name: news-watch
source:
type: rss
url: "https://lenta.ru/rss"
template: rss-agent
prompt: "Кратко резюмируй эти новые статьи:\n{{items}}"
notify: [{ type: telegram, chat_id: 123456 }]
poll_secs: 300
| Поле | Смысл |
|---|---|
name |
уникальный id (он же ключ курсора и сессия monitor:<name>) |
source.type |
источник изменений: rss |
source.url |
URL ленты |
template |
шаблон агента для запуска на новых элементах |
prompt |
шаблон промпта; {{items}} заменяется новыми элементами |
notify |
sink'и, куда раздаётся результат (те же типы, что у cron) |
poll_secs |
интервал опроса (по умолчанию 300) |
Монитор хранит курсор в logs/monitors.db: первый опрос только «догоняет»
(сохраняет курсор, ничего не запускает), дальше запускается только на элементах
новее курсора.
3.6 Переменные окружения
| Переменная | Назначение |
|---|---|
DEEPSEEK_API_KEY / AGENT_OS_API_KEY |
ключ LLM-провайдера |
AGENT_OS_BIND |
адрес привязки (по умолчанию 127.0.0.1:3000) |
AGENT_OS_TLS_CERT / AGENT_OS_TLS_KEY |
пути к PEM-сертификату и ключу для HTTPS |
AGENT_OS_ADMIN_TOKEN |
админ-токены: список через запятую, имя=токен (альтернатива auth.admin_tokens) |
AGENT_OS_BENCH_MODE |
1 = безлимитные бюджеты (для локального спавна бенчмарка) |
AGENT_OS_CONFIG_REPO / _REF / _DIR / _POLL |
источник конфига (см. §3.1) |
AGENT_OS_DISTRIB_DIR |
путь к папке дистрибутива (по умолчанию distrib) |
(на агента) имя из telegram.token_env |
токен Telegram-бота, названный в agent.yaml |
(на агента) имя из email.imap_password_env |
пароль IMAP для email-канала |
(на агента) имя из vk.token_env |
group access token VK-сообщества, названный в agent.yaml |
.env подхватывается автоматически при старте (dotenv). Он в .gitignore,
шаблон — .env.example.
3.7 Live reload
При kernel.live_reload: true (по умолчанию) сервер следит за config/:
config/agents/**— новые сессии получают новые инструкции; инструменты и хуки перерегистрируются и действуют со следующего вызова.config/web/**— markdown-сайт перерендеривается на лету.config/server.yaml— не применяется на лету; нужен рестарт.
3.8 Логирование HTTP-запросов
Каждый HTTP-запрос (метод, путь, статус, длительность, IP клиента, user-agent,
X-User-Id, имя админ-токена) пишется в logs/access.jsonl и logs/access.db
(оба отключаются пустой строкой в соответствующем поле logging). Значение
токена не логируется — только его имя или пометка invalid.