code-agent: rework issue 6

Review-ID: 36
Previous-SHA: 14302a26f9
Plan-SHA256: db38eaf9d5fcf09a0a9d62f44c373eb67bfd6fcffdc40fef5f67762f0d28c477
Bundle-SHA256: 29ce1ef1917864f79938459725201e6e74d67e21b1f817ac53d7b294eca8f1a2
This commit is contained in:
code-agent
2000-01-01 00:00:00 +00:00
parent 14302a26f9
commit d102c02bc1
2 changed files with 44 additions and 7 deletions
+7 -4
View File
@@ -116,17 +116,20 @@ class ChatApp(App[None]):
self.messages.extend((user_message, agent_message)) self.messages.extend((user_message, agent_message))
conversation = self.query_one("#conversation", VerticalScroll) conversation = self.query_one("#conversation", VerticalScroll)
self._mount_message(conversation, user_message, "user-message") self._mount_message(conversation, user_message)
self._mount_message(conversation, agent_message, "response-message") self._mount_message(conversation, agent_message)
conversation.scroll_end(animate=False) conversation.scroll_end(animate=False)
@staticmethod @staticmethod
def _mount_message( def _mount_message(
conversation: VerticalScroll, conversation: VerticalScroll,
message: ChatMessage, message: ChatMessage,
style_class: str,
) -> None: ) -> None:
"""메시지 역할을 라벨과 호환 가능한 구조적 스타일로 변환한다.""" """메시지 역할에서 라벨과 구조적 스타일을 일관되게 파생한다."""
style_class = {
MessageRole.USER: "user-message",
MessageRole.AGENT: "response-message",
}[message.role]
text = f"{message.role.label}: {message.content}" text = f"{message.role.label}: {message.content}"
conversation.mount( conversation.mount(
Label(text, classes=f"chat-message {style_class} {message.role.value}-role") Label(text, classes=f"chat-message {style_class} {message.role.value}-role")
+37 -3
View File
@@ -1,7 +1,7 @@
import unittest import unittest
from unittest.mock import patch from unittest.mock import patch
from textual.widgets import Input, Label from textual.widgets import Input
from chat_tui.app import ( from chat_tui.app import (
RESPONSE_MESSAGES, RESPONSE_MESSAGES,
@@ -78,13 +78,46 @@ class ChatAppTest(unittest.IsolatedAsyncioTestCase):
labels[1].classes, labels[1].classes,
frozenset({"chat-message", "response-message", "agent-role"}), frozenset({"chat-message", "response-message", "agent-role"}),
) )
self.assertIn("사용자:", str(labels[0].renderable)) self.assertEqual(
self.assertIn("에이전트:", str(labels[1].renderable)) str(labels[0].renderable),
"사용자: 역할 확인",
)
self.assertEqual(
str(labels[1].renderable),
f"에이전트: {RESPONSE_MESSAGES[0]}",
)
self.assertIn("border-left", app.CSS) self.assertIn("border-left", app.CSS)
self.assertIn("border-right", app.CSS) self.assertIn("border-right", app.CSS)
self.assertIn("align: left middle", app.CSS) self.assertIn("align: left middle", app.CSS)
self.assertIn("align: right middle", app.CSS) self.assertIn("align: right middle", app.CSS)
async def test_rendering_styles_are_derived_from_message_roles(self) -> None:
app = ChatApp()
async with app.run_test() as pilot:
conversation = app.query_one("#conversation")
app._mount_message(
conversation,
ChatMessage(MessageRole.USER, "사용자 본문"),
)
app._mount_message(
conversation,
ChatMessage(MessageRole.AGENT, "에이전트 본문"),
)
await pilot.pause()
labels = list(app.query("#conversation Label"))
self.assertEqual(len(labels), 2)
self.assertEqual(
labels[0].classes,
frozenset({"chat-message", "user-message", "user-role"}),
)
self.assertEqual(
labels[1].classes,
frozenset({"chat-message", "response-message", "agent-role"}),
)
self.assertEqual(str(labels[0].renderable), "사용자: 사용자 본문")
self.assertEqual(str(labels[1].renderable), "에이전트: 에이전트 본문")
async def test_response_selection_uses_standard_random_choice(self) -> None: async def test_response_selection_uses_standard_random_choice(self) -> None:
app = ChatApp() app = ChatApp()
with patch( with patch(
@@ -112,6 +145,7 @@ class ChatAppTest(unittest.IsolatedAsyncioTestCase):
self.assertEqual(app.selected_responses, []) self.assertEqual(app.selected_responses, [])
self.assertEqual(app.messages, []) self.assertEqual(app.messages, [])
self.assertEqual(len(app.query("#conversation Label")), 0) self.assertEqual(len(app.query("#conversation Label")), 0)
self.assertEqual(input_widget.value, "")
choice_mock.assert_not_called() choice_mock.assert_not_called()
async def test_empty_input_is_not_added(self) -> None: async def test_empty_input_is_not_added(self) -> None: