120 lines
4.9 KiB
Python
120 lines
4.9 KiB
Python
from app.config.ai_prompt_registry import (
|
|
PROMPT_REGISTRY_MAP,
|
|
PROMPT_FAMILY_ALLOWED,
|
|
get_prompt_registry,
|
|
get_prompt_registry_entry,
|
|
iter_prompt_registry_keys,
|
|
)
|
|
from app.config.ai_prompts import (
|
|
PROMPT_DECOMPOSE_TASKS,
|
|
PROMPT_FEISHU_PROJECT_SIGNAL_CLASSIFICATION,
|
|
PROMPT_FEISHU_REQUIREMENT_ANALYSIS,
|
|
PROMPT_SAVED_IDEA_ENRICHMENT,
|
|
PROMPT_TASK_BREAKDOWN,
|
|
)
|
|
from app.config.ai_prompts_catalog import __all__ as PROMPT_CATALOG_EXPORTS
|
|
|
|
|
|
def test_prompt_registry_covers_all_catalog_exports() -> None:
|
|
catalog_keys = set(PROMPT_CATALOG_EXPORTS)
|
|
registry_keys = set(iter_prompt_registry_keys())
|
|
|
|
assert catalog_keys.issubset(registry_keys)
|
|
assert set(PROMPT_REGISTRY_MAP) == registry_keys
|
|
|
|
for key in catalog_keys:
|
|
entry = get_prompt_registry_entry(key)
|
|
assert entry is not None
|
|
assert entry["prompt_key"] == key
|
|
assert entry["prompt_family"] in PROMPT_FAMILY_ALLOWED
|
|
assert entry["responsibility_scope"]
|
|
assert entry["priority"] in {"high", "medium", "low"}
|
|
assert entry["audience"]
|
|
assert entry["editable_policy"]
|
|
assert entry["runtime_source"]
|
|
assert entry["risk_level"] in {"critical", "high", "medium", "low"}
|
|
|
|
|
|
def test_prompt_registry_returns_detached_copies() -> None:
|
|
registry = get_prompt_registry()
|
|
original_key = registry[0]["prompt_key"]
|
|
|
|
registry[0]["prompt_key"] = "BROKEN_KEY"
|
|
|
|
assert PROMPT_REGISTRY_MAP[original_key]["prompt_key"] == original_key
|
|
|
|
|
|
def test_high_frequency_registry_entries_have_complete_metadata() -> None:
|
|
expected_families = {
|
|
"PROMPT_FEISHU_PROJECT_SIGNAL_CLASSIFICATION": "classification",
|
|
"PROMPT_FEISHU_LEVEL_CLASSIFICATION": "classification",
|
|
"PROMPT_FEISHU_SIGNAL_EXTRACTION": "extraction",
|
|
"PROMPT_FEISHU_TASK_ORCHESTRATION": "planning",
|
|
"PROMPT_SIGNAL_PLANNER": "planning",
|
|
"PROMPT_GENERATE_CHARTER": "planning",
|
|
"PROMPT_DECOMPOSE_TASKS": "planning",
|
|
"PROMPT_PROJECT_STATUS_QA": "response",
|
|
"PROMPT_MEMBER_WORKLOAD_QA": "response",
|
|
"PROMPT_AI_PMO_QA": "response",
|
|
"PROMPT_EXTERNAL_TREND_QA": "response",
|
|
"PROMPT_INDUSTRY_TREND_QA": "response",
|
|
}
|
|
|
|
for prompt_key, family in expected_families.items():
|
|
entry = get_prompt_registry_entry(prompt_key)
|
|
assert entry is not None
|
|
assert entry["module"]
|
|
assert entry["business_scenario"]
|
|
assert entry["input_contract"]
|
|
assert entry["output_contract"]
|
|
assert isinstance(entry["call_sites"], tuple)
|
|
assert entry["call_sites"], prompt_key
|
|
assert entry["prompt_family"] == family
|
|
assert entry["responsibility_scope"]
|
|
|
|
signal_planner_entry = get_prompt_registry_entry("PROMPT_SIGNAL_PLANNER")
|
|
assert signal_planner_entry is not None
|
|
assert "charter_json" in signal_planner_entry["input_contract"]
|
|
assert any("mixin_prompt.py" in site for site in signal_planner_entry["call_sites"])
|
|
assert any("mixin_analyze.py" in site for site in signal_planner_entry["call_sites"])
|
|
assert "规划" in signal_planner_entry["responsibility_scope"]
|
|
|
|
|
|
def test_deprecated_prompt_aliases_point_to_canonical_prompts() -> None:
|
|
registry_keys = set(iter_prompt_registry_keys())
|
|
|
|
assert "PROMPT_FEISHU_REQUIREMENT_ANALYSIS" not in registry_keys
|
|
assert "PROMPT_TASK_BREAKDOWN" not in registry_keys
|
|
assert PROMPT_FEISHU_REQUIREMENT_ANALYSIS == PROMPT_FEISHU_PROJECT_SIGNAL_CLASSIFICATION
|
|
assert PROMPT_TASK_BREAKDOWN == PROMPT_DECOMPOSE_TASKS
|
|
|
|
|
|
def test_prompt_registry_includes_runtime_guardrails_and_inline_inventory() -> None:
|
|
expected = {
|
|
"PMFLOW_SEMANTIC_CONTEXT_DECISION_PROMPT": "guarded_release",
|
|
"PROMPT_RAG_QUERY_SEMANTICS": "guarded_release",
|
|
"PROMPT_INTERNAL_TARGET_RESOLUTION": "guarded_release",
|
|
"PROMPT_EXTERNAL_QUERY_PLAN": "guarded_release",
|
|
"PROMPT_SEMANTIC_FACT_EXTRACT_PROJECT": "guarded_release",
|
|
"PROMPT_SIGNAL_WEBPAGE_VALUE_ANALYSIS": "needs_migration",
|
|
"PROMPT_AUDIT_FUNCTIONALITY_REVIEW": "needs_migration",
|
|
"PROMPT_LLM_STRUCTURED_JSON_REPAIR": "needs_migration",
|
|
}
|
|
|
|
for prompt_key, editable_policy in expected.items():
|
|
entry = get_prompt_registry_entry(prompt_key)
|
|
assert entry is not None
|
|
assert entry["editable_policy"] == editable_policy
|
|
assert entry["call_sites"]
|
|
|
|
|
|
def test_saved_idea_enrichment_prompt_covers_non_idea_greeting_input() -> None:
|
|
entry = get_prompt_registry_entry("PROMPT_SAVED_IDEA_ENRICHMENT")
|
|
|
|
assert entry is not None
|
|
assert any("space_saved_idea_service.py" in site for site in entry["call_sites"])
|
|
assert "问候" in entry["input_contract"]
|
|
assert "问候" in PROMPT_SAVED_IDEA_ENRICHMENT
|
|
assert "readiness_score 输出 0.0" in PROMPT_SAVED_IDEA_ENRICHMENT
|
|
assert "这个想法具体想解决什么问题?" in PROMPT_SAVED_IDEA_ENRICHMENT
|