Summary
The gateway/bot runtime already ships strong reliability building blocks — a durable inbound journal, a durable outbound outbox, a gateway-wide admission gate, and graceful-shutdown draining — but the two strongest lifecycle protections (the graceful-drain window and inbound admission/backpressure) are individually opt-in. An operator who runs the gateway the obvious way (BotOS(agent=...), praisonai gateway start, or a minimal gateway.yaml) silently gets a deployment with no admission ceiling and only a 5-second drain, so a burst can fan out unboundedly and a rolling restart can cut in-flight agent turns. This contradicts the SDK's safe-by-default / hard-to-misuse / production-ready pillars: the safe posture exists, but it must be discovered and switched on.
Current behaviour
resolve_reliability() maps the default (reliability=None / "default") to a posture with no admission ceiling, and the module docstring states the problem outright:
# src/praisonai-bot/praisonai_bot/bots/_reliability.py (module docstring)
# ... the two strongest lifecycle knobs (graceful drain and inbound admission)
# are individually opt-in. An operator running the gateway the "obvious" way
# therefore silently gets a no-backpressure deployment that cuts in-flight
# turns on restart.
#
# "default" / None
# A sane, small graceful-drain window (5s) so a restart doesn't cut
# in-flight turns, but no admission ceiling (unbounded, legacy dispatch).
BotOS.__init__ defaults the posture to None, and resolve_reliability/normalize_reliability treat None/"none" as "no preset" — returning early with no admission knobs:
# src/praisonai-bot/praisonai_bot/bots/botos.py
reliability: Optional[str] = None,
...
_resolved = resolve_reliability(reliability, ...)
# src/praisonai-bot/praisonai_bot/bots/_reliability.py
if reliability is None:
return None
...
if name in ("", "none"):
return None
The production profile (15-second drain, CPU-scaled admission ceiling, bounded fair wait queue, strict outbound ordering) is fully implemented — it is simply not the default. The three-way surface is already wired (BotOS(reliability=...), --reliability, gateway.reliability in YAML — see src/praisonai-bot/praisonai_bot/cli/features/gateway.py), so only the default value is unsafe.
Desired behaviour
Running the gateway with no explicit reliability setting should be production-safe by default: a graceful-drain window that does not cut mid-turn replies on restart, plus a bounded admission ceiling and fair wait queue, with an explicit reliability="off" / --reliability off to opt back into today's immediate-teardown behaviour. Bind posture should inform the default — a gateway bound to a non-loopback interface (an actual deployment) should never come up without backpressure.
Layer placement
- Primary layer: wrapper (
praisonai, via the praisonai-bot gateway runtime it aliases; BotOS is explicitly a wrapper concern)
- Why not core: core owns only the policy protocols (
GatewayConcurrencyPolicyProtocol, DrainTimeoutPolicy); the chosen default posture and the heavy BotOS runtime live in the wrapper/bot layer.
- Why not wrapper: it is wrapper — this is the primary.
- Why not tools: nothing here is agent-callable.
- Why not plugins: this is the framework's own default operating posture, not a lifecycle hook a plugin wraps.
- Secondary touch (optional): core — surface the safe posture as a documented default on the reliability protocol /
GatewayConfig so every runtime resolves it identically.
- 3-way surface (CLI + YAML + Python): yes — the switch already exists on all three; this changes the default each resolves to.
Proposed approach
- Extension point: config default + preset resolver (
resolve_reliability).
- Make the resolver's default posture apply the
production-style admission ceiling + drain instead of None, keyed off bind posture, keeping explicit fields and reliability="off" as overrides.
Resolution sketch
# Before (today) — no reliability arg => no admission ceiling, 5s drain
botos = BotOS(agent=my_agent, platforms=["telegram", "discord"])
# unbounded dispatch; a rolling restart can cut in-flight turns
# After (proposed) — safe by default
botos = BotOS(agent=my_agent, platforms=["telegram", "discord"])
# graceful drain + bounded admission ceiling + fair wait queue applied automatically
# opt out explicitly
botos = BotOS(agent=my_agent, platforms=[...], reliability="off")
# resolve_reliability: default posture becomes production-safe (illustrative)
def resolve_reliability(reliability, *, bind_host="127.0.0.1", ...):
profile = normalize_reliability(reliability)
if profile is None: # no explicit preset selected
profile = "production" if _is_externally_bound(bind_host) else "default+admission"
...
Severity
High — the safe posture already exists but is off by default, so real deployments silently run without backpressure and lose in-flight turns on restart, contradicting the SDK's safe-by-default / production-ready contract. The fix is low-risk because the production machinery is already implemented and selectable.
Validation
Confirmed by reading src/praisonai-bot/praisonai_bot/bots/_reliability.py (module docstring; normalize_reliability/resolve_reliability; _DEFAULT_DRAIN_SECONDS = 5.0; _KNOWN_PROFILES = ("production", "default", "off"); the production branch that builds the CPU-scaled ceiling + bounded queue) and src/praisonai-bot/praisonai_bot/bots/botos.py (reliability: Optional[str] = None feeding resolve_reliability). The three-way surface was traced through src/praisonai-bot/praisonai_bot/cli/features/gateway.py (--reliability, gateway.reliability). The production posture is implemented and selectable today; only the default is unsafe.
Summary
The gateway/bot runtime already ships strong reliability building blocks — a durable inbound journal, a durable outbound outbox, a gateway-wide admission gate, and graceful-shutdown draining — but the two strongest lifecycle protections (the graceful-drain window and inbound admission/backpressure) are individually opt-in. An operator who runs the gateway the obvious way (
BotOS(agent=...),praisonai gateway start, or a minimalgateway.yaml) silently gets a deployment with no admission ceiling and only a 5-second drain, so a burst can fan out unboundedly and a rolling restart can cut in-flight agent turns. This contradicts the SDK's safe-by-default / hard-to-misuse / production-ready pillars: the safe posture exists, but it must be discovered and switched on.Current behaviour
resolve_reliability()maps the default (reliability=None/"default") to a posture with no admission ceiling, and the module docstring states the problem outright:BotOS.__init__defaults the posture toNone, andresolve_reliability/normalize_reliabilitytreatNone/"none"as "no preset" — returning early with no admission knobs:The
productionprofile (15-second drain, CPU-scaled admission ceiling, bounded fair wait queue, strict outbound ordering) is fully implemented — it is simply not the default. The three-way surface is already wired (BotOS(reliability=...),--reliability,gateway.reliabilityin YAML — seesrc/praisonai-bot/praisonai_bot/cli/features/gateway.py), so only the default value is unsafe.Desired behaviour
Running the gateway with no explicit reliability setting should be production-safe by default: a graceful-drain window that does not cut mid-turn replies on restart, plus a bounded admission ceiling and fair wait queue, with an explicit
reliability="off"/--reliability offto opt back into today's immediate-teardown behaviour. Bind posture should inform the default — a gateway bound to a non-loopback interface (an actual deployment) should never come up without backpressure.Layer placement
praisonai, via thepraisonai-botgateway runtime it aliases;BotOSis explicitly a wrapper concern)GatewayConcurrencyPolicyProtocol,DrainTimeoutPolicy); the chosen default posture and the heavyBotOSruntime live in the wrapper/bot layer.GatewayConfigso every runtime resolves it identically.Proposed approach
resolve_reliability).production-style admission ceiling + drain instead ofNone, keyed off bind posture, keeping explicit fields andreliability="off"as overrides.Resolution sketch
Severity
High — the safe posture already exists but is off by default, so real deployments silently run without backpressure and lose in-flight turns on restart, contradicting the SDK's safe-by-default / production-ready contract. The fix is low-risk because the
productionmachinery is already implemented and selectable.Validation
Confirmed by reading
src/praisonai-bot/praisonai_bot/bots/_reliability.py(module docstring;normalize_reliability/resolve_reliability;_DEFAULT_DRAIN_SECONDS = 5.0;_KNOWN_PROFILES = ("production", "default", "off"); theproductionbranch that builds the CPU-scaled ceiling + bounded queue) andsrc/praisonai-bot/praisonai_bot/bots/botos.py(reliability: Optional[str] = Nonefeedingresolve_reliability). The three-way surface was traced throughsrc/praisonai-bot/praisonai_bot/cli/features/gateway.py(--reliability,gateway.reliability). Theproductionposture is implemented and selectable today; only the default is unsafe.