mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-21 10:22:18 +00:00
feat(titles): support language-aware title generation (#45296)
Make auxiliary title prompts match the user language by default, with an optional pinned `auxiliary.title_generation.language` config.
This commit is contained in:
parent
8cf7df867e
commit
cf58f1a520
4 changed files with 74 additions and 1 deletions
|
|
@ -22,9 +22,31 @@ TitleCallback = Callable[[str], None]
|
|||
_TITLE_PROMPT = (
|
||||
"Generate a short, descriptive title (3-7 words) for a conversation that starts with the "
|
||||
"following exchange. The title should capture the main topic or intent. "
|
||||
"Write the title in the same language the user is writing in. "
|
||||
"Return ONLY the title text, nothing else. No quotes, no punctuation at the end, no prefixes."
|
||||
)
|
||||
|
||||
_TITLE_PROMPT_PINNED_LANGUAGE = (
|
||||
"Generate a short, descriptive title (3-7 words) for a conversation that starts with the "
|
||||
"following exchange. The title should capture the main topic or intent. "
|
||||
"Write the title in {language}. "
|
||||
"Return ONLY the title text, nothing else. No quotes, no punctuation at the end, no prefixes."
|
||||
)
|
||||
|
||||
|
||||
def _title_language() -> str:
|
||||
"""Return configured title language, or empty string to match the user."""
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
|
||||
return str(
|
||||
((load_config() or {}).get("auxiliary") or {})
|
||||
.get("title_generation", {})
|
||||
.get("language", "")
|
||||
).strip()
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
def generate_title(
|
||||
user_message: str,
|
||||
|
|
@ -48,8 +70,11 @@ def generate_title(
|
|||
user_snippet = user_message[:500] if user_message else ""
|
||||
assistant_snippet = assistant_response[:500] if assistant_response else ""
|
||||
|
||||
language = _title_language()
|
||||
prompt = _TITLE_PROMPT_PINNED_LANGUAGE.format(language=language) if language else _TITLE_PROMPT
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": _TITLE_PROMPT},
|
||||
{"role": "system", "content": prompt},
|
||||
{"role": "user", "content": f"User: {user_snippet}\n\nAssistant: {assistant_snippet}"},
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1438,6 +1438,7 @@ DEFAULT_CONFIG = {
|
|||
"api_key": "",
|
||||
"timeout": 30,
|
||||
"extra_body": {},
|
||||
"language": "",
|
||||
},
|
||||
"tts_audio_tags": {
|
||||
"provider": "auto",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ from agent.title_generator import (
|
|||
generate_title,
|
||||
auto_title_session,
|
||||
maybe_auto_title,
|
||||
_title_language,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -22,6 +23,42 @@ class TestGenerateTitle:
|
|||
title = generate_title("help me fix this import", "Sure, let me check...")
|
||||
assert title == "Debugging Python Import Errors"
|
||||
|
||||
def test_default_prompt_matches_user_language(self):
|
||||
mock_response = MagicMock()
|
||||
mock_response.choices = [MagicMock()]
|
||||
mock_response.choices[0].message.content = "Some Title"
|
||||
|
||||
with patch("agent.title_generator.call_llm", return_value=mock_response) as llm:
|
||||
generate_title("質問です", "回答です")
|
||||
|
||||
system_prompt = llm.call_args.kwargs["messages"][0]["content"]
|
||||
assert "same language the user is writing in" in system_prompt
|
||||
|
||||
def test_configured_language_pins_prompt(self):
|
||||
mock_response = MagicMock()
|
||||
mock_response.choices = [MagicMock()]
|
||||
mock_response.choices[0].message.content = "Some Title"
|
||||
|
||||
with (
|
||||
patch("agent.title_generator.call_llm", return_value=mock_response) as llm,
|
||||
patch("agent.title_generator._title_language", return_value="Japanese"),
|
||||
):
|
||||
generate_title("hello", "hi")
|
||||
|
||||
system_prompt = llm.call_args.kwargs["messages"][0]["content"]
|
||||
assert "Write the title in Japanese" in system_prompt
|
||||
assert "same language the user" not in system_prompt
|
||||
|
||||
def test_title_language_reads_config(self):
|
||||
cfg = {"auxiliary": {"title_generation": {"language": " French "}}}
|
||||
|
||||
with patch("hermes_cli.config.load_config", return_value=cfg):
|
||||
assert _title_language() == "French"
|
||||
with patch("hermes_cli.config.load_config", return_value={}):
|
||||
assert _title_language() == ""
|
||||
with patch("hermes_cli.config.load_config", side_effect=RuntimeError("bad config")):
|
||||
assert _title_language() == ""
|
||||
|
||||
def test_strips_quotes(self):
|
||||
mock_response = MagicMock()
|
||||
mock_response.choices = [MagicMock()]
|
||||
|
|
|
|||
|
|
@ -1007,6 +1007,16 @@ auxiliary:
|
|||
compression:
|
||||
timeout: 120 # seconds — compression summarizes long conversations, needs more time
|
||||
|
||||
# Auto-generated session titles. Empty language follows the conversation;
|
||||
# set e.g. "English" or "Japanese" to pin titles to one language.
|
||||
title_generation:
|
||||
provider: "auto"
|
||||
model: ""
|
||||
base_url: ""
|
||||
api_key: ""
|
||||
timeout: 30
|
||||
language: ""
|
||||
|
||||
# Skills hub — skill matching and search
|
||||
skills_hub:
|
||||
provider: "auto"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue