132 lines
6.7 KiB
Markdown
132 lines
6.7 KiB
Markdown
# Hermes Agent — вынос хардкода промптов в файлы (prompt_overrides)
|
||
|
||
**Дата:** 2026-09-15
|
||
**Статус:** реализовано, закоммичено и запушено
|
||
**Репо:** `~/.hermes/hermes-agent` (сабмодуль, форк `mallexxx/hermes-agent`)
|
||
|
||
## Проблема
|
||
|
||
Стабильный слой system prompt был **захардкожен** в `agent/prompt_builder.py`.
|
||
Чтобы поменять формулировку любого блока (например, ужесточить инструкции
|
||
про язык ответа или про завершение задачи) — надо было править Python-код
|
||
сабмодуля. Это значит: правка живёт в форке, конфликтует при подтяжке
|
||
апстрима, и её надо переносить при каждом обновлении.
|
||
|
||
## Решение: prompt_overrides
|
||
|
||
Каждый хардкод-блок stable-слоя читается из `.md` файла. Маппинг — в конфиге.
|
||
Файла нет → fallback на хардкод, ничего не ломается.
|
||
|
||
### Реализация (3 файла)
|
||
|
||
**1. `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
|
||
```
|
||
|
||
7 констант заменены на её вызовы:
|
||
|
||
| Блок | Константа (fallback) |
|
||
|------|---------------------|
|
||
| `hermes_help` | `HERMES_AGENT_HELP_GUIDANCE` |
|
||
| `task_completion` | `TASK_COMPLETION_GUIDANCE` |
|
||
| `memory_guidance` | `MEMORY_GUIDANCE` |
|
||
| `session_search_guidance` | `SESSION_SEARCH_GUIDANCE` |
|
||
| `skills_guidance` | `SKILLS_GUIDANCE` |
|
||
| `tool_use_enforcement` | `TOOL_USE_ENFORCEMENT_GUIDANCE` |
|
||
| `execution_discipline` | `OPENAI_MODEL_EXECUTION_GUIDANCE` |
|
||
|
||
**2. `agent/agent_init.py`** — чтение конфига в `agent._prompt_overrides`
|
||
(+11 строк, в секции рядом с tool-loop guardrail config).
|
||
|
||
**3. `~/.hermes/hermes-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
|
||
```
|
||
|
||
**4. `~/.hermes/hermes-whale/review/`** — 7 новых `.md` файлов с содержимым
|
||
блоков. Раньше в этой папке лежали только `memory_prompt.md` и `skill_prompt.md`.
|
||
|
||
## Pitfall: prompt_overrides — это про Python-код, а не про config
|
||
|
||
Файлы `review/*.md` **обязаны быть закоммичены**. Если закоммитить `config.yaml`
|
||
с путями, но не сами файлы — подмены промпта молча исчезнут (fallback на
|
||
хардкод), потому что `_load_prompt_block` ловит отсутствие файла в `except`
|
||
и отдаёт default. Ошибки нет, поведение просто возвращается к хардкоду.
|
||
|
||
Это ровно то, что чуть не произошло: 7 файлов `review/*.md` были untracked.
|
||
|
||
## Pitfall: порядок коммита сабмодуля
|
||
|
||
Правки Python живут в сабмодуле. Порядок:
|
||
|
||
```bash
|
||
cd ~/.hermes/hermes-agent && git add agent/*.py && git commit -m "..."
|
||
cd ~/.hermes && git add hermes-agent && git commit -m "..." # обновить пин
|
||
```
|
||
|
||
Если пин не обновить — в родительском репо видно
|
||
`hermes-agent (new commits, modified content)`, и `-dirty` в diff сабмодуля.
|
||
|
||
## Коммиты и push (2026-09-15)
|
||
|
||
| Репо | Коммит | Что |
|
||
|------|--------|-----|
|
||
| `hermes-agent` | `207a1de16` | feat: load stable system-prompt blocks from config prompt_overrides |
|
||
| `~/.hermes` | `7fd200c` | feat: wire prompt_overrides + whale-thread-guard multi-bot routing |
|
||
| `~/.hermes` | `7893c35` | chore: sync skills — curator consolidation |
|
||
| `~/.hermes` | `bdf84da` | chore(lsp): add vue/dockerfile/pyright/yaml language servers |
|
||
| `~/.hermes` | `176ce9c` | chore: thread-scoped memory store + claude token refresh script |
|
||
| `~/.hermes` | `9b111fc` | chore: untrack lsp/node_modules (1957 files, 43M) |
|
||
|
||
**Запушено:**
|
||
- `hermes-agent` → `github.com:mallexxx/hermes-agent` (20 коммитов)
|
||
- `~/.hermes` → `git.mallexxx.duckdns.org/git_admin/eagle-hermes` (9 коммитов)
|
||
|
||
## Осталось в коде (не вынесено)
|
||
|
||
- `DEFAULT_AGENT_IDENTITY` — fallback, остаётся хардкодом
|
||
- `GOOGLE_MODEL_OPERATIONAL_GUIDANCE` — неактуально для Whale
|
||
- `COMPUTER_USE_GUIDANCE`, `KANBAN_GUIDANCE` — неактуально
|
||
- `PLATFORM_HINTS` — webhook там нет
|
||
- `build_skills_system_prompt()` — автогенерируется, файлом не заменить
|
||
|
||
## Зачем это было нужно
|
||
|
||
Два практических повода:
|
||
|
||
1. **Правки промпта без правки Python** — теперь формулировки живут в `.md`,
|
||
редактируются в vault-стиле, не конфликтуют при подтяжке апстрима.
|
||
2. **Фикс языкового дрейфа DeepSeek** — нужна жёсткая языковая инструкция
|
||
в промпте; теперь её можно добавить файлом, а не патчем кода.
|
||
См. [[deepseek-language-drift]].
|
||
|
||
## Связанное
|
||
|
||
- [[hermes-whale-system-prompt]] — полный состав system prompt (3 слоя)
|
||
- [[hermes-git-repo]] — структура репо, .gitignore, что коммитить
|
||
- [[deepseek-language-drift]] — баг с китайским выводом, повод для правок промпта
|
||
- [[hermes-fork-vs-upstream]] — расхождение с апстримом (24k коммитов)
|