code-agent: rework issue 6
Review-ID: 36
Previous-SHA: 14302a26f9
Plan-SHA256: db38eaf9d5fcf09a0a9d62f44c373eb67bfd6fcffdc40fef5f67762f0d28c477
Bundle-SHA256: 29ce1ef1917864f79938459725201e6e74d67e21b1f817ac53d7b294eca8f1a2
This commit is contained in:
+7
-4
@@ -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
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user