diff --git a/personal/plans/extract-stable-prompt-blocks.md b/personal/plans/extract-stable-prompt-blocks.md deleted file mode 100644 index 030d7a66..00000000 --- a/personal/plans/extract-stable-prompt-blocks.md +++ /dev/null @@ -1,133 +0,0 @@ -# План: Вынести хардкод stable-блоков system prompt в файлы - -**Статус:** Реализовано ✅ (ждёт перезапуска webhook) - -## Мотивация - -В Hermes Whale все stable-блоки system prompt (identity, guidance, enforcement) захардкожены в `agent/prompt_builder.py` как Python-константы. Невозможно изменить их без редактирования исходного кода Hermes Agent. - -## Решение - -Вынести каждый блок в отдельный `.md` файл, добавить маппинг в `config.yaml: agent.prompt_overrides`, и модифицировать `agent/system_prompt.py`, чтобы он читал файлы вместо констант. - -## Изменяемые файлы - -### 1. `agent/system_prompt.py` — замена констант на file-load - -Добавлена функция `_load_prompt_block(agent, block_name, default_text)` — строки 51-71 в `/Users/admin/.hermes/hermes-agent/agent/system_prompt.py`: -- Читает `agent._prompt_overrides` (берётся из конфига на старте) -- Если для `block_name` указан путь — читает файл, возвращает его содержимое -- Иначе возвращает `default_text` - -Заменены все 7 прямых ссылок на константы в `build_system_prompt_parts()` на вызовы `_load_prompt_block()`. - -Добавлены импорты: `import logging`, `import os`, `from pathlib import Path`, `logger = logging.getLogger(__name__)`. - -**Константы, которые заменяются (7 блоков):** - -| Блок | Константа | Вставляется при условии | -|------|-----------|------------------------| -| `hermes_help` | `HERMES_AGENT_HELP_GUIDANCE` | всегда | -| `task_completion` | `TASK_COMPLETION_GUIDANCE` | всегда | -| `memory_guidance` | `MEMORY_GUIDANCE` | когда есть tool "memory" | -| `session_search_guidance` | `SESSION_SEARCH_GUIDANCE` | когда есть tool "session_search" | -| `skills_guidance` | `SKILLS_GUIDANCE` | когда есть tool "skill_manage" | -| `tool_use_enforcement` | `TOOL_USE_ENFORCEMENT_GUIDANCE` | зависит от модели | -| `execution_discipline` | `OPENAI_MODEL_EXECUTION_GUIDANCE` | зависит от модели | - -**Не заменяется (остаётся в коде):** -- `DEFAULT_AGENT_IDENTITY` — это fallback когда нет SOUL.md (у нас есть SOUL.md, не нужно) -- `GOOGLE_MODEL_OPERATIONAL_GUIDANCE` — Google-specific, неактуально для Whale -- `COMPUTER_USE_GUIDANCE` — нет toolset -- `KANBAN_GUIDANCE` — нет kanban -- `PLATFORM_HINTS` — platform-specific, другая логика - -### 2. `agent/system_prompt.py` — добавить функцию загрузки - -```python -def _load_prompt_block(agent, block_name: str, default: str) -> str: - """Load a prompt block from a file if configured, else return default.""" - overrides = getattr(agent, "_prompt_overrides", None) or {} - path = overrides.get(block_name) - if path: - try: - resolved = os.path.expanduser(path) - content = Path(resolved).read_text(encoding="utf-8").strip() - if content: - return content - except Exception: - logger.debug("Could not load prompt override '%s' from %s", block_name, path) - return default -``` - -### 3. `agent/agent_init.py` — пробросить конфиг - -После загрузки `_agent_cfg` (строка ~1058) добавлено чтение `agent.prompt_overrides`: - -```python -agent._prompt_overrides = {} -try: - _po = _agent_cfg.get("agent", {}).get("prompt_overrides", {}) - if isinstance(_po, dict): - agent._prompt_overrides = _po -except Exception: - pass -``` - -### 4. Конфиг Whale — `config.yaml` - -Добавить секцию: - -```yaml -agent: - prompt_overrides: - hermes_help: ~/.hermes/hermes-whale/review/hermes_help.md - task_completion: ~/.hermes/hermes-whale/review/task_completion.md - memory_guidance: ~/.hermes/hermes-whale/review/memory_guidance.md - session_search_guidance: ~/.hermes/hermes-whale/review/session_search_guidance.md - skills_guidance: ~/.hermes/hermes-whale/review/skills_guidance.md - tool_use_enforcement: ~/.hermes/hermes-whale/review/tool_use_enforcement.md - execution_discipline: ~/.hermes/hermes-whale/review/execution_discipline.md -``` - -### 5. Файлы блоков - -Создать 7 файлов в `~/.hermes/hermes-whale/review/`: - -- `hermes_help.md` — содержимое константы `HERMES_AGENT_HELP_GUIDANCE` -- `task_completion.md` — содержимое `TASK_COMPLETION_GUIDANCE` -- `memory_guidance.md` — содержимое `MEMORY_GUIDANCE` -- `session_search_guidance.md` — содержимое `SESSION_SEARCH_GUIDANCE` -- `skills_guidance.md` — содержимое `SKILLS_GUIDANCE` -- `tool_use_enforcement.md` — содержимое `TOOL_USE_ENFORCEMENT_GUIDANCE` -- `execution_discipline.md` — содержимое `OPENAI_MODEL_EXECUTION_GUIDANCE` - -### 6. Обратная совместимость - -Если `prompt_overrides` не задан или файл не найден — используется хардкод. Никакой код не ломается для других профилей/пользователей. - -### 7. Документация - -- Обновить `personal/plans/thread-scoped-memory.md` → переименовать или создать отдельный doc -- Создать `personal/plans/extract-stable-prompt-blocks.md` (этот) - -## Порядок выполнения - -1. ✅ Создать 7 файлов блоков в `~/.hermes/hermes-whale/review/` -2. ✅ Пропатчить `agent/system_prompt.py` — добавить `_load_prompt_block()` и заменить 7 констант -3. ✅ Пропатчить `agent/agent_init.py` — пробросить `prompt_overrides` из конфига -4. ✅ Обновить `config.yaml` — добавить `agent.prompt_overrides` (через копию, т.к. patch блокирован TIRITH) -5. ⏸️ Перезапустить webhook (ждёт команды) -6. ⏸️ Обновить Obsidian docs (этот шаг) - -## Проверка - -После изменений system prompt должен содержать те же блоки, что и раньше, но загруженные из файлов. При изменении файла и рестарте сессии — новый текст. При удалении файла — fallback на хардкод. - -## Pitfalls - -- **TIRITH блокирует patch/config.yaml** — `config.yaml` под защитой TIRITH, patch и write_file отказываются писать в него. Решение: `cp` в `/tmp/`, отредактировать там, `cp` обратно (с аппрувом). -- **sed не подходит для YAML конфигов** — сложные многострочные замены с вложенными отступами и escape-символами (`~`, `/`) ломаются в sed. Лучше patch. -- **Конфиг всё равно просит аппрув** — при `cp` обратно TIRITH запрашивает подтверждение (overwrite project env/config file). Это нормально, нужно подтвердить. -- **SOUL.md уже существует** — в Whale он лежит в `/Users/admin/.hermes/hermes-whale/SOUL.md`. Он НЕ выносится через prompt_overrides, т.к. уже является файлом и загружается отдельно через `load_soul_md()`. -- **webhook не в PLATFORM_HINTS** — webhook нет в словаре `PLATFORM_HINTS` в `prompt_builder.py`, поэтому блок platform hints пустой. Это не менялось. diff --git a/personal/projects/personal-os/hermes-agent-improvements.md b/personal/projects/personal-os/hermes-agent-improvements.md index 4b1fb83d..bc02d4c2 100644 --- a/personal/projects/personal-os/hermes-agent-improvements.md +++ b/personal/projects/personal-os/hermes-agent-improvements.md @@ -59,3 +59,243 @@ Eagle использует custom agents — текущий подход. Сессии пишутся в `~/.hermes/sessions/`, но `memory.md` и vault обновляются только вручную или через vault-enrichment (раз в неделю). **Fix:** cron 02:00 AM ежедневно — читает свежие сессии, обновляет `memory.md` и `personal/projects/`. Вписывается в слот между inbox-sort (01:00) и vault-enrichment (03:00 вс). + +--- + +## Вынос хардкода промптов в файлы + +**Статус:** Реализовано ✅ (будет активно после перезапуска webhook) + +### Мотивация + +В Hermes Whale все stable-блоки system prompt (identity, guidance, enforcement) были захардкожены в `agent/prompt_builder.py` как Python-константы. Невозможно изменить их без редактирования исходного кода Hermes Agent. + +### Решение + +Вынести каждый блок в отдельный `.md` файл, добавить маппинг в `config.yaml: agent.prompt_overrides`, модифицировать `agent/system_prompt.py`, чтобы он читал файлы вместо констант. + +### Изменяемые файлы + +#### 1. `agent/system_prompt.py` — замена констант на file-load + +Добавлена функция `_load_prompt_block(agent, block_name, default_text)` — строки 51-71 в `/Users/admin/.hermes/hermes-agent/agent/system_prompt.py`: +- Читает `agent._prompt_overrides` (берётся из конфига на старте) +- Если для `block_name` указан путь — читает файл, возвращает его содержимое +- Иначе возвращает `default_text` + +Заменены все 7 прямых ссылок на константы в `build_system_prompt_parts()` на вызовы `_load_prompt_block()`. + +Добавлены импорты: `import logging`, `import os`, `from pathlib import Path`, `logger = logging.getLogger(__name__)`. + +**Константы, которые заменяются (7 блоков):** + +| Блок | Константа | Вставляется при условии | +|------|-----------|------------------------| +| `hermes_help` | `HERMES_AGENT_HELP_GUIDANCE` | всегда | +| `task_completion` | `TASK_COMPLETION_GUIDANCE` | всегда | +| `memory_guidance` | `MEMORY_GUIDANCE` | когда есть tool "memory" | +| `session_search_guidance` | `SESSION_SEARCH_GUIDANCE` | когда есть tool "session_search" | +| `skills_guidance` | `SKILLS_GUIDANCE` | когда есть tool "skill_manage" | +| `tool_use_enforcement` | `TOOL_USE_ENFORCEMENT_GUIDANCE` | зависит от модели | +| `execution_discipline` | `OPENAI_MODEL_EXECUTION_GUIDANCE` | зависит от модели | + +**Не заменяется (остаётся в коде):** +- `DEFAULT_AGENT_IDENTITY` — это fallback когда нет SOUL.md (у нас есть SOUL.md, не нужно) +- `GOOGLE_MODEL_OPERATIONAL_GUIDANCE` — Google-specific, неактуально для Whale +- `COMPUTER_USE_GUIDANCE` — нет toolset +- `KANBAN_GUIDANCE` — нет kanban +- `PLATFORM_HINTS` — platform-specific, другая логика + +#### 2. `agent/system_prompt.py` — функция загрузки + +```python +def _load_prompt_block(agent, block_name: str, default: str) -> str: + """Load a prompt block from a file if configured, else return default.""" + overrides = getattr(agent, "_prompt_overrides", None) or {} + path = overrides.get(block_name) + if path: + try: + resolved = os.path.expanduser(path) + content = Path(resolved).read_text(encoding="utf-8").strip() + if content: + return content + except Exception: + logger.debug("Could not load prompt override '%s' from %s", block_name, path) + return default +``` + +#### 3. `agent/agent_init.py` — пробросить конфиг + +После загрузки `_agent_cfg` (строка ~1058) добавлено чтение `agent.prompt_overrides`: + +```python +agent._prompt_overrides = {} +try: + _po = _agent_cfg.get("agent", {}).get("prompt_overrides", {}) + if isinstance(_po, dict): + agent._prompt_overrides = _po +except Exception: + pass +``` + +#### 4. Конфиг Whale — `config.yaml` + +Добавлена секция: + +```yaml +agent: + prompt_overrides: + hermes_help: ~/.hermes/hermes-whale/review/hermes_help.md + task_completion: ~/.hermes/hermes-whale/review/task_completion.md + memory_guidance: ~/.hermes/hermes-whale/review/memory_guidance.md + session_search_guidance: ~/.hermes/hermes-whale/review/session_search_guidance.md + skills_guidance: ~/.hermes/hermes-whale/review/skills_guidance.md + tool_use_enforcement: ~/.hermes/hermes-whale/review/tool_use_enforcement.md + execution_discipline: ~/.hermes/hermes-whale/review/execution_discipline.md +``` + +#### 5. Файлы блоков + +Созданы 7 файлов в `~/.hermes/hermes-whale/review/`: + +- `hermes_help.md` — содержимое константы `HERMES_AGENT_HELP_GUIDANCE` +- `task_completion.md` — содержимое `TASK_COMPLETION_GUIDANCE` +- `memory_guidance.md` — содержимое `MEMORY_GUIDANCE` +- `session_search_guidance.md` — содержимое `SESSION_SEARCH_GUIDANCE` +- `skills_guidance.md` — содержимое `SKILLS_GUIDANCE` +- `tool_use_enforcement.md` — содержимое `TOOL_USE_ENFORCEMENT_GUIDANCE` +- `execution_discipline.md` — содержимое `OPENAI_MODEL_EXECUTION_GUIDANCE` + +#### Обратная совместимость + +Если `prompt_overrides` не задан или файл не найден — используется хардкод. Никакой код не ломается для других профилей/пользователей. + +### Порядок выполнения + +1. ✅ Создать 7 файлов блоков в `~/.hermes/hermes-whale/review/` +2. ✅ Пропатчить `agent/system_prompt.py` — добавить `_load_prompt_block()` и заменить 7 констант +3. ✅ Пропатчить `agent/agent_init.py` — пробросить `prompt_overrides` из конфига +4. ✅ Обновить `config.yaml` — добавить `agent.prompt_overrides` (через копию, т.к. patch блокирован TIRITH) +5. ⏸️ Перезапустить webhook (ждёт команды) +6. ⏸️ Обновить Obsidian docs (этот шаг — выполнен) + +### Проверка + +После изменений system prompt должен содержать те же блоки, что и раньше, но загруженные из файлов. При изменении файла и рестарте сессии — новый текст. При удалении файла — fallback на хардкод. + +### Pitfalls + +- **TIRITH блокирует patch/config.yaml** — `config.yaml` под защитой TIRITH, patch и write_file отказываются писать в него. Решение: `cp` в `/tmp/`, отредактировать там, `cp` обратно (с аппрувом). +- **sed не подходит для YAML конфигов** — сложные многострочные замены с вложенными отступами и escape-символами (`~`, `/`) ломаются в sed. Лучше patch. +- **Конфиг всё равно просит аппрув** — при `cp` обратно TIRITH запрашивает подтверждение (overwrite project env/config file). Это нормально, нужно подтвердить. +- **SOUL.md уже существует** — в Whale он лежит в `/Users/admin/.hermes/hermes-whale/SOUL.md`. Он НЕ выносится через prompt_overrides, т.к. уже является файлом и загружается отдельно через `load_soul_md()`. +- **webhook не в PLATFORM_HINTS** — webhook нет в словаре `PLATFORM_HINTS` в `prompt_builder.py`, поэтому блок platform hints пустой. Это не менялось. + +--- + +## Анализ вынесенных prompt-блоков + +Все 7 файлов лежат в `~/.hermes/hermes-whale/review/` и подключаются через `config.yaml → agent.prompt_overrides`. + +### 1. SOUL.md — Identity (не выносился, уже файл) + +**Путь:** `~/.hermes/hermes-whale/SOUL.md` +**33 строки** — определяет личность Кит (Whale), правила работы с Obsidian, инструментами, TIRITH, jq. + +**Структура:** +- Identity + run location +- Core Rules (Obsidian first, vault namespaces, no external APIs, no `python3 -c "import json"`, TIRITH, jq) +- Absolute rules (стоп — zero actions) +- Hermes self-reference (дока в приоритете над skill_view) + +**Наблюдения:** +- ⚠️ **Дублирование с `hermes_help.md`** — SOUL.md строка 34+ («AGAIN. ALWAYS check Obsidian first...») и `hermes_help.md` (Hermes Agent docs) пересекаются. Hermes help ссылается на docs.nousresearch.com, а SOUL напоминает про Obsidian MCP. Это complementary, а не конфликт — одно про внешнюю доку, другое про внутреннюю. Но стоит явно разделить: SOUL = who you ARE, hermes_help = что делать с Hermes как продуктом. +- ✅ jq-правило (строка 22-23) удачно помещено именно сюда — это Whale-specific constraint. +- ✅ `respond in the language you're addressed in` — хорошее мягкое правило, сохраняет билингвальность. +- ❌ Нет guard: после обновления доков — проверить, нет ли сломанных ссылок/дубликатов. + +### 2. `execution_discipline.md` — 48 строк, самый большой блок + +**Структура XML-тэги:** +- `` — не останавливаться рано, retry, verify +- `` — не отвечать по памяти: math, hashes, system state, git, web +- `` — очевидные интерпретации — действовать сразу +- `` — проверять зависимости перед действием +- `` — корректность, grounding, формат, safety +- `` — не гадать, использовать lookup, только потом спросить + +**Наблюдения:** +- ✅ Отличная структура: секции-запреты с чёткими примерами уменьшают ambiguity. +- ⚠️ `` пункт «Safety: if the next step has side effects... confirm scope before executing» — мягко противоречит ``, которое велит не спрашивать. В `hermes_whale` system prompt поверх есть «NEVER REMOVE/KILL WITHOUT CONFIRMATION», так что extra safety здесь не лишняя, но формулировка «confirm scope» может спровоцировать лишний вопрос. +- ✅ `` — самое важное: запрещает LLM-галлюцинации фактов внешнего мира. +- ❌ Нет секции про **batch/parallel execution** — при multi-file операциях агент может делать последовательно то, что можно параллельно. +- ❌ Нет секции про **отношение к ошибкам** — если инструмент вернул ошибку, нужно ли retry с другим подходом (записано в ``) или сообщить пользователю. + +### 3. `task_completion.md` — 3 строки + +**Суть:** не останавливаться на плане/стабе — доводить до работающего артефакта. Не фабриковать результаты при блокере. + +**Наблюдения:** +- ✅ Критически важный guard против premature stopping. +- ⚠️ Не покрывает ситуацию: «задача сделана, но пользователь не проверил» — должен ли агент спросить «проверить?» или просто отчитаться? +- ❌ Не упоминает **сценарий partial failure**: часть задачи выполнена, часть провалилась — как подавать результат? + +### 4. `hermes_help.md` — 1 строка + +**Суть:** docs.nousresearch.com как authoritative reference, `skill_view('hermes-agent')` для guidance. + +**Наблюдения:** +- ✅ Лаконично. +- ❌ Не упоминает куда писать issue / как апдейтить самому. +- ⚠️ **Несовпадение с реальностью:** дока не всегда полная (есть расхождения с реальным API). Skill часто актуальнее. + +### 5. `memory_guidance.md` — 1 строка, 1441 символ (самая длинная строка) + +**Суть:** compact facts, what to save (preferences, corrections, env), what NOT to save (task progress, PRs, stale artifacts). Imperative phrasing bad. Sessions for recall, skills for procedures. + +**Наблюдения:** +- ✅ Отличный negative list (не сохранять PR numbers, commit SHAs, "Phase N done"). +- ✅ Важный паттерн: declarative facts vs instructions — записана разница с примерами. +- ⚠️ «Write memories as declarative facts, not instructions to yourself» — полезно, но не всегда практично: некоторые memory entries работают лучше как правила (например, «Allways back up before editing» vs «User prefers backups before edits»). +- ❌ Нет про **conditional memory** — «если X, то запомни Y». Например, при ошибке сети — не запоминать «нет соединения», это transient. + +### 6. `session_search_guidance.md` — 1 строка + +**Суть:** прежде чем спрашивать пользователя — поищи в истории сессий. + +**Наблюдения:** +- ✅ Одно чёткое правило, минимум слов. +- ❌ **Не хватает:** когда НЕ надо искать (например, если вопрос про current OS state — не искать, а сразу `uname`). + +### 7. `skills_guidance.md` — 1 строка + +**Суть:** после сложной задачи — сохранить как skill; outdated skill — patch сразу. + +**Наблюдения:** +- ✅ Лаконично. +- ❌ **Не хватает:** критерии «сложности» (5+ tool calls — триггер). И что делать с zombie skills (которые больше не нужны). + +### 8. `tool_use_enforcement.md` — 2 строки + +**Суть:** MUST use tools, не описывать планы без экзекьюшена. Каждый response = tool calls или final result. + +**Наблюдения:** +- ✅ Самый жёсткий enforcement блок. Правильно. +- ❌ **Не хватает:** что делать когда tools не доступны (tool_use_enforcement не может быть выполнен). + +### Cross-cutting observations + +1. **Размеры файлов несбалансированы:** `execution_discipline` (48 строк) vs `session_search_guidance` (1 строка). Это ОК — разные блоки разной сложности. +2. **XML vs Markdown**: `execution_discipline` использует XML-тэги как semantic sections — интересно, работает ли это для модели как структурный сигнал? В `hermes_whale` system prompt есть ещё `# Headers` как разделители. **Два стиля в одном system prompt — возможно, снижают эффективность.** +3. **Нет ordering гарантий**: блоки вставляются в разном порядке в `build_system_prompt_parts()` — сначала task_completion, потом hermes_help, потом execution_discipline. Но модель читает слева направо. Если execution_discipline должен быть последним (как enforcement override) — его позиция в сборке не гарантирует этого. +4. **Нет cross-reference** между файлами: например, `execution_discipline` не ссылается на `task_completion` или наоборот. Агент может воспринимать их как независимые, несмотря на overlap. +5. **Нет версионирования блоков:** если поменять `execution_discipline.md`, нет способа отследить «было / стало» без диффа гита. +6. **Potential prompt compression issue:** при длинных system prompts модель может терять середину (lost-in-the-middle). `execution_discipline` (2.7KB) — самый тяжёлый блок. Возможно, стоит сократить примеры в `` (все 11 пунктов проверять не надо — достаточно 4-5). + +### Рекомендации + +1. **Добавить ordering guard** — execution_discipline и tool_use_enforcement должны быть последними в system prompt (как override rules). +2. **Консолидировать XML-стиль** — либо все блоки в XML-тэгах, либо все в Markdown headers. +3. **Добавить conditional session_search** — правило: для state-вопросов (time, OS, memory) — не session_search, сразу tool. +4. **Добавить partial failure protocol** в task_completion. +5. **Ввести дайджест prompt-блоков** — при изменении любого .md файла в `review/` логировать diff.