Skip to content

Commit 2be207c

Browse files
fix: Improve agent display name formatting and add unit tests
1 parent 0857fff commit 2be207c

2 files changed

Lines changed: 59 additions & 19 deletions

File tree

src/backend/callbacks/response_handlers.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ def format_agent_display_name(raw_name: str) -> str:
2121
"""Convert raw agent IDs (e.g. 'HRHelperAgent', 'hr_helper_agent') to
2222
human-readable display names (e.g. 'HR Helper Agent').
2323
24-
Mirrors the frontend's getAgentDisplayName logic so names are consistent
25-
across the AI Thinking buffer and agent message headers.
24+
Applies similar splitting/casing logic as the frontend's
25+
``cleanTextToSpaces`` + ``getAgentDisplayName`` pipeline, but does NOT
26+
strip the "Agent" suffix (the frontend handles that separately).
2627
"""
2728
if not raw_name:
2829
return "Assistant"
@@ -33,7 +34,7 @@ def format_agent_display_name(raw_name: str) -> str:
3334
name = name.replace("_", " ")
3435

3536
# Insert space before each uppercase letter preceded by a lowercase letter
36-
# e.g. "HRHelperAgent" → "H R Helper Agent" (handled next)
37+
# e.g. "HelperAgent" → "Helper Agent"
3738
name = re.sub(r'([a-z])([A-Z])', r'\1 \2', name)
3839

3940
# Insert space between consecutive uppercase and an uppercase+lowercase pair
@@ -46,11 +47,11 @@ def format_agent_display_name(raw_name: str) -> str:
4647
# Title-case each word
4748
name = name.title()
4849

49-
# Fix common acronyms back to uppercase
50-
for acronym in ['Hr', 'It', 'Ai', 'Api', 'Ui', 'Db', 'Kb']:
51-
name = name.replace(acronym, acronym.upper())
52-
# Fix double-uppercase replacements (e.g. "HRR" from "Hrr")
53-
name = name.replace('HRR', 'HR R').replace('ITT', 'IT T')
50+
# Fix common acronyms back to uppercase (word-boundary safe)
51+
_ACRONYMS = {'Hr': 'HR', 'It': 'IT', 'Ai': 'AI', 'Api': 'API',
52+
'Ui': 'UI', 'Db': 'DB', 'Kb': 'KB'}
53+
for title_form, upper_form in _ACRONYMS.items():
54+
name = re.sub(rf'\b{title_form}\b', upper_form, name)
5455

5556
return name
5657

src/tests/backend/callbacks/test_response_handlers.py

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ def __init__(self, text="", role="assistant", author_name=""):
134134
from backend.callbacks.response_handlers import (
135135
_extract_tool_calls_from_contents, _is_function_call_item,
136136
agent_response_callback, clean_citations,
137+
format_agent_display_name,
137138
streaming_agent_response_callback)
138139

139140
# Access mocked modules that we'll use in tests
@@ -216,7 +217,45 @@ def test_clean_citations_preserves_formatting(self):
216217
assert clean_citations(text) == expected
217218

218219

219-
class TestIsFunctionCallItem:
220+
class TestFormatAgentDisplayName:
221+
"""Tests for the format_agent_display_name function."""
222+
223+
def test_empty_string_returns_assistant(self):
224+
assert format_agent_display_name("") == "Assistant"
225+
226+
def test_none_returns_assistant(self):
227+
assert format_agent_display_name(None) == "Assistant"
228+
229+
def test_pascal_case(self):
230+
assert format_agent_display_name("ContentAgent") == "Content Agent"
231+
232+
def test_snake_case(self):
233+
assert format_agent_display_name("content_agent") == "Content Agent"
234+
235+
def test_acronym_prefix(self):
236+
assert format_agent_display_name("HRHelperAgent") == "HR Helper Agent"
237+
238+
def test_acronym_word_boundary_no_false_positive(self):
239+
"""Ensure 'It' inside 'Habit' is NOT replaced with 'IT'."""
240+
assert format_agent_display_name("HabitAgent") == "Habit Agent"
241+
242+
def test_multiple_acronyms(self):
243+
assert format_agent_display_name("AIApiAgent") == "AI API Agent"
244+
245+
def test_already_spaced(self):
246+
assert format_agent_display_name("Content Agent") == "Content Agent"
247+
248+
def test_single_word(self):
249+
assert format_agent_display_name("Triage") == "Triage"
250+
251+
def test_mixed_case_id(self):
252+
assert format_agent_display_name("agent_123") == "Agent 123"
253+
254+
def test_consecutive_uppercase(self):
255+
assert format_agent_display_name("DBAdmin") == "DB Admin"
256+
257+
258+
220259
"""Tests for the _is_function_call_item function."""
221260

