fix(title): follow-ups for salvaged #37349 — lazy config import, guard ordering, config example

- Make the config imports lazy inside _auto_title_enabled(), matching the
  existing _title_language() pattern (title_generator is imported from agent
  code paths where a module-level hermes_cli import risks circularity).
- Check the enabled flag after the cheap first-exchange guard in
  maybe_auto_title so config isn't read on every turn of a long session.
- Repoint the two new tests at the real import site.
- Document the key in cli-config.yaml.example and merge the enabled flag
  into the existing title_generation block in configuration.md.
- AUTHOR_MAP entry for the contributor.
This commit is contained in:
Teknium 2026-07-16 19:49:28 -07:00
parent e20c3c1c29
commit 8222b16785
4 changed files with 23 additions and 8 deletions

View file

@ -9,8 +9,6 @@ import threading
from typing import Callable, Optional
from agent.auxiliary_client import call_llm
from hermes_cli.config import load_config_readonly
from utils import is_truthy_value
logger = logging.getLogger(__name__)
@ -53,6 +51,12 @@ def _title_language() -> str:
def _auto_title_enabled() -> bool:
"""Return whether automatic session title generation is enabled."""
try:
# Lazy imports, matching _title_language(): title_generator is imported
# from agent code paths where a module-level hermes_cli import risks
# circularity, and the read-only loader avoids config-migration writes.
from hermes_cli.config import load_config_readonly
from utils import is_truthy_value
config = load_config_readonly()
title_config = (config.get("auxiliary") or {}).get("title_generation") or {}
return is_truthy_value(title_config.get("enabled"), default=True)
@ -263,10 +267,6 @@ def maybe_auto_title(
if not session_db or not session_id or not user_message or not assistant_response:
return
if not _auto_title_enabled():
logger.debug("Auto-title skipped: auxiliary.title_generation.enabled=false")
return
# Count user messages in history to detect first exchange.
# conversation_history includes the exchange that just happened,
# so for a first exchange we expect exactly 1 user message
@ -275,6 +275,12 @@ def maybe_auto_title(
if user_msg_count > 2:
return
# Config read comes after the cheap first-exchange guard so the file
# isn't touched on every subsequent turn of a long session.
if not _auto_title_enabled():
logger.debug("Auto-title skipped: auxiliary.title_generation.enabled=false")
return
thread = threading.Thread(
target=auto_title_session,
args=(session_db, session_id, user_message, assistant_response),

View file

@ -526,6 +526,14 @@ prompt_caching:
# model: ""
# timeout: 30
#
# # Automatic session title generation after the first exchange
# title_generation:
# enabled: true # set false to disable auto-title generation
# provider: "auto"
# model: ""
# timeout: 30
# language: "" # empty = match the user's language; or e.g. "English"
#
# # Session search — summarizes matching past sessions
# session_search:
# provider: "auto"

View file

@ -364,6 +364,7 @@ AUTHOR_MAP = {
"290859878+synapsesx@users.noreply.github.com": "synapsesx",
"157689911+itsflownium@users.noreply.github.com": "itsflownium",
"dirtyren@users.noreply.github.com": "dirtyren",
"s96919@gmail.com": "s96919",
"yakimenkoleksander228@gmail.com": "doxe0x",
"a54983334@163.com": "Code-suphub",
"78542984+Code-suphub@users.noreply.github.com": "Code-suphub",

View file

@ -215,7 +215,7 @@ class TestGenerateTitle:
config = {"auxiliary": {"title_generation": {"enabled": False}}}
with (
patch("agent.title_generator.load_config_readonly", return_value=config),
patch("hermes_cli.config.load_config_readonly", return_value=config),
patch("agent.title_generator.call_llm") as mock_call_llm,
):
assert generate_title("question", "answer") is None
@ -369,7 +369,7 @@ class TestMaybeAutoTitle:
config = {"auxiliary": {"title_generation": {"enabled": False}}}
with (
patch("agent.title_generator.load_config_readonly", return_value=config),
patch("hermes_cli.config.load_config_readonly", return_value=config),
patch("agent.title_generator.auto_title_session") as mock_auto,
):
maybe_auto_title(db, "sess-1", "hello", "hi there", history)