Skip to content

feat(client): rate limit guidance and backoff-aware retries - #43

Merged
ABujalance merged 1 commit into
mainfrom
feat/rate-limit-guidance
Aug 24, 2026
Merged

feat(client): rate limit guidance and backoff-aware retries#43
ABujalance merged 1 commit into
mainfrom
feat/rate-limit-guidance

Conversation

@ABujalance

Copy link
Copy Markdown
Contributor

feat(client): rate limit guidance and backoff-aware retries

Why

A user (Jack Gray) hit sustained 429s last week. The cause was an assistant that built
autosave-to-the-server into his app without telling him — a write per change, against an
endpoint capped at 30 writes/minute. His feedback: our LLM prep documents never mention
rate limits or an alternative, and our errors don't say what the limit was.

Nothing in this package told anyone otherwise: resources/AGENTS.md had a single hard rule
(UI must be Lit), and no doc anywhere carried a limit number.

What changed

Docs

  • New docs/rate-limits.md: per-endpoint limits, what a 429 looks like, the local-draft
    save pattern, and retry guidance. Numbers copied from the @Throttle decorators in
    platform_backend-api.
  • resources/AGENTS.md: new hard rule Add new methods to the backend library to make the platform builderless #1 — never write to the platform on every change;
    drafts live in localStorage / IndexedDB, the platform gets an explicit save. Added the
    doc to the session-start index table.
  • docs/ai-quickstart.md: same rule in the assistant rules list.
  • CLAUDE.md: where the numbers come from and that they go stale silently.

Client

  • RequestError.retryAfter — seconds to wait, read from the Retry-After header, falling
    back to details.retryAfter in the body (survives proxies that strip headers).
  • Retries now back off exponentially (500ms base, x2, 30s cap) with 25% jitter, and honour
    Retry-After when the server sends one.
  • Only network failures, 429 and 5xx are retried. Previously every failure was
    retried immediately with no delay, so a client configured with retries turned a rate
    limit into a burst against the same endpoint, and repeated 401/404s that could never
    succeed.
  • Retries stay off by default (retries: 0), so this only changes behaviour for callers who
    opted in.

Pairs with

platform_backend-api PR — structured 429 body (code: 'RATE_LIMITED', limit, window,
retryAfter). The client reads it, but degrades fine against the current generic body.

Testing

  • npx vitest run — 96 passed, including 8 new retry-policy tests (no retry on 4xx, retry
    on 429/5xx/network, waits for Retry-After, gives up after N, exposes retryAfter).
  • npx eslint src/ and npx tsc --noEmit clean.
  • Examples under src/core/examples/ were not run — they need real credentials in
    src/core/examples/.env, which isn't set up here. No example calls changed shape.

Document the per-endpoint limits, the 429 shape and the local-draft save pattern, and add a hard rule against autosaving to the platform on every change. Expose RequestError.retryAfter, back off between retries with jitter, honour Retry-After, and stop retrying 4xx that cannot succeed.
@ABujalance
ABujalance merged commit 21e4fb5 into main Aug 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant