From c9fc4a247f5cdd7f879376f57cfd86f261f3e8a0 Mon Sep 17 00:00:00 2001 From: Railway Agent Date: Fri, 22 May 2026 05:32:16 +0000 Subject: [PATCH 1/3] Fix VERSION_MISMATCH error by updating SKILL_VERSION to 1.6.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem\nThe molty5 agent was experiencing repeated errors:\n- Error: \n- Local SKILL_VERSION: \n- Server API version: \n\nThe heartbeat was failing repeatedly with exponential backoff (10s → 20s → 40s → 80s → 120s), preventing the agent from connecting to the Molty Royale API.\n\n## Solution\nUpdated in from to to match the current server API version.\n\n## Changes\n- : Updated \n\nThis ensures the agent sends the correct header in all API requests and WebSocket connections, resolving the version mismatch error. --- bot/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/config.py b/bot/config.py index dd20742..b6fc77e 100644 --- a/bot/config.py +++ b/bot/config.py @@ -9,7 +9,7 @@ load_dotenv() # ── Skill / API version ────────────────────────────────────────────── -SKILL_VERSION = "1.5.2" +SKILL_VERSION = "1.6.2" # ── URLs ────────────────────────────────────────────────────────────── API_BASE = "https://cdn.moltyroyale.com/api" From 083b3b8d6c7ab271af55598dfeb9b164ccf48a90 Mon Sep 17 00:00:00 2001 From: "railway-app[bot]" <68434857+railway-app[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 06:26:30 +0000 Subject: [PATCH 2/3] fix: use GET /identity fallback in state_router to fix NO_IDENTITY loop --- bot/heartbeat.py | 11 ++++++++++- bot/state_router.py | 20 ++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/bot/heartbeat.py b/bot/heartbeat.py index 85bd34b..8cce810 100644 --- a/bot/heartbeat.py +++ b/bot/heartbeat.py @@ -116,8 +116,17 @@ async def _heartbeat_cycle(self): return raise + # Step 1b: GET /identity — used as a fallback by determine_state so + # that a registered identity is recognised even when /accounts/me + # readiness.erc8004Id has not yet been populated by the server. + identity_resp: dict | None = None + try: + identity_resp = await self.api.get_identity() + except APIError: + pass # Non-fatal — determine_state will fall back gracefully + # Step 2: Determine state - state, ctx = determine_state(me) + state, ctx = determine_state(me, identity_response=identity_resp) log.info("State: %s", state) # Feed dashboard with account info — use CONSISTENT key diff --git a/bot/state_router.py b/bot/state_router.py index df9984f..bba2b17 100644 --- a/bot/state_router.py +++ b/bot/state_router.py @@ -15,10 +15,16 @@ ERROR = "ERROR" -def determine_state(me_response: dict) -> tuple[str, dict]: +def determine_state(me_response: dict, identity_response: dict | None = None) -> tuple[str, dict]: """ Analyze /accounts/me response → return (state, context). Context contains relevant data for the next step. + + identity_response: optional result of GET /identity (same source as + setup.identity.ensure_identity). Used as a fallback when + readiness.erc8004Id is absent from /accounts/me — fixes the mismatch + where the identity registry is already populated but /accounts/me has + not yet reflected it. """ readiness = me_response.get("readiness", {}) current_games = me_response.get("currentGames", []) @@ -36,8 +42,18 @@ def determine_state(me_response: dict) -> tuple[str, dict]: "is_alive": game.get("isAlive", True), } - # Check ERC-8004 identity + # Check ERC-8004 identity — prefer /accounts/me readiness field, but + # fall back to the dedicated GET /identity response when the field is + # absent. This prevents a state mismatch where setup.identity already + # confirmed registration but /accounts/me still returns erc8004Id=null. erc8004_id = readiness.get("erc8004Id") + if erc8004_id is None and identity_response is not None: + erc8004_id = identity_response.get("erc8004Id") + if erc8004_id is not None: + log.info( + "erc8004Id absent in /accounts/me readiness; " + "using GET /identity fallback: tokenId=%s", erc8004_id + ) if erc8004_id is None: log.info("No ERC-8004 identity registered") return NO_IDENTITY, {} From 7bacbeb01d06f122e6e9290c155edcf56f42984a Mon Sep 17 00:00:00 2001 From: Kikiihydraa_ Date: Fri, 22 May 2026 13:40:08 +0700 Subject: [PATCH 3/3] Revert "fix: use GET /identity fallback in state_router to fix NO_IDENTITY loop" This reverts commit 083b3b8d6c7ab271af55598dfeb9b164ccf48a90. --- bot/heartbeat.py | 11 +---------- bot/state_router.py | 20 ++------------------ 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/bot/heartbeat.py b/bot/heartbeat.py index 8cce810..85bd34b 100644 --- a/bot/heartbeat.py +++ b/bot/heartbeat.py @@ -116,17 +116,8 @@ async def _heartbeat_cycle(self): return raise - # Step 1b: GET /identity — used as a fallback by determine_state so - # that a registered identity is recognised even when /accounts/me - # readiness.erc8004Id has not yet been populated by the server. - identity_resp: dict | None = None - try: - identity_resp = await self.api.get_identity() - except APIError: - pass # Non-fatal — determine_state will fall back gracefully - # Step 2: Determine state - state, ctx = determine_state(me, identity_response=identity_resp) + state, ctx = determine_state(me) log.info("State: %s", state) # Feed dashboard with account info — use CONSISTENT key diff --git a/bot/state_router.py b/bot/state_router.py index bba2b17..df9984f 100644 --- a/bot/state_router.py +++ b/bot/state_router.py @@ -15,16 +15,10 @@ ERROR = "ERROR" -def determine_state(me_response: dict, identity_response: dict | None = None) -> tuple[str, dict]: +def determine_state(me_response: dict) -> tuple[str, dict]: """ Analyze /accounts/me response → return (state, context). Context contains relevant data for the next step. - - identity_response: optional result of GET /identity (same source as - setup.identity.ensure_identity). Used as a fallback when - readiness.erc8004Id is absent from /accounts/me — fixes the mismatch - where the identity registry is already populated but /accounts/me has - not yet reflected it. """ readiness = me_response.get("readiness", {}) current_games = me_response.get("currentGames", []) @@ -42,18 +36,8 @@ def determine_state(me_response: dict, identity_response: dict | None = None) -> "is_alive": game.get("isAlive", True), } - # Check ERC-8004 identity — prefer /accounts/me readiness field, but - # fall back to the dedicated GET /identity response when the field is - # absent. This prevents a state mismatch where setup.identity already - # confirmed registration but /accounts/me still returns erc8004Id=null. + # Check ERC-8004 identity erc8004_id = readiness.get("erc8004Id") - if erc8004_id is None and identity_response is not None: - erc8004_id = identity_response.get("erc8004Id") - if erc8004_id is not None: - log.info( - "erc8004Id absent in /accounts/me readiness; " - "using GET /identity fallback: tokenId=%s", erc8004_id - ) if erc8004_id is None: log.info("No ERC-8004 identity registered") return NO_IDENTITY, {}