You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PraisonAI provides built-in retry functionality specifically for guardrail validation failures, distinct from the generic `ExponentialBackoffRetry` patterns above.
904
+
905
+
<Note>
906
+
Guardrail retries are handled automatically by the executor when `Task(guardrail=..., max_retries=...)` is configured. This is separate from manual retry implementations.
907
+
</Note>
908
+
909
+
```python
910
+
from praisonaiagents import Agent, Task, PraisonAIAgents
911
+
912
+
defvalidate_content(output):
913
+
"""Built-in guardrail with retry support"""
914
+
iflen(output.raw.split()) <50:
915
+
returnFalse, "Content too short - needs at least 50 words"
916
+
returnTrue, output
917
+
918
+
task = Task(
919
+
description="Write a detailed explanation",
920
+
agent=agent,
921
+
guardrail=validate_content,
922
+
max_retries=3, # Built-in executor-level retry
923
+
retry_with_feedback=True
924
+
)
925
+
926
+
# The executor automatically handles:
927
+
# - Guardrail validation
928
+
# - Retry logic on failure
929
+
# - Feedback to agent on retry
930
+
# - Final failure after max_retries
931
+
```
932
+
933
+
This differs from manual retry strategies as it's integrated into the task execution workflow and handles the retry loop at the executor level.
934
+
901
935
## Conclusion
902
936
903
937
Implementing robust retry strategies is essential for building resilient multi-agent systems. By choosing the appropriate retry pattern and configuring it correctly, you can handle transient failures gracefully while avoiding issues like retry storms and cascading failures.
Copy file name to clipboardExpand all lines: docs/best-practices/memory-cleanup.mdx
+31Lines changed: 31 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -89,6 +89,19 @@ class MemoryEfficientConversationManager:
89
89
90
90
### 2. Agent Memory Management
91
91
92
+
Memory construction is now thread-safe and async-safe. Concurrent `Task`s sharing a `memory_config` will coordinate through locks rather than each creating duplicate stores.
93
+
94
+
```python
95
+
from praisonaiagents import Agent, Task, PraisonAIAgents
@@ -371,6 +384,24 @@ class AutomaticMemoryManager:
371
384
schedule.every(5).minutes.do(conditional_cleanup)
372
385
```
373
386
387
+
### 3. Agent Garbage Collection Safety Net
388
+
389
+
Since PR #1514, `Agent.__del__` runs a best-effort `close_connections()` during garbage collection as a safety net. However, this may be skipped by the Python interpreter and **must not be relied upon**. Always use explicit cleanup:
2.**After PR #1514**: Both sync and async execution paths properly retry failed validations
277
+
278
+
The executor increments `task.retry_count`, sets `task.status = "in progress"`, logs the retry, and continues the execution loop. On final failure after `max_retries`, it raises an exception. When a guardrail returns a modified `TaskOutput` or string, the downstream `task.result` and any memory callbacks receive the **modified** value, not the original.
279
+
280
+
```python
281
+
from praisonaiagents import Agent, Task, PraisonAIAgents
282
+
283
+
defmust_mention_price(output):
284
+
ok ="$"in output.raw
285
+
return (ok, output if ok else"Rewrite and include a price in USD.")
286
+
287
+
agent = Agent(name="Writer", instructions="Write a one-line product blurb.")
Copy file name to clipboardExpand all lines: docs/features/resource-lifecycle.mdx
+16Lines changed: 16 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -83,6 +83,7 @@ sequenceDiagram
83
83
User->>Team: (exit with block)
84
84
Team->>Agents: close() each
85
85
Team->>Memory: close()
86
+
Note right of Memory: Closes SQLite, MongoDB, etc.
86
87
Team-->>User: cleanup complete
87
88
```
88
89
@@ -208,6 +209,21 @@ async with PraisonAIAgents(agents=[agent]) as workflow:
208
209
```
209
210
</Accordion>
210
211
212
+
<Accordiontitle="MongoDB connections are now included in cleanup">
213
+
Since PR #1514, `Memory.close_connections()` also closes MongoDB clients when present. Multiple calls to `close_connections()` are safe (idempotent). Agent `__del__` provides a safety net but should not be relied upon:
214
+
215
+
```python
216
+
# Explicit cleanup (preferred)
217
+
with Agent(name="Analyst", instructions="Analyze quarterly numbers.") as agent:
Copy file name to clipboardExpand all lines: docs/features/thread-safety.mdx
+12Lines changed: 12 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -53,6 +53,18 @@ Prior to PR #1488, chat_history mutations bypassed thread-safety locks at 31+ ca
53
53
-`chat_history` setter now acquires the `AsyncSafeState` lock for assignments
54
54
</Note>
55
55
56
+
#### What changed in PR #1514
57
+
58
+
<Note>
59
+
PR #1514 enhanced thread-safety in three key areas:
60
+
61
+
**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.
62
+
63
+
**2. Async-Locked Workflow State**: New `_set_workflow_finished(value)` method uses async locks to safely update workflow completion status across concurrent tasks.
64
+
65
+
**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.
0 commit comments