Files
ai-kefu-admin/tests/test_context_seeding.py
T
浅念 e34378257f feat: PromptProvider 化 + $DEFLECTION_POOL 单一事实源注入 + runtime 必填化
- PromptProvider(app/engine/services/ai_service.py): 租户提示词四件套
  from_dir 加载;build_system 把 system.md 的 $DEFLECTION_POOL 占位符替换为
  wall.json deflections 话术池(按语言分组一行,EN/ZH/ES)再拼事实卡;
  extractor/evaluator 的 $existing_info/$messages/$profile/$recent_messages
  替换逻辑自 AIService 原样搬入(行为等价);删模块级 import 时读文件的
  PROMPTS_DIR 与四个常量,保留 DEFAULT_PROVIDER(jiancai 出厂,__file__ 锚定)
- 两租户 system.md「三类请求的处理」第2条的迂回话术枚举 → $DEFLECTION_POOL
  占位符(保留段落说明文字),话术只存 wall.json 一份,改一处两边同步变
- TenantRuntime 加 prompts 字段(加载期 from_dir(seed_dir/prompts));
  ConversationManager 的 runtime 转必填(keyword-only),默认 AIService 用
  runtime.prompts + compiled_wall.deflections 组装
- app/engine/prompts/ 删除(grep 无代码消费方,jiancai 出厂由
  seed_profiles/jiancai/prompts 承接);test_company_facts/
  test_system_prompt_dual_contact 的 cwd 相对路径改 Path(__file__) 锚定,
  test_extractor_evaluator_prompts 断言对象改 DEFAULT_PROVIDER(语义等价)
- 新增 tests/test_prompt_provider.py(14 用例): 加载/注入/格式/占位符防漂移/
  extractor-evaluator 组装/registry 接线/runtime 必填/池线过两墙

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 19:54:47 +08:00

46 lines
1.5 KiB
Python

"""Red-line: `context` injection must be CONDITIONAL + WHITELIST only.
- No `context` passed -> `raw_info` stays `{}` (widget WS path unchanged).
- `context` passed -> only `product_name`/`product_id` map to `app_*`.
"""
from sqlalchemy import select
from app.engine.models import CustomerProfile
from app.engine.services.conversation import ConversationManager
async def _raw_info_for(async_db, conv_id) -> dict:
async with async_db() as db:
result = await db.execute(
select(CustomerProfile).where(
CustomerProfile.conversation_id == conv_id
)
)
profile = result.scalar_one()
return profile.raw_info or {}
async def test_no_context_keeps_raw_info_empty(async_db, jiancai_runtime):
async with async_db() as db:
mgr = ConversationManager(db, runtime=jiancai_runtime)
conv = await mgr.create_conversation(context=None)
raw = await _raw_info_for(async_db, conv.id)
assert raw == {}
async def test_context_seeds_whitelist_only(async_db, jiancai_runtime):
async with async_db() as db:
mgr = ConversationManager(db, runtime=jiancai_runtime)
conv = await mgr.create_conversation(
context={
"product_name": "HDPE PE100 Pipe DN110",
"product_id": "p123",
"evil_key": "should_be_ignored",
}
)
raw = await _raw_info_for(async_db, conv.id)
assert raw == {
"app_product_name": "HDPE PE100 Pipe DN110",
"app_product_id": "p123",
}