[2026-06-25] taiga-vault: family/how-to/htpc-emulators-setup.md family/how-to/htpc-gaming-plans.md family/how-to/kraken-access.md family/how-to/openmediavault-rpi5.md family/how-to/time-machine.md family/how-to/wireguard-vpn.md personal/documents/todo-list.md personal/plans/extract-stable-prompt-blocks.md personal/plans/hermes-whale-system-prompt.md personal/plans/thread-scoped-memory.md

This commit is contained in:
Taiga
2026-06-25 05:23:46 +00:00
parent ac0d753ec0
commit 16987d69f3
26 changed files with 2656 additions and 457 deletions
@@ -0,0 +1,222 @@
# Hermes Self-Improvement Review (Background Memory/Skill Review)
Source: codebase analysis of `hermes-agent/agent/background_review.py`, `run_agent.py`, `agent/conversation_loop.py`, `agent/agent_init.py`.
## Что это
После каждого юзерского сообщения ([run_conversation](https://github.com/NousResearch/hermes-agent)) AIAgent может запустить **фоновый daemon-thread**, который форкает ещё один AIAgent, даёт ему снимок всего разговора и просит оценить — нужно ли сохранить что-то в память (Memory) или обновить/создать скилл (Skill).
Основной поток продолжается немедленно. Ревью не блокирует пользователя.
## Where it lives
| File | Lines | Role |
|------|-------|------|
| `agent/background_review.py` | 1–597 | Центральный модуль — промпты, `_run_review_in_thread`, `spawn_background_review_thread`, `summarize_background_review_actions` |
| `run_agent.py` | 1360–1400 | Форвардеры: `_spawn_background_review`, `_summarize_background_review_actions`, импорт констант-промптов |
| `agent/conversation_loop.py` | 4779–4805 | Место вызова — после завершения ответа, перед возвратом `result` |
| `agent/codex_runtime.py` | 150–162 | Аналогичный вызов для Codex Response API режима |
| `agent/agent_init.py` | 10671075, 11871190 | Инициализация счётчиков и интервалов |
| `agent/tool_executor.py` | 207209, 776778 | Сброс счётчиков при вызове `memory` или `skill_manage` |
| `tui_gateway/server.py` | 2452–2464 | Подключение `background_review_callback` для TUI (Ink) |
| `gateway/run.py` | 17849–17893 | Подключение `background_review_callback` для gateway-сообщений |
## Как триггерится
Два независимых счётчика:
### Memory review (turn-based)
- Счётчик: `_turns_since_memory`
- Интервал: `_memory_nudge_interval` (default = **10**)
- Задаётся из `config.yaml: memory.nudge_interval`
- Инкрементится **в начале** каждого `run_conversation` (строка 559)
- Проверка: `if _turns_since_memory >= _memory_nudge_interval``_should_review_memory = True`
- Сброс: при вызове `memory` tool (строка 207 в tool_executor.py)
- Условия: `"memory" in valid_tool_names` и `_memory_store != None`
Если `memory_enabled: false` → ревью не триггерится.
### Skills review (iteration-based)
- Счётчик: `_iters_since_skill`
- Интервал: `_skill_nudge_interval` (default = **10**)
- Инкрементится **внутри tool-call цикла** после каждого батча (строка 860)
- Проверка: `if _iters_since_skill >= _skill_nudge_interval``_should_review_skills = True`
- Сброс: при вызове `skill_manage` tool (строки 209, 778 в tool_executor.py)
- Условия: `"skill_manage" in valid_tool_names`
### Финальная проверка
```python
if final_response and not interrupted and (_should_review_memory or _should_review_skills):
agent._spawn_background_review(
messages_snapshot=list(messages),
review_memory=_should_review_memory,
review_skills=_should_review_skills,
)
```
## Что происходит внутри
### `_run_review_in_thread` (background_review.py:327559)
1. **Создаёт форк AIAgent**, наследуя:
- `model`, `provider`, `base_url`, `api_key`, `credential_pool` от родителя (чтобы попасть в тот же prefix cache у Anthropic/OpenRouter)
- `_cached_system_prompt` — byte-идентичный, чтобы не разогревать кеш заново
- `session_id`, `session_start` — те же
- `_memory_store`, `_memory_enabled`, `_user_profile_enabled` — те же
- Но `skip_memory=True` (чтобы форк не создавал свой MemoryManager)
- `_memory_nudge_interval = 0`, `_skill_nudge_interval = 0` (чтобы не рекурсил)
2. **Устанавливает tool whitelist** (строки 459472):
```python
review_whitelist = {
t["function"]["name"]
for t in get_tool_definitions(
enabled_toolsets=["memory", "skills"],
quiet_mode=True,
)
}
```
Вне whitelist — всё блокируется с сообщением `"Background review denied non-whitelisted tool: ..."`
3. **Запускает** `review_agent.run_conversation(...)` с:
- Выбранным промптом (см. ниже) + суффикс `"You can only call memory and skill management tools. Other tools will be denied at runtime — do not attempt them."`
- `conversation_history=messages_snapshot` — весь разговор до этого момента
- `max_iterations=16` (жёстко, не из конфига)
4. **После завершения** — собирает успешные tool-результаты через `summarize_background_review_actions()`, фильтруя те, что уже были в `messages_snapshot` (чтобы не показывать старые как новые).
5. **Выводит** пользователю:
```python
f" 💾 Self-improvement review: {summary}"
# Например: "💾 Self-improvement review: Memory updated · Skill 'xxx' patched"
```
Через `agent._safe_print()` и через `agent.background_review_callback()` (для TUI/gateway).
6. **На ошибках** — пишет в лог `"Background memory/skill review failed: ..."` и шлёт `_emit_auxiliary_failure`. Не ломает основной разговор.
## 3 варианта промпта
Выбираются в `spawn_background_review_thread()` по комбинации флагов:
| `review_memory` | `review_skills` | Промпт | Суть |
|---|---|---|---|
| ✅ | ❌ | `_MEMORY_REVIEW_PROMPT` (~10 строк) | Сохранить факты о пользователе (persona, preferences, style). Если нечего — 'Nothing to save.' |
| ❌ | ✅ | `_SKILL_REVIEW_PROMPT` (~120 строк) | Самая большая инструкция. Искать сигналы: коррекции, frustration, новые техники, устаревшие скиллы. Приоритет: loaded skill → existing umbrella → support file → new umbrella. Запрещено: env-зависимости, негативные фиксации, session-specific. |
| ✅ | ✅ | `_COMBINED_REVIEW_PROMPT` (~80 строк) | Смесь обоих — сначала memory, потом skills с той же логикой. |
## Потенциальные проблемы
- **Нет конфигурируемости для skills interval** — `_skill_nudge_interval` хардкожен в 10, не читается из config.yaml (в отличие от memory).
- **Tool whitelist был фиксирован** — теперь настраивается через `review.allowed_toolsets` в config.yaml (см. ниже).
- **Форк не имеет MCP-серверов** — MCP tools (obsidian-mcp, etc.) не регенерируются в форке.
- **max_iterations=16** — жёстко, не из конфига. Может не хватить на комплексное ревью многоскилловых сессий.
## Реализованные расширения (2026-06-24)
Сделаны два изменения в исходном коде Hermes Agent для того, чтобы промпты и whitelist ревью были настраиваемы из `config.yaml`:
### 1. agent_init.py — чтение секции `review:` из config.yaml
Место: `agent/agent_init.py` (после блока skills config).
Читает секцию:
```yaml
review:
# Пути к .md файлам с кастомными промптами.
# Если файл не найден/не читается — тихо падает на встроенный хардкод.
skill_prompt_path: ~/.hermes/review/skill_prompt.md
memory_prompt_path: ~/.hermes/review/memory_prompt.md
combined_prompt_path: ~/.hermes/review/combined_prompt.md
# Какие toolsets доступны форку ревью.
# По дефолту: ["memory", "skills"].
# Чтобы форк мог читать/писать .md файлы Obsidian — добавить "file".
allowed_toolsets:
- memory
- skills
# - file
```
Что делает код:
1. Выставляет `agent._review_allowed_toolsets` (по дефолту `["memory", "skills"]`)
2. Для каждого из трёх путей (`skill_prompt_path`, `memory_prompt_path`, `combined_prompt_path`) — пытается прочитать файл и записать содержимое в `agent._SKILL_REVIEW_PROMPT` / `agent._MEMORY_REVIEW_PROMPT` / `agent._COMBINED_REVIEW_PROMPT` соответственно.
3. Если путь не указан, файл не найден или не читается — тихо игнорируется, остаётся встроенный хардкод.
### 2. background_review.py — использование `_review_allowed_toolsets` с инстанса
Место: `agent/background_review.py`, функция `_run_review_in_thread`, whitelist (строка ~459).
**Было:**
```python
review_whitelist = {
t["function"]["name"]
for t in get_tool_definitions(
enabled_toolsets=["memory", "skills"],
quiet_mode=True,
)
}
```
**Стало:**
```python
_allowed_sets = getattr(agent, "_review_allowed_toolsets", ["memory", "skills"])
review_whitelist = {
t["function"]["name"]
for t in get_tool_definitions(
enabled_toolsets=_allowed_sets,
quiet_mode=True,
)
}
```
А также сообщение для форка динамически подставляет имена toolsets вместо хардкода `"memory and skill"`.
### 3. Примеры промптов
Созданы в `~/.hermes/review/`:
- **`skill_prompt.md`** — копия встроенного `_SKILL_REVIEW_PROMPT` + секция `--- Obsidian documentation update ---`, которая инструктирует форк после каждого обновления скилла читать и патчить соответствующий `.md` в `/Users/admin/obsidian/`.
- **`memory_prompt.md`** — копия `_MEMORY_REVIEW_PROMPT` + инструкция обновлять `personal/profiles/Alex.md` при сохранении user preference.
### Как включить Obsidian-обновление
1. Раскомментировать в `~/.hermes/config.yaml`:
```yaml
review:
skill_prompt_path: ~/.hermes/review/skill_prompt.md
memory_prompt_path: ~/.hermes/review/memory_prompt.md
allowed_toolsets:
- memory
- skills
- file
```
2. Перезапустить Hermes (новый сессионный конфиг прочитается при старте `AIAgent.__init__`).
3. После каждого десятого tool-батча (или любого вызова `skill_manage` раньше) форк будет: создать/обновить скилл **и** прочитать/пропатчить соответствующий Obsidian-документ через `read_file`/`patch`.
### Замечание по архитектуре
File tools работают напрямую с файловой системой, в обход obsidian-mcp. Это значит:
- **Линки** `[[wiki]]` в Obsidian не резолвятся автоматически — форк видит сырой `.md`.
- **Frontmatter** (YAML заголовки) — видит как часть текста, может патчить.
- **Vault search** недоступен — только прямой путь к файлу.
Для большинства задач (пропатчить существующий doc, создать новый .md с frontmatter) file tools достаточно. Если нужен полный Obsidian API — надо дорабатывать подключение MCP в форке (Вариант B из первоначального исследования, пока не реализован).
## Related files
- `~/.hermes/hermes-whale/review/skill_prompt.md` — кастомный skills промпт с Obsidian-инструкцией (для всех артефактов: планы, конфиги, этапы проектов)
- `~/.hermes/hermes-whale/review/memory_prompt.md` — кастомный memory промпт с Obsidian-инструкцией
- `agent/agent_init.py` — чтение секции `review:` из config.yaml
- `agent/background_review.py` — использование `_review_allowed_toolsets` и кастомных промптов
- Config: `config.yaml → review.*` (см. секцию выше)
## Хронология
- 2026-06-24: Исследование и документирование механизма self-improvement review (Whale/Alex).
- 2026-06-24: Реализация настройки через config.yaml: промпты (через пути к .md) + allowed_toolsets. Созданы примеры промптов с Obsidian-инструкцией.
- 2026-06-24: Реализация thread-scoped memory + custom memory instruction (см. `personal/plans/thread-scoped-memory.md`).
- 2026-06-24: Тесты thread-scoped memory: 9 новых тестов (76/76 passed), закоммичено в `4ebad4f69`.