samai-sdk
Ops & reliability

Concurrency & rate limiting

Two provider wrappers, same shape as withRetry/withFallback/withTimeout — compose all of them freely. Both queue calls beyond the limit rather than rejecting.

concurrency.ts
import { withConcurrencyLimit, withRateLimit, withRetry, anthropic } from "samai-sdk";

// Caps in-flight calls — a queue, not a rejection.
const capped = withConcurrencyLimit(anthropic({ apiKey: "..." }), { maxConcurrent: 5 });

// Caps requests per time window — a token-bucket limiter, refills continuously.
const throttled = withRateLimit(anthropic({ apiKey: "..." }), { maxRequests: 60, intervalMs: 60_000 });

// Compose with retries — wrapping the limit AROUND retry means retries of the same call
// count against the limit too (usually what you want).
const provider = withConcurrencyLimit(
  withRetry(anthropic({ apiKey: "..." }), { maxRetries: 2 }),
  { maxConcurrent: 5 }
);

Use withConcurrencyLimit() to stay under a provider's hard concurrent-request cap when running many agents (or a generateObjectBatch()) at once. Use withRateLimit() to stay under a published requests-per-minute limit before it turns into 429s that withRetry then has to spend time recovering from.

Order matters

Wrapping withConcurrencyLimit() around withRetry() means each retry attempt of a call also counts against the concurrency cap — usually what you want, since it prevents a burst of retries from silently exceeding your provider's limit.