強化 EA JSON fallback 與 EDM cache 自癒
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
This commit is contained in:
@@ -316,6 +316,31 @@ def test_promo_dashboard_shared_cache_ignores_other_versions(tmp_path, monkeypat
|
||||
assert edm_routes._load_shared_promo_dashboard_cache(cache_key) is None
|
||||
|
||||
|
||||
def test_promo_dashboard_shared_cache_discards_corrupt_payload(tmp_path, monkeypatch):
|
||||
from routes import edm_routes
|
||||
|
||||
shared_cache = tmp_path / "promo_dashboard_cache.pkl"
|
||||
shared_cache.write_bytes(b"\x96not-a-pickle")
|
||||
monkeypatch.setattr(edm_routes, "_PROMO_SHARED_CACHE_FILE", shared_cache)
|
||||
|
||||
assert edm_routes._load_shared_promo_dashboard_cache(("edm",)) is None
|
||||
assert not shared_cache.exists()
|
||||
|
||||
|
||||
def test_promo_dashboard_shared_cache_write_recovers_from_corrupt_payload(tmp_path, monkeypatch):
|
||||
from routes import edm_routes
|
||||
|
||||
shared_cache = tmp_path / "promo_dashboard_cache.pkl"
|
||||
shared_cache.write_bytes(b"\x96not-a-pickle")
|
||||
cache_key = ("edm", "default", "desc", "", "bucket", (1, "ts", 1))
|
||||
data = {"items_in_batch": [{"sku": "SKU-1"}]}
|
||||
monkeypatch.setattr(edm_routes, "_PROMO_SHARED_CACHE_FILE", shared_cache)
|
||||
|
||||
edm_routes._write_shared_promo_dashboard_cache(cache_key, data)
|
||||
|
||||
assert edm_routes._load_shared_promo_dashboard_cache(cache_key) == data
|
||||
|
||||
|
||||
def test_sales_analysis_preview_context_cache_avoids_reloading_options(tmp_path, monkeypatch):
|
||||
from routes import sales_routes
|
||||
|
||||
|
||||
99
tests/test_elephant_alpha_orchestrator.py
Normal file
99
tests/test_elephant_alpha_orchestrator.py
Normal file
@@ -0,0 +1,99 @@
|
||||
import asyncio
|
||||
|
||||
|
||||
def test_elephant_orchestrator_extracts_fenced_json_object():
|
||||
from services.elephant_alpha_orchestrator import ElephantAlphaOrchestrator
|
||||
|
||||
payload = ElephantAlphaOrchestrator._extract_json_object(
|
||||
"""```json
|
||||
{"priority":"high","confidence":0.91}
|
||||
```"""
|
||||
)
|
||||
|
||||
assert payload == {"priority": "high", "confidence": 0.91}
|
||||
|
||||
|
||||
def test_elephant_orchestrator_extracts_json_object_from_prefaced_text():
|
||||
from services.elephant_alpha_orchestrator import ElephantAlphaOrchestrator
|
||||
|
||||
payload = ElephantAlphaOrchestrator._extract_json_object(
|
||||
'先做分析:\n{"priority":"medium","agents_required":["hermes"]}\n以上。'
|
||||
)
|
||||
|
||||
assert payload["priority"] == "medium"
|
||||
assert payload["agents_required"] == ["hermes"]
|
||||
|
||||
|
||||
def test_elephant_orchestrator_fallback_uses_concrete_evidence_without_plan():
|
||||
from services.elephant_alpha_orchestrator import ElephantAlphaOrchestrator
|
||||
|
||||
orchestrator = ElephantAlphaOrchestrator()
|
||||
decision = orchestrator._fallback_decision(
|
||||
{
|
||||
"trigger_type": "market_opportunity",
|
||||
"conditions": {
|
||||
"_prefetched_hermes_threats": [
|
||||
"[SKU-1] 測試商品|MOMO $1,200 vs PChome $990|每件價差 NT$ 210"
|
||||
]
|
||||
},
|
||||
},
|
||||
reason="測試解析失敗",
|
||||
)
|
||||
|
||||
assert decision.priority == "high"
|
||||
assert decision.confidence == 0.74
|
||||
assert decision.execution_plan == []
|
||||
assert "1 筆 DB/Hermes 價格比對實證" in decision.reasoning
|
||||
assert "自動調價" in decision.reasoning
|
||||
|
||||
|
||||
def test_elephant_orchestrator_fallback_without_evidence_has_no_openclaw_action():
|
||||
from services.elephant_alpha_orchestrator import ElephantAlphaOrchestrator
|
||||
|
||||
orchestrator = ElephantAlphaOrchestrator()
|
||||
decision = orchestrator._fallback_decision(
|
||||
{"trigger_type": "market_opportunity", "conditions": {}},
|
||||
reason="測試解析失敗",
|
||||
)
|
||||
|
||||
assert decision.confidence == 0.6
|
||||
assert decision.execution_plan == []
|
||||
assert decision.agents_required == ["elephant_alpha"]
|
||||
assert "沒有可稽核的 DB/Hermes 實證" in decision.reasoning
|
||||
|
||||
|
||||
def test_elephant_orchestrator_uses_evidence_fallback_on_non_json_response(monkeypatch):
|
||||
from services.elephant_service import ElephantResponse
|
||||
from services.elephant_alpha_orchestrator import ElephantAlphaOrchestrator
|
||||
|
||||
class FakeElephant:
|
||||
def generate(self, **_kwargs):
|
||||
return ElephantResponse(
|
||||
success=True,
|
||||
content="\n我無法輸出 JSON,但建議先處理。",
|
||||
model="fake-model",
|
||||
)
|
||||
|
||||
async def _noop_log(*_args, **_kwargs):
|
||||
raise AssertionError("parse fallback should not log an LLM decision")
|
||||
|
||||
orchestrator = ElephantAlphaOrchestrator()
|
||||
orchestrator.elephant = FakeElephant()
|
||||
monkeypatch.setattr(orchestrator, "_get_recent_performance_metrics", lambda: {})
|
||||
monkeypatch.setattr(orchestrator, "_get_agent_status", lambda: {})
|
||||
monkeypatch.setattr(orchestrator, "_get_system_load", lambda: "normal")
|
||||
monkeypatch.setattr(orchestrator, "_get_pending_actions_count", lambda: 0)
|
||||
monkeypatch.setattr(orchestrator, "_log_decision", _noop_log)
|
||||
|
||||
decision = asyncio.run(orchestrator.analyze_and_coordinate({
|
||||
"trigger_type": "price_drop_alert",
|
||||
"conditions": {
|
||||
"_prefetched_hermes_threats": [
|
||||
"[SKU-9] 實證商品|MOMO $1,000 vs PChome $800|每件價差 NT$ 200"
|
||||
]
|
||||
},
|
||||
}))
|
||||
|
||||
assert decision.priority == "high"
|
||||
assert decision.execution_plan == []
|
||||
assert "1 筆 DB/Hermes 價格比對實證" in decision.reasoning
|
||||
@@ -531,6 +531,38 @@ def test_marketplace_matcher_promotes_nivea_dry_lotion_with_long_shared_anchor()
|
||||
assert "shared_identity_anchor_nivea_dry_lotion" in diagnostics.reasons
|
||||
|
||||
|
||||
def test_marketplace_matcher_promotes_curel_body_lotion_with_brand_alias():
|
||||
from services.marketplace_product_matcher import score_marketplace_match
|
||||
|
||||
diagnostics = score_marketplace_match(
|
||||
"【Curel 珂潤】潤浸保濕清爽身體乳液 220ml",
|
||||
"珂潤 Curel 潤浸保濕清爽身體乳液220ml",
|
||||
momo_price=399,
|
||||
competitor_price=399,
|
||||
)
|
||||
|
||||
assert diagnostics.score >= 0.76
|
||||
assert diagnostics.hard_veto is False
|
||||
assert "brand_match" in diagnostics.tags
|
||||
assert "shared_identity_anchor" in diagnostics.reasons
|
||||
|
||||
|
||||
def test_marketplace_matcher_promotes_karadium_pearl_shadow_stick_anchor():
|
||||
from services.marketplace_product_matcher import score_marketplace_match
|
||||
|
||||
diagnostics = score_marketplace_match(
|
||||
"【KARADIUM】閃亮珍珠眼影棒 1.4g",
|
||||
"karadium 閃亮珍珠眼影棒 1.4g",
|
||||
momo_price=259,
|
||||
competitor_price=259,
|
||||
)
|
||||
|
||||
assert diagnostics.score >= 0.76
|
||||
assert diagnostics.hard_veto is False
|
||||
assert "brand_match" in diagnostics.tags
|
||||
assert "shared_identity_anchor" in diagnostics.reasons
|
||||
|
||||
|
||||
def test_marketplace_matcher_rejects_refill_core_vs_case_only_pack():
|
||||
from services.marketplace_product_matcher import score_marketplace_match
|
||||
|
||||
|
||||
Reference in New Issue
Block a user