Difficulty: Advanced (senior · 6/10). ~10–16h. Python asyncio, websockets, resilience patterns.
Context
Issue #31 asks for a resilient reconnecting WebSocket client for the TypeScript SDK. The Python SDK's Agent.subscribe() already reconnects, but naively: a bare while True loop with a fixed 5-second sleep on any exception, no backoff, no retry cap, and only a signal/connected callback surface — no distinct connection-status or error events, and no protection against a burst of buffered messages after a reconnect.
Goal
Bring the Python client's WebSocket resilience up to the same bar as #31: exponential backoff with jitter, a retry cap, and typed callbacks a caller can actually branch on.
Scope / Deliverables
- Replace the fixed 5s retry with exponential backoff + jitter and a configurable max-retries cap (after which
subscribe() raises instead of looping forever silently).
- Separate callback channels:
on("signal") (existing), plus on("status") (connecting/connected/reconnecting/disconnected) and on("error") (the exception that triggered a reconnect) — additive, must not break the current on("signal") API.
- Basic de-duplication so a burst of buffered messages after a reconnect doesn't double-fire the same signal.
- A
close() method for graceful shutdown (currently there's no way to stop subscribe() short of killing the task).
- Tests: force a disconnect against a mock WS server and assert reconnection with backoff, and that the retry cap is respected.
- Update
packages/sdk-python/README.md.
Acceptance criteria
- A forced disconnect against the real testnet WS (
wss://nirium-agent.fly.dev/ws/signals) recovers automatically — demonstrate it in the PR (log output is enough, no tx hash needed here).
- Existing
on("signal") callers keep working unmodified.
pytest passes; no unhandled exceptions escape subscribe().
Pointers
Out of scope
- Changing the message schema or wire format.
- MPP support over this same socket (out of scope for this issue).
References
Reward
Eligibility is subject to GrantFox review under this campaign. Rewards are decided by GrantFox based on quality and available budget and are not guaranteed.
Difficulty: Advanced (senior · 6/10). ~10–16h. Python asyncio,
websockets, resilience patterns.Context
Issue #31 asks for a resilient reconnecting WebSocket client for the TypeScript SDK. The Python SDK's
Agent.subscribe()already reconnects, but naively: a barewhile Trueloop with a fixed 5-second sleep on any exception, no backoff, no retry cap, and only asignal/connectedcallback surface — no distinct connection-status or error events, and no protection against a burst of buffered messages after a reconnect.Goal
Bring the Python client's WebSocket resilience up to the same bar as #31: exponential backoff with jitter, a retry cap, and typed callbacks a caller can actually branch on.
Scope / Deliverables
subscribe()raises instead of looping forever silently).on("signal")(existing), pluson("status")(connecting/connected/reconnecting/disconnected) andon("error")(the exception that triggered a reconnect) — additive, must not break the currenton("signal")API.close()method for graceful shutdown (currently there's no way to stopsubscribe()short of killing the task).packages/sdk-python/README.md.Acceptance criteria
wss://nirium-agent.fly.dev/ws/signals) recovers automatically — demonstrate it in the PR (log output is enough, no tx hash needed here).on("signal")callers keep working unmodified.pytestpasses; no unhandled exceptions escapesubscribe().Pointers
packages/sdk-python/src/nirium/client.py—Agent.subscribe()is the method to harden.Out of scope
References
Reward
Eligibility is subject to GrantFox review under this campaign. Rewards are decided by GrantFox based on quality and available budget and are not guaranteed.