Documentation Index
Fetch the complete documentation index at: https://docs.praison.ai/llms.txt
Use this file to discover all available pages before exploring further.
Thread-Safe Agent State
PraisonAI Agents v0.5.0+ includes thread-safe management of chat history and caches; PR #1567 makes the underlying lock re-entrant and adds a per-event-loop async lock.Thread-Safe Components
Chat History
Thechat_history property is now fully thread-safe with automatic locking. The SDK protects chat history mutations through internal helper methods and a locked setter:
What changed in PR #1488
Prior to PR #1488, chat_history mutations bypassed thread-safety locks at 31+ call sites. The SDK now uses internal helper methods that properly acquire locks:
_append_to_chat_history(message)- Thread-safe message appending_truncate_chat_history(length)- Thread-safe history truncation_replace_chat_history(new_history)- Thread-safe full replacementchat_historysetter now acquires theAsyncSafeStatelock for assignments
What changed in PR #1514
PR #1514 enhanced thread-safety in three key areas:1. Locked Memory Initialization:
Task.initialize_memory() now uses threading.Lock with double-checked locking pattern. A new async variant initialize_memory_async() uses asyncio.Lock and offloads construction with asyncio.to_thread() to prevent event loop blocking.2. Async-Locked Workflow State: New _set_workflow_finished(value) method uses async locks to safely update workflow completion status across concurrent tasks.3. Non-Mutating Task Context: Task execution no longer mutates task.description during runs. Per-execution context is stored in _execution_context field, keeping the user-facing task.description stable across multiple executions.Safe operations
Caches
Internal caches usethreading.RLock for reentrant locking:
_system_prompt_cache- Cached system prompts_formatted_tools_cache- Cached tool definitions
Rate Limiter
RateLimiter can be shared across threads and agents. Both the sync and async method families are fully locked — see Rate Limiter → Thread Safety & Multi-Agent Use for patterns.
LiteAgent Thread Safety
The lite package also provides thread-safe operations:Implementation Details
Lock Types
| Component | Lock Type | Reason |
|---|---|---|
chat_history | AsyncSafeState (DualLock: RLock + per-loop asyncio.Lock) | Re-entrant on same thread; non-blocking in async contexts |
_cache_lock | threading.RLock | Allows reentrant access from cached helpers |
RateLimiter (sync) | threading.Lock | Protects _tokens, _api_tokens, and refill state from races in multi-threaded acquire calls |
RateLimiter (async) | asyncio.Lock | Same protection for coroutine contexts |
Lock Usage Pattern
Why a re-entrant lock?
Nested calls (e.g. a helper that holds the lock and then assignschat_history, which itself acquires the lock) used to deadlock. RLock permits the same thread to re-enter. See PR #1567 for details.
Best Practices
Do: Use Agent Methods
Don’t: Bypass the Property Interface
Reads and full replacements via
agent.chat_history = [...] are now safe out-of-the-box. The wrapper is only needed for custom compound operations that require atomic read-modify-write sequences.Do: Clear History Safely
Async Considerations
agent.chat_history is async-aware out of the box — no external asyncio.Lock is required when all calls are inside the same event loop.
Verifying Thread Safety
Test thread safety with concurrent access:Multi-team HTTP launch
PraisonAI provides comprehensive thread-safety for HTTP server deployment:- Multiple
Agent/Agentsinstances may call.launch(port=N)concurrently from different threads — registration is atomic. - If two launch calls use the same path on the same port, the second gets an auto-suffixed path (
/path_abc123) and a warning is logged. - Server readiness is signalled deterministically (no fixed sleep);
.launch()returns only after the port is accepting connections (5s timeout). aworkflow()state lock is created inside the running async context, so workflows remain stable when invoked under pytest-asyncio or when nested inside another loop.
Wrapper-layer thread safety (praisonai package)
The praisonai wrapper layer (distinct from the praisonaiagents content above) provides thread-safe OpenAI client management and CLI command discovery.
Key-aware OpenAI client
The OpenAI client is now cached per(api_key, base_url) tuple, allowing multiple keys in the same process without cross-talk:
Thread-safe Typer command discovery
Embeddingpython -m praisonai from multiple threads is now safe. The CLI command discovery uses a double-check lock pattern and doesn’t poison the cache on failure:
Failure-safe cache
A transient discovery error does not lock the CLI into a broken state — the next call retries instead of permanently breaking dispatch. This ensures reliable operation in multi-threaded server environments where temporary import failures might occur.New Thread-Safe Components in PR #1548
AsyncAgentScheduler is now loop-aware. Thestart() method binds its async primitives (asyncio.Event, asyncio.Lock) to the running loop, and stop() raises RuntimeError if called from a different loop than start().
Lazy loaders in praisonai/auto.py are now thread-safe. A single _load_optional(key, loader) helper with a module-level lock replaces the previous unguarded module-level globals.
Integration registry (praisonai/integrations/registry.py) now has a per-instance threading.Lock guarding register/unregister/create/list_registered operations.

