Конфиг — секциями (yaml/toml/json), можно несколько --config — поздние
сливаются поверх ранних; env-префикс EVA_ (см. Быстрый
старт). Обязательны только server, db и llm, остальное —
опционально с дефолтами. Полный аннотированный пример —
config.example.yaml. Длительности — humantime (5s, 1m, 7days,
1h 30m).
| поле | дефолт | что это |
server.listen | — | адрес API, напр. 127.0.0.1:8090 |
server.drain | 2m | сколько ждать идущие туры при остановке. Передеплой посреди тура иначе рвёт его на полуслове; по истечении срока туры сворачиваются штатной отменой, дописывающей частичный ответ |
db.path | — | путь к SQLite-файлу; создастся сам, миграции — на старте |
| поле | дефолт | что это |
provider | — | anthropic | openai (Chat Completions — llama-server/vLLM тоже он) | venice (Venice.ai, только картинки: generate и правка по source-картинке, открытые модели без вшитой цензуры; текстовых туров не обслуживает — ему место именованным апстримом при рисующей записи models, не основным) | mock (эхо, без ключа) |
model.general | — | основная модель |
model.fastest | не задана (general) | мгновенная модель декоративных реплик (комментарии в меню настроек поверхности, inline-ответы); лучше вовсе без reasoning |
model.smartest | не задана (general) | самая сильная модель — решения, где качество суждения важнее латентности и цены: консолидация памяти во сне |
model.advisor | не задана (советчика нет) | вторая, дешёвая модель поверх рабочего тура — см. Советчик. Не задана — цикл не запускается ни разу |
model.fallback | [] | кому передать тур, если модель отказала не по-транзиентному (упавший ключ на апстриме, снятая модель, кончившаяся квота); пробуются по порядку. Без цепочки такой отказ роняет тур вместе с уже сделанной работой |
api_key | — | generic-ключ активного провайдера; для openai необязателен (локальные серверы) |
base_url | у провайдера свой | override эндпоинта, напр. http://127.0.0.1:8080 |
proxy | не задан | прокси до LLM-эндпоинта (socks5h://… | http://…) — когда WAF провайдера блочит прямой IP хоста |
max_tokens | 8192 | потолок ответа |
max_tokens_guest | 2048 | потолок для туров НЕ-разрешённых пользователей (чужие в открытых чатах) |
max_tokens_uncapped | не задан | потолок uncapped-туров доверенных клиентов; не задан — openai-провайдеру max_tokens не шлётся вовсе, anthropic подставляет 32000 (Messages API требует поле) |
models | [] | дополнительные модели на выбор per-чат (GET /v1/models + PUT /v1/chats/{id}/model); применяются к турам Господина. Элемент — имя-строкой или { name, multimodal, image_output, jailbreak, description, effort, price_out, provider }: multimodal включает прямую передачу картинок, image_output — модель умеет отдавать картинки в ответе (тур просит их сам, image_generate спрятан), jailbreak — per-model стир против встроенной цензуры (часть кэшируемого промпта), description — для чего модель хороша (уезжает клиентам в descriptions и читается самой Евой при выборе исполнителя; по-английски), effort — уровень рассуждения по умолчанию для этой модели (off, low, mid, high), чтобы сильная и дорогая думала в полную силу, не поднимая уровень остальным, price_out — цена выходного токена в USD за миллион, из неё статистика считает деньги за рассуждения, context_window — жёсткий потолок контекста модели в токенах (счёт контекста меряет остаток и до него, ошибка «окно переполнено» пинит счёт в это число; уезжает клиентам в context_windows), provider — имя апстрима из providers, через который ходит эта модель |
providers | {} | именованные дополнительные апстримы: имя: { provider, api_key, base_url, proxy, reasoning, temperature, prompt_cache, structured_output } — поля значат то же, что одноимённые в llm. Модель из models выбирает свой полем provider, остальные ходят через основной; роли и model.fallback свободно смешивают модели разных апстримов. Один апстрим — один HTTP-клиент, сколько бы моделей через него ни ходило. У venice правка картинки уходит парной *-edit модели (qwen-image-2 → qwen-image-2-edit); имя, уже несущее «edit» (qwen-edit-uncensored), едет как есть — но тогда генерация с нуля этой записью откажет словами Venice |
reasoning | off | уровень рассуждения: off | low | mid | high. Старое булево читается как раньше (true — mid, false — off). средняя ступень значит «думай как обычно» и едет без глубины — ровно то, что уходило на провод при старом true. openai: поле OpenRouter + вырезание inline <think>; anthropic: расширенное мышление (off говорится вслух — думающая по умолчанию модель иначе думает всегда). Уровень тура сильнее: поле effort записи модели, ключевое слово в реплике, настройка чата, поле запроса |
structured_output | false | апстрим понимает структурированный ответ: response_format с json_schema уходит на провод там, где вызов просит схему (план сна, schema в одноразовом дополнении). По умолчанию выключено: часть шлюзов ломается на незнакомом поле (как с reasoning), а вызывающие всё равно разбирают текст с ретраем — без флага всё работает как раньше, просто чаще ретраится. Касается openai-провайдера; anthropic эмулирует схему вынужденным вызовом инструмента и флага не требует, mock отвечает валидным по схеме образцом |
magic_keywords | true | слово ultrathink целиком и вне кода в реплике Господина поднимает уровень рассуждения до верхнего на один ход; из текста оно не вырезается, инструкция доезжает до модели отдельной строкой состояния тура |
temperature | дефолт провайдера | температура сэмплинга |
prompt_cache | выключен | TTL кэша промпта: "5m" | "1h"; локальным серверам не включать |
prompt_cache_telegram | не задан | оверрайд для туров поверхности с якорём (телеграм): "off" | "5m" | "1h"; не задан — глобальный |
code_model | не задана | модель посильнее для code_task; не задана — инструмента нет |
image_model | первая с image_output | рисующая модель для image_generate; не задана и рисующих в models нет — инструмента нет |
summary_model | основная | дешёвая модель служебных саммари (компакция, названия чатов) |
max_turn_iterations | 16 | жёсткий потолок походов к провайдеру за один ход |
Каждая модель, на которую конфиг ссылается по имени — model.general,
model.fastest, model.smartest, model.advisor, model.fallback, code_model,
image_model, summary_model — обязана
быть в models (а image_model — ещё и нести image_output). Иначе ядро не стартует и называет поле с опечаткой.
Правило одно на весь конфиг, потому что список — это ещё и то, что видит
Господин в меню, из чего Ева
выбирает исполнителя и откуда модель получает свой jailbreak: не
перечисленная модель работает тише и хуже, а опечатка вскрывается отказом
провайдера посреди тура. Модели эмбеддингов (memory.embedding_model) сюда
не относятся — у них свой каталог (и ходят они всегда через основной
провайдер). Тем же стартовым правилом проверяются и ссылки provider у
записей models: имя, которого нет в providers, роняет ядро сразу, а не
туром не на том апстриме.
| поле | дефолт | что это |
dir | <каталог базы>/images | куда ложатся файлы картинок |
base_url | http://<server.listen> | из чего строится ссылка <base_url>/images/<id>; публичным клиентам сюда — адрес reverse-proxy, у которого /images/* открыт мимо токена (ключ доступа — неугадываемый uuid) |
keep | 30d | ретенция: старше — файл и запись сносятся (чистка на старте и раз в сутки); картинка ~1 МБ, без потолка чат молча заполняет диск |
| поле | дефолт | что это |
tool_result_keep | 6 | сколько последних сообщений держат тул-трафик целиком; старее — огрызок: и вывод, и длинные строки входа вызова (тело записанного файла, патч, скрипт), от которых остаётся пометка длины |
tool_result_keep_chars | 24000 | второй бюджет того же окна, в символах — и он строже: выхлоп ОДНОЙ итерации ложится одним сообщением, поэтому шесть сообщений значат то шесть последовательных вызовов, то восемь параллельных на каждой из шести итераций. Последнее сообщение свежо всегда, даже если толще бюджета; 0 — мерить только сообщениями |
reader_result_max_chars | 8000 | свой потолок ОКОННЫХ читателей (read_file, find_pattern, read_hex, history_search): их выхлоп нарезан по границам строк и сам говорит, как читать дальше, поэтому режется хвостом, а не серединой — и по более щедрой мерке |
tool_result_max_chars | 4000 | кап на один tool_result даже среди свежих; инструменты, которых зовут ради полного текста (skill, agent_inbox, memory_list, chat_note_read…), внутри окна не режутся вовсе, оконные читатели режутся по reader_result_max_chars |
past_tool_traffic | stub | что делать с тул-трафиком ЗАКРЫТЫХ ходов: keep — оставить как есть, stub — оставить вызовы и огрызки, но схлопнуть полезную нагрузку входа за границей хода (даже если живое окно её ещё не тронуло), drop — выбросить вовсе, парами. Полный текст всегда достаёт history_search, база не трогается |
turn_squeeze_percent | 50 | доля профильного порога компакции, после которой длинный тур поджимает СВОЙ трафик прямо на ходу: элизия гоняется один раз на входе, и сорокаитерационный ход иначе нёс весь свой выхлоп до переполнения окна провайдера. Тем же проходом вытесняются копии перечитанного внутри тура (тот же файл, та же выдача памяти) — у обоих одна цена, разрыв префикс-кэша, и платится она разом. Свежими остаются последние 4 сообщения, записи чтений внутри тура не отменяют; повторно — только на удвоенном весе, и проход, которому нечего схлопывать, молчит. Модель узнаёт строкой в [state], клиент — событием turn_squeezed, трасса — событием turn_squeeze. 0 выключает — вместе с вытеснением копий |
compact_after_tokens | 37500 | порог компакции доверенного окружения (личка), в токенах честного счёта: контекст тяжелее — старая часть сворачивается в резюме. Устаревший ключ compact_after_chars читается как символы ÷ 4 (warning на старте) |
compact_keep_tokens | 12500 | свежий хвост (в токенах), переживающий компакцию живьём; legacy-ключ compact_keep_chars — так же |
compact_scope | body_after_prefix | что меряет порог: body_after_prefix — разговор без кэшируемого префикса (персона, правила, схемы тулов — стабилен и дёшев), total — весь промпт. Жёсткий потолок модели (context_window записи llm.models) всегда считает всё |
compact_verbatim_percent | 15 | доля профильного порога на ДОСЛОВНЫЕ реплики Господина: при свёртке его самые свежие сообщения переживают её как есть, рядом с резюме, — формулировка задания дороже пересказа. Отбор от свежих к старым, первая не влезшая режется серединой; окно без его реплик сохранённое не стирает. 0 выключает |
pressure.notice | англ. текст | вторая ступень давления в [state]: «осталось N»; плейсхолдеры {used}, {limit}, {left} |
pressure.wrap_up | англ. текст | третья ступень: приглашение свернуться ДО компакции — один раз на окно, только когда компакция не сработает сама прямо сейчас; "" выключает |
pressure.just_folded | англ. текст | «история только что свернулась — запиши, что резюме размыло» |
pressure.wrap_up_reserve_tokens | 8000 | резерв третьей ступени: «сворачивайся» приходит, когда до ближайшей стены (порог компакции или потолок модели) меньше этого |
summary_max_chars | 6000 | потолок саммари; merge пишет факт-лист без бюджета, переросшее ужимается отдельным проходом до ~80% |
telegram.history_limit | 10 | нижняя граница окна живой истории телеграм-чатов В РЕПЛИКАХ ЛЮДЕЙ, не сообщениях (0 — без лимита); окно живёт в [limit, 2×limit) ходов ради кэша |
telegram.past_tool_traffic | drop | то же поле для чатов поверхностей, со своим дефолтом: собственный выхлоп по закрытым задачам там не нужен ни модели, ни читателям чата |
telegram.compact_after_tokens | 10000 | порог компакции чатов поверхностей (у чата задан surface: telegram, mtl) — ниже, компакция чаще |
telegram.compact_keep_tokens | 3750 | свежий хвост поверхностной компакции |
cron.compact_after_tokens | 3750 | порог компакции cron-туров — низкий: фоновой джобе не нужна вся история |
cron.compact_keep_tokens | 1500 | свежий хвост cron-компакции |
aggressive_folders | [] | папки, которые жмутся по cron-профилю (копят тяжёлый контент) |
pin_first_message_folders | [] | папки с закреплённым первым сообщением (например транскрипт) — оно не компактится |
project.root_markers | [".git", ".jj", "flake.nix"] | маркеры корня проекта для блока [project] (все AGENTS.md от корня до рабочего каталога): подъём от рабочего каталога останавливается на первом каталоге с любым из них; [] — подъём выключен, читается только сам каталог |
project.max_bytes | 16384 | ОБЩИЙ бюджет на все AGENTS.md разом, в байтах: не влезшее усекается с подписью, какой файл пострадал; 0 выключает сбор целиком |
project.memory_max_bytes | 8192 | свой бюджет памяти проекта (.eva/MEMORY.md, читается тем же проходом); 0 — файлы памяти не читаются |
client_context_chars | 32000 | потолок клиентского context из send_message, в символах: чужие байты не смеют забить окно; перерост усекается серединой с явной пометкой, 0 — без потолка |
| поле | дефолт | что это |
chats.ephemeral_ttl | 1day | столько молчания прощается временным чатам; молчащий уносится вместе со своими подагентами |
chats.reap_interval | 1m | как часто ходит жнец |
chats.problem_folder | problems | папка, куда Ева заводит чат на каждую свою проблему |
chats.max_agents | 4 | сколько подагентов чат держит живыми разом — предохранитель от веера |
chats.quiet_folders | ["youtube", "cron", "code"] | тихие полки: их плодит автоматика, и в GET /v1/chats без явного фильтра folder/project/surface их чаты не попадают; хвостовая * — префикс, без неё — точное имя (той же маской пользуется и сам фильтр folder: folder=mtl:* — все игровые полки разом). GET /v1/chats/folders отдаёт их как обычно |
cron.tick | 5s | разрешающая способность планировщика |
memory.top_k | 8 | сколько отскоренных воспоминаний вплетается в промпт |
memory.public_top_k | top_k / 2 (мин. 2) | потолок релевантных в чужом публичном туре; core — всегда, личное — никогда |
memory.recall_floor | 0.15 | нижняя граница выборки — ДОЛЯ от лучшего счёта в ней самой: top_k без порога добирает список до счёта, и запись, разделившая с запросом одно общее слово, занимает место наравне с попаданием. Порог относительный, потому что BM25 между запросами не нормирован; core идёт мимо скоринга и порогом не задевается. 0 выключает |
memory.half_life | 7days | полураспад свежести |
memory.prompt_budget | 8000 | потолок секции памяти в промпте, символов; core занимает не больше 60% его, остальное принадлежит выборке |
memory.embedding_model | не задана | модель эмбеддингов у активного провайдера (напр. baai/bge-m3); не задана — чистый BM25 |
Секция целиком необязательная: сон включён из коробки и безвреден на мелком
корпусе (min_memories не даст этапу памяти стартовать). Наверху — общее
ядро сна, работа ночи — в подсекциях этапов.
| поле | дефолт | что это |
enabled | true | выключить целиком: компонент не поднимается, тул и ручки отвечают отказом |
at | 00:00 | время суток (зона хоста), в которое пора спать, раз в сутки; пропущенную границу досыпает первым подходящим тиком |
tick | 5m | как часто компонент сверяет, не пора ли |
idle_for | 30m | не будить, пока идёт разговор: последнее сообщение должно быть старше, живых генераций — ноль; срок не сгорает, недождавшийся тик пробует на следующем |
dry_run | false | планы обоих этапов считаются и пишутся в журнал, но не применяются — режим первых недель |
| поле | дефолт | что это |
enabled | true | выключить только этап памяти; сон остальными этапами живёт |
model | не задана | оверрайд роли smartest только для этапа; цепочка: sleep.memory.model → llm.model.smartest → llm.model.general |
min_memories | 20 | корпус мельче — этап памяти пропускается (сон целиком не блокируется, если этапу tools есть что делать) |
max_ops | 40 | потолок правок памяти за один сон; лишние отбрасываются с отметкой в журнале |
max_forget | 8 | из них забываний — отдельным, более узким потолком |
keep_recent | 48h | моложе — не забываем и не переписываем: свежее ещё не устоялось |
archive_ttl | 30d | сколько забытое лежит в архиве до окончательного выноса |
cluster_jaccard | 0.35 | ребро графа кластеризации по лексике (Jaccard основ) |
cluster_cosine | 0.6 | ребро по семантике (косинус векторов одного пространства) |
max_cluster | 8 | кластер крупнее — режется на подкластеры по слабейшим рёбрам |
| поле | дефолт | что это |
enabled | true | выключить только этап tools; сон остальными этапами живёт |
model | не задана | оверрайд роли smartest только для этапа |
max_ops | 10 | потолок правок наборов за одну ночь |
Старых плоских ключей (sleep.model, sleep.max_ops, …) больше нет —
serde их молча проигнорирует, и этап памяти уедет на дефолты: при
обновлении секцию нужно переписать под подсекции (ломающее).
сон чата: набор инструментов по умолчанию
Отдельный от sleep компонент: свой у каждого чата, ленивый и фоновый,
туров не держит. Секция необязательная целиком.
| поле | дефолт | что это |
enabled | true | выключить целиком: компонент не поднимается, нуджи уходят в никуда, ручки отвечают отказом. Уже посчитанное курирование продолжает действовать — снять его можно только явно |
at | 00:00 | граница суток (зона хоста), после которой сну чата пора |
min_gap | 20h | защита от двойного сна за сутки: срок ставится не раньше, чем через это после пробуждения |
retry_after | 1h | на столько уезжает срок в момент захвата; им же закрываются дубли нуджей и падение посреди ночи |
max_parallel | 2 | сколько чатов спит одновременно |
dry_run | false | план в журнал без применения — первые недели держать true |
keep_days | 400 | ретеншн дневной статистики чатов; жнёт её гигиена глобального сна |
min_turns | 10 | меньше туров в статистике — данных нет, этап молча пропускается |
thin_turns | 10 | ниже — окно помечается thin, и на нём модели разрешено только расширять набор |
skip_folders | [agents, cron] | полки, чьи чаты не курируются: у подагентов и крон-джоб свой узкий whitelist и однообразные туры |
| поле | дефолт | что это |
enabled | true | выключить только этап; статистика копится и срок двигается по-прежнему |
model | не задана | оверрайд на все чаты; не задана — модель самого чата |
budget_percent | 10 | доля окна модели чата на схемы инструментов. Досягаемый набор влезает — этап не запускается вовсе: ни вызова модели, ни расхода. Отсюда же и то, что инструмент никогда не прячется «за молчание» |
max_hide_per_night | 8 | сколько видимых инструментов одна ночь вправе спрятать |
core | [memory, ask_questions, think_harder, notify_master, telegram] | обязательное ядро набора: курирование его не прячет. Имена тулов и групп регистрации, сверяются с реестром на старте |
блокнот модели по чату
Секция целиком необязательная: дефолты рассчитаны на то, чтобы её не писать.
| поле | дефолт | что это |
enabled | true | выключенный блокнот не регистрирует тулов, не идёт в промпт и не трогает базу |
inline_chars | 2000 | тела тяжелее — блокнот показывается индексом |
inline_back_chars | 1400 | возврат к дословному показу; ниже входного порога ради гистерезиса |
inline_max | 8 | то же по числу заметок |
inline_back_max | 6 | возврат по числу заметок |
index_max_chars | 4000 | потолок индекса: перерос — пора пересобирать, даже если тела лёгкие |
compact_after_chars | 20000 | порог пересборки по размеру тел |
compact_target_chars | 6000 | во столько символов просим уложить блокнот при пересборке |
max_note_chars | 2000 | потолок тела одной заметки; перебор — отказ «разбей на две» |
max_notes | 40 | порог пересборки по числу заметок |
pinned_max | 3 | сколько заметок можно закрепить |
pinned_chars | 2500 | суммарный бюджет закреплённых тел в промпте; ниже max_note_chars ставить нельзя — законная по размеру заметка перестанет закрепляться |
model | не задана | модель пересборки; не задана — модель самого чата |
советчик поверх рабочего тура
Секция необязательная и работает, только когда задана llm.model.advisor:
без роли советчика нет вовсе. Дефолты рассчитаны на то, чтобы секцию не
писать — назначил модель, и он уже не шумит.
| поле | дефолт | что это |
enabled | true | заткнуть советчика, не убирая роль модели |
every_iterations | 3 | цикл каждой N-й итерации рабочего тура |
max_steps | 3 | его собственных шагов за цикл (чтения инструментами — внутри счёта) |
max_notes | 2 | вклеенных заметок за тур; подавленные щитом не в счёт |
cooldown_cycles | 3 | сколько циклов молчать после вклеенной заметки |
delta_max_chars | 6000 | потолок дельты транскрипта на цикл; жертвуется середина |
timeout | 60s | не уложился — тур идёт дальше без него |
| поле | дефолт | что это |
tools.dir | не задан | каталог *.toml-деклараций внешних инструментов |
tools.on_demand | [] | имена тулов и групп, которых нет в списке по умолчанию: они видны только именем и назначением, а схему получают по tool_load. Для редкой работы, чьи схемы не должны ехать провайдеру в каждом запросе |
mcp.servers.<имя>.command | — | stdio: argv запуска (ядро держит процесс); env — окружение |
mcp.servers.<имя>.url | — | streamable HTTP: URL эндпоинта; headers — заголовки (авторизация). Ровно одно из command/url |
mcp.servers.<имя>.timeout | 60s | таймаут одного запроса (handshake, список, вызов) |
mcp.servers.<имя>.access | master | кому доступны инструменты: master | allowed | everyone |
mcp.servers.<имя>.trusted_only | false | только из доверенного окружения (TUI/Android; телеграм — нет) |
mcp.servers.<имя>.lazy | false | ленивый старт: на старте ядра к серверу не ходить, тулы поднять из кэша прошлого запуска, первый живой вызов запустит сервер сам. Первый запуск (кэша нет) подключается как обычно |
shell.remote | не задан (локально) | удалённый хост: name (для логов и подсказки модели), destination ([user@]host или алиас ssh_config), args (identity, порт…) |
shell.output_cap | не задан (без обрезки) | потолок вывода shell в символах; задан — обрезка с пометкой |
Сломанный MCP-сервер выключается целиком, ядро живёт дальше. На старте
серверы разрешаются параллельно (старт платит за самый медленный, не за
сумму), а регистрируются по отсортированным именам — порядок инструментов
в промпте детерминирован. Инструмент, объявивший _meta.ui.visibility без
"model" в списке (UI-виджеты MCP apps), модели не отдаётся.
| поле | дефолт | что это |
servers.<имя>.socket | — | UDS-сокет модуля (line-JSON-RPC, как stdio) |
servers.<имя>.tcp | — | host:port модуля на другой машине; ровно одно из socket/tcp |
servers.<имя>.access | everyone | кому доступны тулы: модуль ставит оператор, а администрирование внутри себя он запирает сам (_meta["dev.eva/master"]) |
servers.<имя>.trusted_only | false | только из доверенного окружения |
servers.<имя>.timeout | как у MCP | таймаут запроса |
socket_dir | не задана | директория *.sock-кандидатов: видны в module_list, подключаются module_approve |
Динамические модули регистрируются не конфигом, а тулами
(module_register и др.) — живут в базе, тулы появляются и исчезают без
рестарта ядра.
| поле | дефолт | что это |
proxy | не задан | прокси веб-запросов (socks5h://… или http://…) |
fetch_chars | 8000 | потолок отдаваемого моделью текста страницы |
searxng | не задана | база своего SearXNG — источник web_search; не задана — поиска нет (на SearXNG прокси не действует — он свой и локальный) |
search_results | 6 | сколько результатов поиска отдавать |
booru.<доска> | {} | учётки danbooru/e621/gelbooru: login/user_id + api_key (секрет) — снимают анонимные лимиты |
allow_private_hosts | [] | исключения из SSRF-щита: хосты (имена или IP-литералы), в которые web_fetch и скачивание source картинок могут ходить, даже если адрес приватный; см. безопасность |
| поле | дефолт | что это |
rules | встроенный набор | полный список правил {pattern, replace} (синтаксис Regex::replace_all, группы — ${1}); свой список замещает встроенный целиком, порядок несущий, пустой — выключает затирание |
Встроенный набор: Bearer …, sk-…, AKIA…, AGE-SECRET-KEY-…,
glpat-…, ghp_…/gho_…, PEM-блок приватного ключа целиком и присвоения
вида token=…/API_KEY: …. Плейсхолдер называет вид секрета:
[redacted: bearer token]. Подробнее — в безопасности.
| поле | дефолт | что это |
dir | не задан | каталог с *.toml-декларациями внешних инструментов |
ask_ttl | 5m | сколько ждут ответа кнопочные вопросы ask_questions |
on_demand | [] | что держать вне списка по умолчанию до tool_load |
Секции telegram в ядре нет: поверхность — отдельный модуль
со своим конфигом.
Путей четыре, включать можно сколько угодно — уведомление уйдёт по каждому
включённому (тул может сузить набор на один вызов: имена путей — chat,
push, tool, turn). Путь, который не смог, пишет в лог и не мешает
остальным.
| поле | дефолт | что это |
chat_id | не задан | чат ядра, куда падает сообщение-уведомление — видно в любом клиенте |
push.url | не задан | пуш на телефон: POST текста на URL (ntfy-совместимый) |
push.headers | {} | заголовки пуша: авторизация, приоритет, теги |
tool | не задан | инструмент реестра, которым уходит уведомление: текст ядро кладёт полем text его входа |
tool_args | {} | постоянная часть входа этого инструмента (объект): адрес, приоритет — всё, чего ядру знать не нужно |
turn.prompt | не задан | тур Евы по инструкции: master+trusted, но всё, что требует разрешения, идёт через очередь одобрений |
turn.chat_id | не задан | чат тура; не задан — чат повода, иначе свежий в папке проблем |
Путь tool — то, чем ядро дотягивается до мессенджера, ничего о нём не
зная: имя инструмента и его аргументы даёт оператор, куда это приедет —
забота самого инструмента. Личка Господина в телеграме выглядит так:
notify:
tool: "telegram_send_to_other_chat" # инструмент модуля-поверхности
tool_args: { chat_id: 123456789 } # его личка
Вызов идёт мастерским и доверенным (личности за ним нет), поэтому
инструменту доступны и master-only аргументы вроде адреса чата.
| поле | дефолт | что это |
persona.file | встроенная я | файл персоны для системного промпта |
master.name | не задан | имя Господина для маркера; сообщения без sender считаются его |
master.aliases | [] | алиасы его личностей (tg:<id> и т.п.) — по ним считается master-тур |