From c2071594cf49c96cbd7ac9f46a19d2590ef77c3e Mon Sep 17 00:00:00 2001 From: santhreal <64453045+santhreal@users.noreply.github.com> Date: Sat, 18 Jul 2026 17:24:50 -0700 Subject: [PATCH] fix(triggers): rename coerce helper to _store_int Match the cron store-load naming and cover null attempts on deliveries. --- nanobot/triggers/local_types.py | 12 ++++++------ tests/triggers/test_local_triggers.py | 12 +++++++++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/nanobot/triggers/local_types.py b/nanobot/triggers/local_types.py index bbf182af..49b1ddb2 100644 --- a/nanobot/triggers/local_types.py +++ b/nanobot/triggers/local_types.py @@ -11,7 +11,7 @@ from nanobot.utils.dict_keys import get_camel_snake as _get TriggerStatus = Literal["ok", "error"] -def _ms_int(value: Any, default: int = 0) -> int: +def _store_int(value: Any, default: int = 0) -> int: """Coerce JSON numerics to int; treat null/blank like a missing key.""" if value is None or value == "": return default @@ -29,7 +29,7 @@ class TriggerRunRecord: @classmethod def from_dict(cls, data: dict[str, Any]) -> "TriggerRunRecord": return cls( - run_at_ms=_ms_int(_get(data, "runAtMs", "run_at_ms", 0)), + run_at_ms=_store_int(_get(data, "runAtMs", "run_at_ms", 0)), status=str(data.get("status") or "error"), # type: ignore[arg-type] error=data.get("error"), ) @@ -77,8 +77,8 @@ class LocalTrigger: session_key=str(_get(data, "sessionKey", "session_key", "")), sender_id=str(_get(data, "senderId", "sender_id", "trigger") or "trigger"), origin_metadata=dict(_get(data, "originMetadata", "origin_metadata", {}) or {}), - created_at_ms=_ms_int(_get(data, "createdAtMs", "created_at_ms", 0)), - updated_at_ms=_ms_int(_get(data, "updatedAtMs", "updated_at_ms", 0)), + created_at_ms=_store_int(_get(data, "createdAtMs", "created_at_ms", 0)), + updated_at_ms=_store_int(_get(data, "updatedAtMs", "updated_at_ms", 0)), last_run_at_ms=_get(data, "lastRunAtMs", "last_run_at_ms"), last_status=_get(data, "lastStatus", "last_status"), # type: ignore[arg-type] last_error=_get(data, "lastError", "last_error"), @@ -127,8 +127,8 @@ class TriggerDelivery: id=str(data["id"]), trigger_id=str(_get(data, "triggerId", "trigger_id", "")), content=str(data.get("content") or ""), - created_at_ms=_ms_int(_get(data, "createdAtMs", "created_at_ms", 0)), - attempts=_ms_int(data.get("attempts", 0)), + created_at_ms=_store_int(_get(data, "createdAtMs", "created_at_ms", 0)), + attempts=_store_int(data.get("attempts", 0)), last_error=data.get("lastError") or data.get("last_error"), path=path, ) diff --git a/tests/triggers/test_local_triggers.py b/tests/triggers/test_local_triggers.py index 25ababff..6942ae7d 100644 --- a/tests/triggers/test_local_triggers.py +++ b/tests/triggers/test_local_triggers.py @@ -13,6 +13,7 @@ from nanobot.agent.automation_turns import AutomationTurnError from nanobot.bus.events import InboundMessage, OutboundMessage from nanobot.triggers.local_runner import run_local_trigger_queue from nanobot.triggers.local_store import LocalTriggerStore, TriggerDisabledError +from nanobot.triggers.local_types import LocalTrigger, TriggerDelivery from nanobot.webui.metadata import WEBUI_MESSAGE_SOURCE_METADATA_KEY, WEBUI_TURN_METADATA_KEY @@ -493,8 +494,6 @@ async def test_local_trigger_queue_recovers_processing_delivery_on_start( def test_local_trigger_from_dict_accepts_null_run_at_ms() -> None: - from nanobot.triggers.local_types import LocalTrigger, TriggerDelivery - trigger = LocalTrigger.from_dict( { "id": "t1", @@ -513,6 +512,13 @@ def test_local_trigger_from_dict_accepts_null_run_at_ms() -> None: assert trigger.updated_at_ms == 0 delivery = TriggerDelivery.from_dict( - {"id": "d1", "triggerId": "t1", "content": "hi", "createdAtMs": None} + { + "id": "d1", + "triggerId": "t1", + "content": "hi", + "createdAtMs": None, + "attempts": None, + } ) assert delivery.created_at_ms == 0 + assert delivery.attempts == 0