agent.chat() fails, the Inbound DLQ persists the user’s message so operators can inspect and replay it later.
The user sends a channel message; if the LLM fails, the message is queued for operator replay.
On by default for gateway/bot runs — When your bot starts via
praisonai bot start, onboard, or bot.yaml, an InboundDLQ is wired automatically. No code needed. Set delivery.durable: false in your channel config to opt out.Quick Start
How It Works
The user sends a message; if the LLM call fails, the message is persisted to the DLQ so an operator can replay it later.Why you want this
No silent data loss
Failed inbound messages are persisted to a SQLite file before the exception bubbles up.
Operator-friendly replay
A single CLI command (
praisonai bot dlq replay) re-runs failed messages through the agent.Bounded by design
TTL +
max_size keep the queue from growing unbounded; oldest entries evict first.Zero new dependency
Uses only stdlib
sqlite3. On by default for gateway/bot runs — existing bots are upgraded automatically.Default behaviour (no config needed)
Every bot started throughbuild_session_manager (all shipped adapters) automatically gets a DLQ at:
~/.praisonai/state/telegram/inbound_dlq.sqlite. A Discord bot uses ~/.praisonai/state/discord/inbound_dlq.sqlite. Each platform is fully isolated.
Set PRAISONAI_HOME to override the base directory:
Opt out or override path
Add adelivery: block to any channel in your bot.yaml or gateway.yaml:
CLI
Advanced: manual instantiation
Most users get the DLQ automatically. For custom setups outsidebuild_session_manager, create it directly:
API reference
Where the SQLite file lives. Parent directories are created automatically.
Maximum number of entries kept. When exceeded, oldest entries are dropped first.
Entries older than this are evicted on the next
enqueue() or evict_expired().DLQEntry
Methods
- Inspect
- Mutate
- Replay
Real LLM smoke test
Best Practices
Tune retention for your SLO
Tune retention for your SLO
Set
max_size and ttl_seconds to match how long you need to retain failed messages. Chronic LLM outages can fill disk quickly.Retry inline before the DLQ
Retry inline before the DLQ
For transient failures, use
BackoffPolicy to retry inline first. The DLQ is the last resort, not the first response.Alert on DLQ growth
Alert on DLQ growth
Wrap
dlq.enqueue() with your tracer (e.g. OTEL span). A non-zero dlq.size() is a strong SLO trip-wire.Combine with durable outbound
Combine with durable outbound
Pair inbound DLQ with Durable Outbound Delivery so both sides of a conversation survive failures.
Thread safety — every write is guarded by an internal
threading.Lock. SQLite WAL is enabled. Safe to share one InboundDLQ instance across threads.Fallback — if durability is requested but SQLite fails to initialise (permissions, disk full, etc.), the manager logs a warning and falls back to in-memory delivery automatically.
Combining with other features
With Cross-Platform Mirror (W1)
With Cross-Platform Mirror (W1)
The DLQ records
platform, user_id, and (if W1’s IdentityResolver is wired) the same user_id resolves the same human across platforms. Replay restores the exact session.With BackoffPolicy (resilience)
With BackoffPolicy (resilience)
For transient failures use
praisonai.bots._resilience.BackoffPolicy to retry inline before falling back to the DLQ. The DLQ is the last resort, not the first.With observability
With observability
Wrap
dlq.enqueue() with your tracer (e.g. OTEL span) to alert on DLQ growth. A non-zero dlq.size() is a great SLO trip-wire.Paid upgrade path
OSS now File-backed SQLite DLQ — single-host deploys. Cloud (planned) Multi-region replicated DLQ with web dashboard, automatic alerting, and one-click bulk replay.Related
Delivery Config
Full reference for the
delivery: channel config block — defaults, opt-out, and path overrideInbound Journal
Deduplicate webhook redeliveries and recover in-flight messages after a crash
Durable Outbound Delivery
Outbound counterpart — persist outgoing messages with retry and idempotency
Messaging Bots
Bot setup where the DLQ is wired automatically

