[claude] Fix ruff S105/S106/B017/E402 errors in bannerlord (#1161) #1165
@@ -126,8 +126,7 @@ class KingAgent:
|
||||
|
||||
if victory.achieved:
|
||||
logger.info(
|
||||
"SOVEREIGN VICTORY — King of Calradia! "
|
||||
"Territory: %.1f%%, tick: %d",
|
||||
"SOVEREIGN VICTORY — King of Calradia! Territory: %.1f%%, tick: %d",
|
||||
victory.territory_control_pct,
|
||||
self._tick,
|
||||
)
|
||||
@@ -186,7 +185,7 @@ class KingAgent:
|
||||
logger.warning(
|
||||
"King LLM decision failed at tick %d: %s — defaulting to RECRUIT", self._tick, exc
|
||||
)
|
||||
return KingSubgoal(token="RECRUIT", context="LLM unavailable — safe default")
|
||||
return KingSubgoal(token="RECRUIT", context="LLM unavailable — safe default") # noqa: S106
|
||||
|
||||
def _llm_decide(self, state: dict[str, Any]) -> KingSubgoal:
|
||||
"""Synchronous Ollama call (runs in a thread via asyncio.to_thread)."""
|
||||
|
||||
@@ -76,9 +76,7 @@ class BaseVassal:
|
||||
msg = self._subgoal_queue.get_nowait()
|
||||
if msg.to_agent == self.name:
|
||||
self._active_subgoal = msg.subgoal
|
||||
logger.debug(
|
||||
"%s received subgoal %s", self.name, msg.subgoal.token
|
||||
)
|
||||
logger.debug("%s received subgoal %s", self.name, msg.subgoal.token)
|
||||
except asyncio.QueueEmpty:
|
||||
pass
|
||||
|
||||
@@ -147,10 +145,8 @@ class WarVassal(BaseVassal):
|
||||
subgoal_bonus=bonus,
|
||||
)
|
||||
|
||||
def _plan_action(
|
||||
self, state: dict[str, Any], subgoal: KingSubgoal
|
||||
) -> TaskMessage | None:
|
||||
if subgoal.token == "EXPAND_TERRITORY" and subgoal.target:
|
||||
def _plan_action(self, state: dict[str, Any], subgoal: KingSubgoal) -> TaskMessage | None:
|
||||
if subgoal.token == "EXPAND_TERRITORY" and subgoal.target: # noqa: S105
|
||||
return TaskMessage(
|
||||
from_agent=self.name,
|
||||
to_agent="logistics_companion",
|
||||
@@ -158,7 +154,7 @@ class WarVassal(BaseVassal):
|
||||
args={"destination": subgoal.target},
|
||||
priority=subgoal.priority,
|
||||
)
|
||||
if subgoal.token == "RECRUIT":
|
||||
if subgoal.token == "RECRUIT": # noqa: S105
|
||||
qty = subgoal.quantity or 20
|
||||
return TaskMessage(
|
||||
from_agent=self.name,
|
||||
@@ -167,7 +163,7 @@ class WarVassal(BaseVassal):
|
||||
args={"troop_type": "infantry", "quantity": qty},
|
||||
priority=subgoal.priority,
|
||||
)
|
||||
if subgoal.token == "TRAIN":
|
||||
if subgoal.token == "TRAIN": # noqa: S105
|
||||
return TaskMessage(
|
||||
from_agent=self.name,
|
||||
to_agent="logistics_companion",
|
||||
@@ -219,10 +215,8 @@ class EconomyVassal(BaseVassal):
|
||||
subgoal_bonus=bonus,
|
||||
)
|
||||
|
||||
def _plan_action(
|
||||
self, state: dict[str, Any], subgoal: KingSubgoal
|
||||
) -> TaskMessage | None:
|
||||
if subgoal.token == "FORTIFY" and subgoal.target:
|
||||
def _plan_action(self, state: dict[str, Any], subgoal: KingSubgoal) -> TaskMessage | None:
|
||||
if subgoal.token == "FORTIFY" and subgoal.target: # noqa: S105
|
||||
return TaskMessage(
|
||||
from_agent=self.name,
|
||||
to_agent="logistics_companion",
|
||||
@@ -230,7 +224,7 @@ class EconomyVassal(BaseVassal):
|
||||
args={"settlement": subgoal.target},
|
||||
priority=subgoal.priority,
|
||||
)
|
||||
if subgoal.token == "TRADE":
|
||||
if subgoal.token == "TRADE": # noqa: S105
|
||||
return TaskMessage(
|
||||
from_agent=self.name,
|
||||
to_agent="caravan_companion",
|
||||
@@ -282,10 +276,8 @@ class DiplomacyVassal(BaseVassal):
|
||||
subgoal_bonus=bonus,
|
||||
)
|
||||
|
||||
def _plan_action(
|
||||
self, state: dict[str, Any], subgoal: KingSubgoal
|
||||
) -> TaskMessage | None:
|
||||
if subgoal.token == "ALLY" and subgoal.target:
|
||||
def _plan_action(self, state: dict[str, Any], subgoal: KingSubgoal) -> TaskMessage | None:
|
||||
if subgoal.token == "ALLY" and subgoal.target: # noqa: S105
|
||||
return TaskMessage(
|
||||
from_agent=self.name,
|
||||
to_agent="scout_companion",
|
||||
@@ -293,7 +285,7 @@ class DiplomacyVassal(BaseVassal):
|
||||
args={"name": subgoal.target},
|
||||
priority=subgoal.priority,
|
||||
)
|
||||
if subgoal.token == "SPY" and subgoal.target:
|
||||
if subgoal.token == "SPY" and subgoal.target: # noqa: S105
|
||||
return TaskMessage(
|
||||
from_agent=self.name,
|
||||
to_agent="scout_companion",
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
"""Tests for the three-tier metabolic LLM router (issue #966)."""
|
||||
|
||||
import asyncio
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
from infrastructure.router.metabolic import (
|
||||
DEFAULT_TIER_MODELS,
|
||||
MetabolicRouter,
|
||||
@@ -16,6 +13,7 @@ from infrastructure.router.metabolic import (
|
||||
get_metabolic_router,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
# ── classify_complexity ──────────────────────────────────────────────────────
|
||||
|
||||
@@ -198,7 +196,12 @@ class TestMetabolicRouter:
|
||||
async def test_t1_uses_t1_model(self):
|
||||
mock_cascade = MagicMock()
|
||||
mock_cascade.complete = AsyncMock(
|
||||
return_value={"content": "ok", "provider": "ollama-local", "model": "qwen3:8b", "latency_ms": 100}
|
||||
return_value={
|
||||
"content": "ok",
|
||||
"provider": "ollama-local",
|
||||
"model": "qwen3:8b",
|
||||
"latency_ms": 100,
|
||||
}
|
||||
)
|
||||
router = MetabolicRouter(cascade=mock_cascade)
|
||||
await router.route("go north", state={})
|
||||
@@ -208,7 +211,12 @@ class TestMetabolicRouter:
|
||||
async def test_t2_uses_t2_model(self):
|
||||
mock_cascade = MagicMock()
|
||||
mock_cascade.complete = AsyncMock(
|
||||
return_value={"content": "ok", "provider": "ollama-local", "model": "qwen3:14b", "latency_ms": 300}
|
||||
return_value={
|
||||
"content": "ok",
|
||||
"provider": "ollama-local",
|
||||
"model": "qwen3:14b",
|
||||
"latency_ms": 300,
|
||||
}
|
||||
)
|
||||
router = MetabolicRouter(cascade=mock_cascade)
|
||||
await router.route("what should I say to the innkeeper", state={})
|
||||
@@ -218,7 +226,12 @@ class TestMetabolicRouter:
|
||||
async def test_t3_uses_t3_model(self):
|
||||
mock_cascade = MagicMock()
|
||||
mock_cascade.complete = AsyncMock(
|
||||
return_value={"content": "ok", "provider": "ollama-local", "model": "qwen3:30b", "latency_ms": 2000}
|
||||
return_value={
|
||||
"content": "ok",
|
||||
"provider": "ollama-local",
|
||||
"model": "qwen3:30b",
|
||||
"latency_ms": 2000,
|
||||
}
|
||||
)
|
||||
router = MetabolicRouter(cascade=mock_cascade)
|
||||
await router.route("plan the optimal quest route", state={})
|
||||
@@ -228,7 +241,12 @@ class TestMetabolicRouter:
|
||||
async def test_custom_tier_models_respected(self):
|
||||
mock_cascade = MagicMock()
|
||||
mock_cascade.complete = AsyncMock(
|
||||
return_value={"content": "ok", "provider": "test", "model": "custom-8b", "latency_ms": 100}
|
||||
return_value={
|
||||
"content": "ok",
|
||||
"provider": "test",
|
||||
"model": "custom-8b",
|
||||
"latency_ms": 100,
|
||||
}
|
||||
)
|
||||
custom = {ModelTier.T1_ROUTINE: "custom-8b"}
|
||||
router = MetabolicRouter(cascade=mock_cascade, tier_models=custom)
|
||||
@@ -239,7 +257,12 @@ class TestMetabolicRouter:
|
||||
async def test_t3_pauses_world_before_inference(self):
|
||||
mock_cascade = MagicMock()
|
||||
mock_cascade.complete = AsyncMock(
|
||||
return_value={"content": "ok", "provider": "ollama", "model": "qwen3:30b", "latency_ms": 1500}
|
||||
return_value={
|
||||
"content": "ok",
|
||||
"provider": "ollama",
|
||||
"model": "qwen3:30b",
|
||||
"latency_ms": 1500,
|
||||
}
|
||||
)
|
||||
router = MetabolicRouter(cascade=mock_cascade)
|
||||
|
||||
@@ -281,7 +304,12 @@ class TestMetabolicRouter:
|
||||
async def test_t1_does_not_pause_world(self):
|
||||
mock_cascade = MagicMock()
|
||||
mock_cascade.complete = AsyncMock(
|
||||
return_value={"content": "ok", "provider": "ollama", "model": "qwen3:8b", "latency_ms": 120}
|
||||
return_value={
|
||||
"content": "ok",
|
||||
"provider": "ollama",
|
||||
"model": "qwen3:8b",
|
||||
"latency_ms": 120,
|
||||
}
|
||||
)
|
||||
router = MetabolicRouter(cascade=mock_cascade)
|
||||
|
||||
@@ -297,7 +325,12 @@ class TestMetabolicRouter:
|
||||
async def test_t2_does_not_pause_world(self):
|
||||
mock_cascade = MagicMock()
|
||||
mock_cascade.complete = AsyncMock(
|
||||
return_value={"content": "ok", "provider": "ollama", "model": "qwen3:14b", "latency_ms": 350}
|
||||
return_value={
|
||||
"content": "ok",
|
||||
"provider": "ollama",
|
||||
"model": "qwen3:14b",
|
||||
"latency_ms": 350,
|
||||
}
|
||||
)
|
||||
router = MetabolicRouter(cascade=mock_cascade)
|
||||
|
||||
@@ -314,7 +347,12 @@ class TestMetabolicRouter:
|
||||
"""If world.act() raises, inference must still complete."""
|
||||
mock_cascade = MagicMock()
|
||||
mock_cascade.complete = AsyncMock(
|
||||
return_value={"content": "done", "provider": "ollama", "model": "qwen3:30b", "latency_ms": 2000}
|
||||
return_value={
|
||||
"content": "done",
|
||||
"provider": "ollama",
|
||||
"model": "qwen3:30b",
|
||||
"latency_ms": 2000,
|
||||
}
|
||||
)
|
||||
router = MetabolicRouter(cascade=mock_cascade)
|
||||
|
||||
@@ -329,7 +367,12 @@ class TestMetabolicRouter:
|
||||
async def test_no_world_adapter_t3_still_works(self):
|
||||
mock_cascade = MagicMock()
|
||||
mock_cascade.complete = AsyncMock(
|
||||
return_value={"content": "plan done", "provider": "ollama", "model": "qwen3:30b", "latency_ms": 2000}
|
||||
return_value={
|
||||
"content": "plan done",
|
||||
"provider": "ollama",
|
||||
"model": "qwen3:30b",
|
||||
"latency_ms": 2000,
|
||||
}
|
||||
)
|
||||
router = MetabolicRouter(cascade=mock_cascade)
|
||||
# No set_world() called
|
||||
@@ -347,7 +390,12 @@ class TestMetabolicRouter:
|
||||
"""Calling route without ui_state should not raise."""
|
||||
mock_cascade = MagicMock()
|
||||
mock_cascade.complete = AsyncMock(
|
||||
return_value={"content": "ok", "provider": "ollama", "model": "qwen3:8b", "latency_ms": 100}
|
||||
return_value={
|
||||
"content": "ok",
|
||||
"provider": "ollama",
|
||||
"model": "qwen3:8b",
|
||||
"latency_ms": 100,
|
||||
}
|
||||
)
|
||||
router = MetabolicRouter(cascade=mock_cascade)
|
||||
# No ui_state argument
|
||||
@@ -357,7 +405,12 @@ class TestMetabolicRouter:
|
||||
async def test_temperature_and_max_tokens_forwarded(self):
|
||||
mock_cascade = MagicMock()
|
||||
mock_cascade.complete = AsyncMock(
|
||||
return_value={"content": "ok", "provider": "ollama", "model": "qwen3:14b", "latency_ms": 200}
|
||||
return_value={
|
||||
"content": "ok",
|
||||
"provider": "ollama",
|
||||
"model": "qwen3:14b",
|
||||
"latency_ms": 200,
|
||||
}
|
||||
)
|
||||
router = MetabolicRouter(cascade=mock_cascade)
|
||||
await router.route("describe the scene", state={}, temperature=0.1, max_tokens=50)
|
||||
|
||||
@@ -15,7 +15,6 @@ from bannerlord.models import (
|
||||
WarReward,
|
||||
)
|
||||
|
||||
|
||||
# ── KingSubgoal ───────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -35,7 +34,7 @@ class TestKingSubgoal:
|
||||
KingSubgoal(token="NUKE_CALRADIA")
|
||||
|
||||
def test_priority_clamp(self):
|
||||
with pytest.raises(Exception):
|
||||
with pytest.raises(ValueError):
|
||||
KingSubgoal(token="TRADE", priority=3.0)
|
||||
|
||||
def test_optional_fields_default_none(self):
|
||||
|
||||
Reference in New Issue
Block a user