Why
Today's API retry behavior is ad-hoc. A formal, documented retry ladder makes the CLI resilient on flaky networks and avoids hammering the server on permanent errors.
What
Implement a budgeted retry policy in the API client:
- Exponential backoff 2s/4s/8s/16s, then flat ~30s cap; overall budget ~6 minutes, max ~15 attempts
- HTTP 429: max 2 retries, honor
Retry-After when present
- Never retry permanent 4xx (400/401/403/404/422) — 401 already has its own auth-refresh path, don't fight it
- Retry on: network errors, 5xx, and "empty response" (stream ended with no content and no tool calls)
- Oversized-image rejection: strip image parts and retry once (not counted against the budget)
- Surface retry state in the TUI status line ("retrying 3/15…") instead of silent hangs
Where to start
src/api/client.ts (chat, chatStream) — keep the ladder as a small pure helper with unit tests (client.test.ts exists)
Acceptance criteria
- Unit tests for: backoff sequence, 429 cap, permanent-4xx no-retry, empty-response retry
- No regression to 401 auto-recovery
- typecheck + tests green
Why
Today's API retry behavior is ad-hoc. A formal, documented retry ladder makes the CLI resilient on flaky networks and avoids hammering the server on permanent errors.
What
Implement a budgeted retry policy in the API client:
Retry-Afterwhen presentWhere to start
src/api/client.ts(chat,chatStream) — keep the ladder as a small pure helper with unit tests (client.test.tsexists)Acceptance criteria