Персона
Ядро нейтрально: ни имени, ни рода, ни обращения в коде нет. Всё, что
делает ассистента кем-то, задаёт секция persona конфига — а строки
своих UI каждый клиент держит у себя. Ядро о клиентах не знает; клиенты
знают ядро.
Из чего складывается персона
| слой | где живёт | на что влияет |
|---|---|---|
| голос модели | persona.file (persona.md) у ядра | первые байты системного промпта |
| обращение | persona.honorific у ядра | правило в [speakers] и якоре атрибуции: «say {honorific} ONLY under a Master marker»; клиенты подставляют в свои строки |
| имя | persona.name у ядра | клиенты подставляют в тайтлы и строки, дефолтная причина chat_attention |
| строки UI | оверлей в конфиге клиента | голос интерфейса поверх нейтрального встроенного каталога |
Без секции persona всё работает на брендовых дефолтах: имя «Ева»,
обращение «Господин», встроенный текст персоны — нейтральный ассистент.
Форкеру достаточно задать свои name/honorific; null или пустая
строка выключают поле совсем — клиенты уходят на нейтральный бренд, а
правило об обращении из промпта пропадает.
GET /v1/persona
{ "name": "Ева", "honorific": "Господин" }
Только идентичность. Клиент подставляет её в собственные строки через
подстановки {name} и {honorific}; null — клиент падает на свой
нейтральный бренд и обходится без обращения. Старое ядро без ручки
(404) читается так же, как null-ы.
Оверлеи клиентов
Каждый клиент шьёт в себя полный нейтральный каталог строк и принимает
оверлей — плоский файл «ключ → строка или список строк» — через свой
конфиг (где именно — в доке клиента; образец — docs/persona-overlay.example.yaml
в каждой клиентской репе). Общий контракт, чтобы один документ персоны
порождал согласованные оверлеи:
- плоские dot-ключи; неймспейс — клиент:
web.*,app.*,tui.*,tg.*,common.*; - значение — строка или список строк (списки — для ротаций);
{placeholders}встроенной строки сохраняются байт-в-байт; всюду доступны{name}и{honorific}— имена и обращения в текст не зашиваются, файл переживает их смену;- плюрализация — суффикс-ключами
key.one/key.few/key.many(CLDR-категории): переписывается вся тройка или ничего; - ключ, которого в оверлее нет, остаётся встроенным — оверлей можно вести по частям.
Генерация оверлеев
scripts/persona-localize.py — из документа персоны и нейтральных
каталогов через OpenRouter-совместимый API, по разу на клиента:
OPENROUTER_API_KEY=… python3 scripts/persona-localize.py \
--persona persona.md \
--catalog tui/src/eva_tui/locale/builtin.json \
--reference tui/docs/persona-overlay.example.yaml \
--model anthropic/claude-sonnet-5 \
--out tui-overlay.yaml
Каталоги ест как есть (.json/.yaml — плоская карта, .ts — веб,
.rs — мост); сам валидирует ключи, плейсхолдеры и полноту счётных
троек. --reference подкладывает прежний оверлей эталоном тона,
--base-url/EVA_LOCALIZE_BASE_URL — свой апстрим, --dry-run только
считает ключи. Результат ревьюится git-диффом в конфиг-репе и уезжает в
конфиг соответствующего клиента. Скрипт — оффлайн-инструмент: в
рантайме ядро клиентских строк не касается.
NixOS
services.eva-kernel = {
persona.file = ./persona.md; # → settings.persona.file
settings.persona = {
name = "Ева";
honorific = "Господин";
};
};
Персона — не секрет: файл уезжает в мировой стор. Нужен путь вне
стора — пишите settings.persona.file строкой. Оверлеи клиентов
подключаются в модулях самих клиентов.