RateLimitRule interface
Configures one rate limit rule for incoming turns.
A rule first decides whether it applies to the turn, then derives a scope key, then increments the fixed-window counter for that scope key. Multiple rules can apply to the same turn; the first rule whose counter is at the limit throttles the turn and prevents the route handler from running.
The fixed window starts when the first matching activity for a scope key is
accepted. It does not start when the limit is reached. For example, with
limit: 3 and windowMs: 10_000:
- at 0s, the first matching activity is accepted and starts a window ending at 10s
- at 1s and 2s, the second and third matching activities are accepted
- at 3s, the fourth matching activity is throttled with
retryAfterMsnear 7000 - at 10s, the window has expired and the next accepted activity starts a new window
Example
Limit all activities per user:
{
scope: (context) => context.activity.from?.id,
limit: 10,
windowMs: 60_000
}
Example
Limit only message activities per conversation:
{
scope: (context) => context.activity.conversation?.id,
activityTypes: [ActivityTypes.Message],
limit: 20,
windowMs: 60_000
}
Example
Limit only an expensive command per user:
{
appliesTo: (context) => context.activity.text?.startsWith('/expensive') === true,
scope: (context) => context.activity.from?.id,
limit: 3,
windowMs: 60_000
}
Properties
| activity |
Activity types counted by this rule. When provided, the rule only applies to activities whose type is in this array. When omitted, the rule applies to all activity types, subject to Example
|
| applies |
Optional predicate that decides whether this rule participates in the turn. When provided, it runs after the When omitted, every activity that passed Use this for policy or feature filtering, such as limiting only a command, tenant, channel, or class of users. Keep this separate from Example
|
| limit | Maximum number of activities allowed for each scope key over This property is required. Each accepted turn that matches the rule increments the counter for its scope key. |
| max |
Number of times to retry storage operations. Defaults to 3. When provided, failed window evaluations and writes are retried up to this many times before
applying When omitted, failed window evaluations and writes are retried up to 3 times. Retries help when shared storage reports transient read or write failures. |
| message | Message sent when this rule throttles a turn. When provided, this message is used for throttled message turns. It can be a
plain string, an Activity, or a factory. Use a factory when the response
should include details such as When omitted, the default message is sent: "Too many requests. Please try again later." |
| scope | Derives the scope key that will be counted when this rule applies. This property is required. This is for grouping, not filtering. Return the same key for activities that should share a quota, such as a user ID for per-user limits or a conversation ID for per-conversation limits. If this rule applies and the returned key is missing or blank, the turn is throttled instead of being allowed through without a counter. |
| storage | Storage used for this rule's fixed-window state. When provided, the rule reads and writes window state through this storage provider. When omitted, the rule uses the |
| storage |
Behavior when rate limit storage fails. Defaults to When provided, the selected behavior is used when storage cannot be read or
written. When omitted, storage failures use |
| window |
Time window, in milliseconds, used for the rule's fixed-window counter. This property is required. For example, |
Property Details
activityTypes
Activity types counted by this rule.
When provided, the rule only applies to activities whose type is in this array.
When omitted, the rule applies to all activity types, subject to appliesTo
if that predicate is also configured.
Example
activityTypes: [ActivityTypes.Message]
activityTypes?: ActivityTypes[]
Property Value
appliesTo
Optional predicate that decides whether this rule participates in the turn.
When provided, it runs after the activityTypes check. If it returns
true, the rule continues to scope and may increment a counter. If it
returns false, the rule is skipped and no window state is read or written.
When omitted, every activity that passed activityTypes is considered to
match this rule.
Use this for policy or feature filtering, such as limiting only a command, tenant, channel, or class of users.
Keep this separate from scope: appliesTo answers "does this rule apply?",
while scope answers "which scope key should be counted?".
Example
appliesTo: (context) => context.activity.text?.startsWith('/expensive') === true
appliesTo?: (context: TurnContext) => boolean | Promise<boolean>
Property Value
(context: TurnContext) => boolean | Promise<boolean>
limit
Maximum number of activities allowed for each scope key over windowMs.
This property is required.
Each accepted turn that matches the rule increments the counter for its scope key.
limit: number
Property Value
number
maxStorageRetries
Number of times to retry storage operations. Defaults to 3.
When provided, failed window evaluations and writes are retried up to this many times before
applying storageErrorBehavior.
When omitted, failed window evaluations and writes are retried up to 3 times. Retries help when shared storage reports transient read or write failures.
maxStorageRetries?: number
Property Value
number
message
Message sent when this rule throttles a turn.
When provided, this message is used for throttled message turns. It can be a
plain string, an Activity, or a factory. Use a factory when the response
should include details such as retryAfterMs.
When omitted, the default message is sent: "Too many requests. Please try again later."
message?: string | Activity | RateLimitMessageFactory
Property Value
string | Activity | RateLimitMessageFactory
scope
Derives the scope key that will be counted when this rule applies.
This property is required.
This is for grouping, not filtering. Return the same key for activities that should share a quota, such as a user ID for per-user limits or a conversation ID for per-conversation limits.
If this rule applies and the returned key is missing or blank, the turn is throttled instead of being allowed through without a counter.
scope: RateLimitScope
Property Value
storage
Storage used for this rule's fixed-window state.
When provided, the rule reads and writes window state through this storage provider.
When omitted, the rule uses the AgentApplication storage. If the
application does not have storage configured, the limiter falls back to
app-local memory storage. Provide rule-specific durable or shared storage
when this rule should use a different store than the application state, or
when limits must survive restarts or apply across multiple app instances.
storage?: StorageProvider
Property Value
storageErrorBehavior
Behavior when rate limit storage fails. Defaults to throttle.
When provided, the selected behavior is used when storage cannot be read or
written. throttle fails closed and rejects the turn, allow fails open and
lets the turn continue, and throw surfaces the storage error.
When omitted, storage failures use throttle.
storageErrorBehavior?: RateLimitStorageErrorBehavior
Property Value
windowMs
Time window, in milliseconds, used for the rule's fixed-window counter.
This property is required.
For example, limit: 5 and windowMs: 60_000 allows up to five activities
per minute for each scope key. The window starts when the first matching
activity for the scope key is accepted, and resets after windowMs. If the
counter reaches limit before the window resets, additional matching
activities are throttled and retryAfterMs reports the remaining time in
that same window.
windowMs: number
Property Value
number