> ## 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.

# Fleet Supervision Policy • AI Agent SDK

> FleetSupervisionPolicy: Pure fleet-level crash-loop breaker for channel supervision (Issue #3840).

# FleetSupervisionPolicy

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

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

Pure fleet-level crash-loop breaker for channel supervision (Issue #3840).

Per-channel restart budgets (`ChannelHealthMonitor` /
`ChannelRestartHistory` in `praisonai-bot`) throttle one misbehaving
channel, but they are blind to a *systemic* fault — a bad shared provider,
a network partition, an org-wide expired token — that makes *every* channel
restart at once. Each channel then independently stays "under budget" while
the fleet as a whole thrashes: a reconnect storm that floods logs, burns
CPU, and risks an upstream rate-limit ban with no single operator-visible
signal.

This is the aggregate breaker that sits *on top of* the per-channel budgets.
Like :class:`RestartLoopGuard` it is intentionally side-effect free (records
timestamps only, no I/O, no heavy deps) so the *decision* lives in core and
is provable in isolation; the wrapper owns the side effects (halting
restarts, recording one `gateway` degraded-owner entry).

The breaker trips when *either* aggregate signal crosses its threshold
within the trailing window:

* the fleet restart rate reaches `fleet_restarts_per_hour` restarts across
  all channels, or
* the fraction of channels in a failing/parked state reaches
  `failing_channel_fraction`.

Once tripped it stays tripped for `breaker_cooldown_s` so the caller
applies backpressure (stops auto-restarting, backs off) instead of feeding
the storm; after the cooldown it re-arms automatically.

Example::

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
policy = FleetSupervisionPolicy(fleet_restarts_per_hour=40)
if policy.note_restart(now=time.monotonic()):
    # fleet breaker tripped — stop auto-restarting, surface degraded
    ...
```

## Constructor

<ParamField query="fleet_restarts_per_hour" type="int" required={false} default="40">
  No description available.
</ParamField>

<ParamField query="failing_channel_fraction" type="float" required={false} default="0.5">
  No description available.
</ParamField>

<ParamField query="breaker_cooldown_s" type="float" required={false} default="120.0">
  No description available.
</ParamField>

## Methods

<CardGroup cols={2}>
  <Card title="note_restart()" icon="function" href="../functions/FleetSupervisionPolicy-note_restart">
    Record a fleet restart at `now` and return whether the breaker is tripped.
  </Card>

  <Card title="note_fleet_state()" icon="function" href="../functions/FleetSupervisionPolicy-note_fleet_state">
    Trip the breaker when too large a fraction of the fleet is failing.
  </Card>

  <Card title="tripped()" icon="function" href="../functions/FleetSupervisionPolicy-tripped">
    Return whether the breaker is currently tripped without recording.
  </Card>

  <Card title="reset()" icon="function" href="../functions/FleetSupervisionPolicy-reset">
    Clear recorded restart history and any active trip (clean recovery).
  </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#L4469">
  `praisonaiagents/gateway/protocols.py` at line 4469
</Card>

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Multimodal" icon="eye" href="/docs/docs/features/multimodal" />
</CardGroup>