222261
def test_is_function_call_item_none(self):
@@ -415,7 +454,7 @@ def test_agent_response_callback_with_chat_message(self, mock_time, mock_create_
415454

416455
# Verify AgentMessage was created with cleaned text
417456
mock_agent_message.assert_called_once_with(
418-
agent_name="TestAgent",
457+
agent_name="Test Agent",
419458
timestamp=1234567890.0,
420459
content="Test message with citations "
421460
)
@@ -445,7 +484,7 @@ def test_agent_response_callback_fallback_message(self, mock_time, mock_create_t
445484

446485
# Verify AgentMessage was created with agent_id as agent_name
447486
mock_agent_message.assert_called_once_with(
448-
agent_name="agent_123",
487+
agent_name="Agent 123",
449488
timestamp=1234567890.0,
450489
content="Fallback message text"
451490
)
@@ -469,7 +508,7 @@ def test_agent_response_callback_no_text_attribute(self, mock_time, mock_create_
469508

470509
# Verify AgentMessage was created with empty content
471510
mock_agent_message.assert_called_once_with(
472-
agent_name="TestAgent",
511+
agent_name="Test Agent",
473512
timestamp=1234567890.0,
474513
content=""
475514
)
@@ -515,7 +554,7 @@ def test_agent_response_callback_successful_logging(self, mock_time, mock_create
515554
call_args = mock_logger.info.call_args[0]
516555
assert call_args[0] == "%s message (agent=%s): %s"
517556
assert call_args[1] == "Assistant"
518-
assert call_args[2] == "TestAgent"
557+
assert call_args[2] == "Test Agent"
519558
assert len(call_args[3]) == 193 # Message should be the actual length (not truncated in this case)
520559

521560

@@ -547,7 +586,7 @@ async def test_streaming_callback_with_text(self):
547586

548587
# Verify AgentMessageStreaming was created with cleaned text
549588
mock_streaming.assert_called_once_with(
550-
agent_name="agent_123",
589+
agent_name="Agent 123",
551590
content="Test streaming text ",
552591
is_final=True
553592
)
@@ -587,7 +626,7 @@ async def test_streaming_callback_no_text_with_contents(self):
587626

588627
# Verify AgentMessageStreaming was created with concatenated content text
589628
mock_streaming.assert_called_once_with(
590-
agent_name="agent_123",
629+
agent_name="Agent 123",
591630
content="Content from content attribute",
592631
is_final=False
593632
)
@@ -640,7 +679,7 @@ async def test_streaming_callback_with_tool_calls(self):
640679
await streaming_agent_response_callback("agent_123", mock_update, False, user_id="user_456")
641680

642681
# Verify tool message was created and sent
643-
mock_tool_message.assert_called_once_with(agent_name="agent_123")
682+
mock_tool_message.assert_called_once_with(agent_name="Agent 123")
644683
# Verify tool_calls.extend was called with our mock tool call
645684
assert mock_tool_call in mock_tool_msg.tool_calls or mock_tool_msg.tool_calls.extend.called # type: ignore[union-attr] # noqa: E1101 # pylint: disable=no-member
646685

@@ -666,7 +705,7 @@ async def test_streaming_callback_no_contents_attribute(self):
666705

667706
# Should still process the text
668707
mock_streaming.assert_called_once_with(
669-
agent_name="agent_123",
708+
agent_name="Agent 123",
670709
content="Test text",
671710
is_final=True
672711
)
@@ -733,7 +772,7 @@ async def test_streaming_callback_tool_calls_functionality(self):
733772
await streaming_agent_response_callback("agent_123", mock_update, False, user_id="user_456")
734773

735774
# Verify tool message was created and tool calls were processed
736-
mock_tool_message.assert_called_once_with(agent_name="agent_123")
775+
mock_tool_message.assert_called_once_with(agent_name="Agent 123")
737776
assert connection_config.send_status_update_async.called
738777

739778
@pytest.mark.asyncio
@@ -751,7 +790,7 @@ async def test_streaming_callback_chunk_processing(self):
751790

752791
# Verify streaming message was created with correct parameters
753792
mock_streaming.assert_called_once_with(
754-
agent_name="agent_123",
793+
agent_name="Agent 123",
755794
content="Test streaming text for processing",
756795
is_final=True
757796
)

0 commit comments

Comments
 (0)