> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Windowed Spend Budget Policy • AI Agent SDK

> WindowedSpendBudgetPolicy: Config-driven cumulative per-identity spend-budget policy.

# WindowedSpendBudgetPolicy

> Defined in the [**protocols**](../modules/protocols) module.

<Badge color="blue">AI Agent</Badge>

Config-driven cumulative per-identity spend-budget policy.

Intended as the default the wrapper will wire onto a forthcoming
`gateway.budget` config block and a `spend_budget_policy=` gateway
constructor argument (neither of which exists in the repo yet — this PR
ships only the core decision primitive; the CLI/YAML and constructor
surfaces are a follow-up wrapper change). It is intentionally minimal and
dependency-free so the decision lives in core and is provable in isolation,
exactly like :class:`SlidingWindowRateLimitPolicy`.

The decision, given the amount `spent_usd` already accumulated for the
identity+scope in the current window and the `pending_usd` estimated cost
of the turn being admitted:

* `allowed` while `spent_usd + pending_usd` is below `limit_usd`.
* Otherwise the turn is denied with a `retry_after_seconds` hint equal to
  the time until enough spend rolls out of the window. When
  `oldest_spend_ts` is supplied the hint is computed precisely
  (`oldest_spend_ts + window_seconds - now`); without it the policy falls
  back to the full `window_seconds` as a safe upper bound.

Passing `pending_usd` lets a caller reserve budget for the turn's
estimated cost *before* the LLM call so a single expensive turn cannot
overshoot the cap; leaving it at the default `0.0` preserves the simpler
"gate on spend so far" behaviour.

A `limit_usd` of `0` (or negative) disables the budget entirely (every
turn is allowed) — the legacy default when no budget is configured.

Unlike :class:`SlidingWindowRateLimitPolicy` this policy is *stateless*: the
cumulative spend is owned by a durable
:class:`~praisonaiagents.telemetry.protocols.TokenUsageSinkProtocol`, so the
same budget survives restarts and is shared across processes.

Example::

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
WindowedSpendBudgetPolicy(limit_usd=2.00, window_seconds=86_400)
```

## Methods

<CardGroup cols={2}>
  <Card title="enabled()" icon="function" href="../functions/WindowedSpendBudgetPolicy-enabled">
    Whether budgeting is active (a positive limit is set).
  </Card>

  <Card title="window_start()" icon="function" href="../functions/WindowedSpendBudgetPolicy-window_start">
    Start timestamp of the current window for a `now` timestamp.
  </Card>

  <Card title="check()" icon="function" href="../functions/WindowedSpendBudgetPolicy-check">
    Instance method.
  </Card>
</CardGroup>

## Source

<Card title="View on GitHub" icon="github" href="https://github.com/MervinPraison/PraisonAI/blob/main/src/praisonai-agents/praisonaiagents/gateway/protocols.py#L4369">
  `praisonaiagents/gateway/protocols.py` at line 4369
</Card>
