fix(exploration): flatten dict reply payloads instead of storing str(dict)
E2E on t480 showed assistant bubbles rendering {'content': '...'} because
tutu replies carry msgBody as a parsed object and the router stored
str(reply.content). Coerce to the inner text before persisting.
This commit is contained in:
parent
958cefc380
commit
9abf572949
@ -10,6 +10,7 @@ with 409 plus a readable reason, so the rejection itself is feedback to the
|
|||||||
resident agent.
|
resident agent.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@ -61,6 +62,20 @@ class CloseSessionRequest(BaseModel):
|
|||||||
experience: dict[str, Any]
|
experience: dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
def _coerce_reply_text(content: Any) -> str:
|
||||||
|
"""Flatten a reply payload to text; tutu returns msgBody as a parsed object, and str(dict) would leak a Python repr into the view."""
|
||||||
|
if isinstance(content, str):
|
||||||
|
return content
|
||||||
|
if isinstance(content, dict):
|
||||||
|
for key in ("content", "text", "message"):
|
||||||
|
value = content.get(key)
|
||||||
|
if isinstance(value, str) and value:
|
||||||
|
return value
|
||||||
|
if content is None:
|
||||||
|
return ""
|
||||||
|
return json.dumps(content, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
def _check_creation_guardrails(
|
def _check_creation_guardrails(
|
||||||
campaign: Campaign,
|
campaign: Campaign,
|
||||||
triggered_by: ExplorationTrigger,
|
triggered_by: ExplorationTrigger,
|
||||||
@ -283,7 +298,7 @@ async def send_session_message(
|
|||||||
|
|
||||||
received_at = utc_now()
|
received_at = utc_now()
|
||||||
latency_ms = int((received_at - sent_at).total_seconds() * 1000)
|
latency_ms = int((received_at - sent_at).total_seconds() * 1000)
|
||||||
reply_text = str(reply.content)
|
reply_text = _coerce_reply_text(reply.content)
|
||||||
message_repo.save_message(
|
message_repo.save_message(
|
||||||
ExplorationMessage(
|
ExplorationMessage(
|
||||||
session_id=session_obj.id,
|
session_id=session_obj.id,
|
||||||
|
|||||||
@ -175,6 +175,37 @@ async def test_full_lifecycle_create_message_close(seeded_db, mock_channel, clie
|
|||||||
assert closed["closed_at"] is not None
|
assert closed["closed_at"] is not None
|
||||||
|
|
||||||
|
|
||||||
|
async def test_dict_reply_content_is_flattened_to_text(seeded_db, monkeypatch, client):
|
||||||
|
"""通道回复 content 为对象(如 tutu msgBody)时应提取文本而非存 str(dict)。"""
|
||||||
|
from agenteval.channels.base import Reply
|
||||||
|
from tests.unit.mock_channel import MockChannel
|
||||||
|
|
||||||
|
class _DictReplyChannel(MockChannel):
|
||||||
|
async def poll_reply(self, question_msg_id, timeout=30.0, poll_interval=1.0):
|
||||||
|
return Reply(
|
||||||
|
question_msg_id=question_msg_id,
|
||||||
|
content={"content": "您好,我是客服"},
|
||||||
|
raw_message={},
|
||||||
|
)
|
||||||
|
|
||||||
|
_stub_channel_factory(monkeypatch, _DictReplyChannel(reply_text="unused"))
|
||||||
|
|
||||||
|
resp = await _create_session(client)
|
||||||
|
assert resp.status_code == 200, resp.text
|
||||||
|
session_id = resp.json()["id"]
|
||||||
|
|
||||||
|
resp = await client.post(
|
||||||
|
f"/api/exploration/sessions/{session_id}/messages",
|
||||||
|
json={"content": "你好"},
|
||||||
|
)
|
||||||
|
assert resp.status_code == 200, resp.text
|
||||||
|
assert resp.json()["reply"] == "您好,我是客服"
|
||||||
|
|
||||||
|
messages_resp = await client.get(f"/api/exploration/sessions/{session_id}/messages")
|
||||||
|
assistant = [m for m in messages_resp.json()["messages"] if m["role"] == "assistant"]
|
||||||
|
assert assistant[0]["content"] == "您好,我是客服"
|
||||||
|
|
||||||
|
|
||||||
async def test_create_requires_existing_running_campaign(seeded_db, client):
|
async def test_create_requires_existing_running_campaign(seeded_db, client):
|
||||||
resp = await _create_session(client, campaign_id="nope")
|
resp = await _create_session(client, campaign_id="nope")
|
||||||
assert resp.status_code == 404
|
assert resp.status_code == 404
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user