feat(chat): 低信息短答主动续话;修复本地 dev 环境与迁移链

- interview_turn_plan: 识别低信息短回复,引导 AI 承接后主动追问新话题
- development.sh / docker-compose.dev: Postgres/Redis 端口与 .env 对齐,补充宿主机端口监听检查
- Alembic: 补回 0016 memory pipeline status、0017 segment narrative defer
- app-expo: api/ws URL 去掉末尾斜杠,避免 WS 双斜杠;更新 .env.staging

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Kevin
2026-05-11 12:06:17 +08:00
parent 55cfbc7f80
commit 705fe951b3
8 changed files with 427 additions and 15 deletions

View File

@@ -181,13 +181,66 @@ def test_plan_clarify_first_when_very_short():
p = plan_interview_turn(
current_stage="childhood",
empty_slots=["place"],
normalized_user_message="还好吧",
normalized_user_message="有点说不清",
memory_evidence_text="",
stage_switched_this_turn=False,
)
assert p.mode == "clarify_first"
def test_plan_low_information_reply_pushes_next_topic_when_slots_remain():
p = plan_interview_turn(
current_stage="childhood",
empty_slots=["place", "people"],
normalized_user_message="嗯。",
memory_evidence_text="",
stage_switched_this_turn=False,
)
assert p.mode == "memoir_push"
assert p.anchor_slot_key == "place"
assert p.reply_shape == "ack_then_question"
assert p.low_information_reply is True
def test_low_information_directive_asks_for_proactive_topic_not_clarification():
p = plan_interview_turn(
current_stage="childhood",
empty_slots=["place"],
normalized_user_message="",
memory_evidence_text="",
stage_switched_this_turn=False,
)
block = format_interview_turn_directive_block(p)
assert "低信息短回复处理" in block
assert "不要把这个短答本身当成需要澄清的内容" in block
assert "恰好一个" in block
assert "主动" in block
def test_plan_low_information_reply_uses_follow_when_no_slots_remain():
p = plan_interview_turn(
current_stage="childhood",
empty_slots=[],
normalized_user_message="是的",
memory_evidence_text="",
stage_switched_this_turn=False,
)
assert p.mode == "follow_user_only"
assert p.reply_shape == "ack_then_question"
assert p.low_information_reply is True
def test_short_substantive_reply_is_not_treated_as_low_information():
p = plan_interview_turn(
current_stage="childhood",
empty_slots=["place", "people"],
normalized_user_message="上海",
memory_evidence_text="",
stage_switched_this_turn=False,
)
assert p.low_information_reply is False
def test_plan_memoir_push():
p = plan_interview_turn(
current_stage="childhood",
@@ -232,3 +285,4 @@ def test_plan_follow_when_no_empty_slots():
stage_switched_this_turn=False,
)
assert p.mode == "follow_user_only"
assert p.low_information_reply is True