d = agent.run(makerequest(history=[USER], models=hermes.models), {})
The examples violated the battery contract in three ways (unconditional finished=True, no history echo, no session tracking). The fix mirrors echo.py conventions exactly, so any template copied from them stays compliant.
examples/minimal.py — fixed (the template contract):
class MinimalAgent:
def run(self, req, session_info=None) -> Decision:
history = list(req.context.history) # 1. echo on EVERY decision
content = history[-1].get("content", "") if history else ""
return Decision(
content=content,
finished=not ("do not finish" in content), # 2. derived, never unconditional
history=history, # (fresh copy, not aliased)
)
def main():
router = Router(MinimalAgent()) # 3. session tracking via Router
session_id = router.new_session() # _sessions + get_session_info
return router, session_id
examples/langchain_agent.py — same plus the models guard:
class LangChainAgent:
def run(self, req, session_info=None) -> Decision:
history = list(req.context.history)
content = history[-1].get("content", "") if history else ""
finished = not ("do not finish" in content)
if not req.context.models: # empty-context.models guard:
return Decision(content=content, finished=finished,
history=history, kind=DecisionKind.TEXT) # TEXT fallback
return Decision(content=content, finished=finished,
history=history, kind=DecisionKind.LLM_CALL,
model=req.context.models[0]) # only reachable with models set
Router session tracking (unknown id ⇒ 404):
class Router:
def __init__(self, agent):
self._agent = agent
self._sessions: dict[str, dict] = {}
def get_session_info(self, session_id): # None for unknown ids
return self._sessions.get(session_id)
def handle(self, req):
info = self.get_session_info(req.session_id)
if info is None:
return 404, None # router 404s unknown sessions
info["turns"] += 1
info["messages"] = list(req.context.history)
return 200, self._agent.run(req, info)
Test-harness gotcha fix — Context.models defaults to [] and MockHermes never set it, so LLM_CALL assertions were unreachable. MockHermes gained a backward-compatible optional models arg (and the test helper passes it through):
class MockHermes:
def __init__(self, models=None, responses=None): # optional arg: omitted => []
self.models = list(models or []) # legacy MockHermes() unchanged
...
# tests asserting LLM_CALL now construct the context with models:
hermes = MockHermes(models=["hermes-3"])
d = agent.run(make_request(history=[USER], models=hermes.models), {})
assert d.kind == DecisionKind.LLM_CALL
Health version — _version.py is a zero-import leaf module (single source); the harness imports it directly so __init__ (which pulls in core → examples) can never cycle:
# _version.py (no imports — single source of truth)
__version__ = "0.4.0"
VERSION = tuple(int(p) for p in __version__.split("."))
# harness.py — imports the leaf, NOT the package __init__
from h3_sdk_python._version import __version__
def health(): return {"status": "ok", "version": __version__}
Reproduced the SDK and battery from the spec, ran `pytest` on Python 3.14 / pytest 9.0.2: **22 passed, exit 0**. - **Conventions per agent** (echo, minimal, langchain_agent, 3× each): `finished` is `False` for `"please do not finish"`, `True` for plain content; `history == list(req.context.history)` echoed on every Decision as a non-aliased copy; empty-history decisions still carry `history == []` (not `None`). - **Session tracking**: unknown id → `get_session_info is None` → router `404`; known session → `200`, `turns` increments across turns, `messages` snapshots the full history per turn. - **The models gotcha**: `Context().models == []` and `MockHermes().models == []` (verified); langchain agent with no models returns `TEXT`/`model=None` — never `LLM_CALL`; with `MockHermes(models=["hermes-3"])` the decision is `LLM_CALL` on `"hermes-3"`. - **Version/cycle**: `pkg.__version__ == _version.__version__ == health()["version"]`; a clean subprocess imports `_version` + `harness` directly with no ImportError (the `__init__` cycle is avoided). - **Edge cases**: multi-turn history echo; decision aliasing check (`d.history is not req.context.history`); two independent sessions on one router; backward-compat of `MockHermes()` with zero args. - **Discriminating power**: (a) legacy templates (unconditional `finished=True`, `history=None`) are rejected by the battery — `pytest.raises(AssertionError)` around the same contract assertions; (b) mutation test — reintroducing `finished=True` into the fixed `minimal.py` made exactly 2 minimal-specific checks fail (`2 failed, 20 passed`), proving the battery detects the original defect.
{"model": "deepseek-v4-flash", "problem_class": "python-sdk-example-battery-compliance", "result": "passed", "tests": 22}