feat(ai): add guarded Claude fallback route

This commit is contained in:
ogt
2026-07-15 15:57:24 +08:00
parent f57845ba5e
commit 5c5eb48091
56 changed files with 4942 additions and 760 deletions

View File

@@ -21,6 +21,10 @@ def _explicitly_enable_gemini_environment(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("ENABLE_GEMINI", "true")
monkeypatch.setenv("ENABLE_CLAUDE", "false")
monkeypatch.setattr(openclaw_module.settings, "CLAUDE_API_KEY", "")
monkeypatch.setattr(openclaw_module.settings, "CLAUDE_EXECUTION_MODE", "shadow")
monkeypatch.setattr(openclaw_module.settings, "CLAUDE_CANARY_PERCENT", 0)
@dataclass
@@ -105,6 +109,23 @@ class _FakeExecutor:
)
def _prepared_paid_alert_context(
service: OpenClawService,
**overrides: Any,
) -> dict[str, Any]:
context = service._prepare_paid_cloud_route_context(
{
"incident_id": "INC-1",
"alertname": "HostHighCpuLoad",
"source": "test-alert-producer",
"target_resource": "node-110",
**overrides,
}
)
assert context is not None
return context
@pytest.mark.asyncio
async def test_alert_context_uses_exact_ollama_lane_then_gemini(
monkeypatch: pytest.MonkeyPatch,
@@ -290,7 +311,7 @@ async def test_alert_context_sorts_ollama_lane_and_drops_cloud_providers(
service = object.__new__(OpenClawService)
provider_order = await service._resolve_alert_provider_order(
task_type="diagnose",
alert_context={"incident_id": "INC-1", "alertname": "HostHighCpuLoad"},
alert_context=_prepared_paid_alert_context(service),
)
assert provider_order == ["ollama_gcp_a", "ollama_gcp_b", "ollama_local"]
@@ -309,13 +330,46 @@ async def test_alert_context_drops_cloud_insertions_before_gemini_backup(
service = object.__new__(OpenClawService)
provider_order = await service._resolve_alert_provider_order(
task_type="diagnose",
alert_context={"incident_id": "INC-1", "alertname": "HostHighCpuLoad"},
alert_context=_prepared_paid_alert_context(service),
cloud_provider_order=["claude", "openclaw_nemo", "gemini", "ollama"],
)
assert provider_order == ["ollama_gcp_a", "ollama_gcp_b", "ollama_local", "gemini"]
@pytest.mark.asyncio
async def test_alert_context_appends_enabled_claude_before_gemini(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(openclaw_module.settings, "ALERT_AI_ALLOW_CLOUD_FALLBACK", True)
monkeypatch.setattr(openclaw_module.settings, "ALERT_AI_ENFORCE_OLLAMA_FIRST", True)
monkeypatch.setattr(openclaw_module.settings, "CLAUDE_API_KEY", "configured-test-value")
monkeypatch.setattr(openclaw_module.settings, "CLAUDE_EXECUTION_MODE", "production")
monkeypatch.setattr(openclaw_module.settings, "CLAUDE_CANARY_PERCENT", 0)
monkeypatch.setattr(openclaw_module.settings, "GEMINI_API_KEY", "configured-test-value")
monkeypatch.setenv("ENABLE_CLAUDE", "true")
monkeypatch.setattr(ai_control_module, "is_provider_disabled", AsyncMock(return_value=False))
monkeypatch.setattr(
openclaw_module,
"get_ollama_failover_manager",
lambda: _UnorderedFailoverManager(),
)
service = object.__new__(OpenClawService)
provider_order = await service._resolve_alert_provider_order(
task_type="diagnose",
alert_context=_prepared_paid_alert_context(service),
)
assert provider_order == [
"ollama_gcp_a",
"ollama_gcp_b",
"ollama_local",
"claude",
"gemini",
]
@pytest.mark.asyncio
async def test_disabled_gemini_is_not_readded_to_alert_route(
monkeypatch: pytest.MonkeyPatch,