feat: 吸收上游 7 个测试文件断言与 placeholder 配置化对齐

上游 ai-kefu → phase1 吸收(Task 11 unit 12):
- 拷入 7 个测试文件,import/夹具按目标库重锚(app.engine.* / conftest
  async_db+build_jiancai_runtime / seed_profiles 提示词锚点)
- 补实现(同步自上游): chat_rest 服务端可信 IP(_server_ip/
  _merge_client_info,直连场景自报假 IP 不再原样落库);widget.js 与
  chat.js 的 data-placeholder 读取(叠加 Task 10 管道:data-* > brand >
  中性兜底,tests/test_placeholder_static.py 守卫)
- 断言重锚以 jc 主线为准: ev.contact_info 存裸号+等待尾注(e164 走
  _cc 派生)、source 值 fallback/customer_stated 口径、推送标注键
  号码补全说明、prompt 静态锚按租户(seed_profiles)双测
- 全量回归 459 passed(基线 421 + 吸收 38)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-10-12 23:19:02 +08:00
parent 7697673a3b
commit d1aed8e722
10 changed files with 880 additions and 7 deletions
+20 -5
View File
@@ -33,6 +33,23 @@ class SessionRequest(BaseModel):
client_info: dict | None = None
def _server_ip(request: Request) -> str:
"""服务端可信 IP:XFF 第一段优先,否则直连 host;全空返回空串。
同步自上游 ai-kefu(app/api/routes/chat_rest.py):REST 路径原先只在有
XFF 时覆盖自报 ip,直连(无代理)场景自报假 IP 原样落库。"""
xff = request.headers.get("x-forwarded-for", "").split(",")[0].strip()
return xff or (request.client.host if request.client else "")
def _merge_client_info(client_info: dict | None, server_ip: str) -> dict:
"""服务端 IP 覆盖自报 ip 键;服务端为空时保留自报(空串不得冲掉客户端值)。"""
merged = dict(client_info or {})
if server_ip:
merged["ip"] = server_ip
return merged
@router.post("/session")
async def chat_session(req: SessionRequest, request: Request):
"""Resume an active conversation by session_id, or create a new app one.
@@ -41,11 +58,9 @@ async def chat_session(req: SessionRequest, request: Request):
`raw_info` (only when non-None). `client_info` is stored for analytics only
(ip/ua/device-id/lang) and never fed to the AI prompt.
"""
# 服务端 XFF 优先于客户端自报 ip(客户端自报可伪造,可伪造面最小)
xf = request.headers.get("x-forwarded-for", "").split(",")[0].strip()
client_info = dict(req.client_info or {})
if xf:
client_info["ip"] = xf
# 服务端可信 IP 同步自上游 ai-kefu:XFF 第一段优先,无 XFF 用直连 host
# 覆盖客户端自报(可伪造面最小);全空保留自报。?site= 处理不变。
client_info = _merge_client_info(req.client_info, _server_ip(request))
# Task 10: ?site=<slug> 记入 client_info 作会话站点标(与 WS init 的
# site 字段同语义)——只加记录,不参与业务逻辑