-
Notifications
You must be signed in to change notification settings - Fork 6
docs: update guardrails, thread-safety, and resource-lifecycle pages for PR #1514 architectural fixes #230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -89,6 +89,19 @@ class MemoryEfficientConversationManager: | |
|
|
||
| ### 2. Agent Memory Management | ||
|
|
||
| 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. | ||
|
|
||
| ```python | ||
| from praisonaiagents import Agent, Task, PraisonAIAgents | ||
|
|
||
| memory_config = {"storage": {"path": "./shared.db"}, "provider": "file"} | ||
|
|
||
| agents = [Agent(name=f"A{i}", instructions="Summarize one line.") for i in range(4)] | ||
| tasks = [Task(description=f"Summarize doc {i}.", agent=agents[i], config={"memory_config": memory_config}) for i in range(4)] | ||
|
|
||
| PraisonAIAgents(agents=agents, tasks=tasks).start() | ||
| ``` | ||
|
|
||
| Implement memory limits and cleanup for agents: | ||
|
|
||
| ```python | ||
|
|
@@ -371,6 +384,24 @@ class AutomaticMemoryManager: | |
| schedule.every(5).minutes.do(conditional_cleanup) | ||
| ``` | ||
|
|
||
| ### 3. Agent Garbage Collection Safety Net | ||
|
|
||
| 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: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| ```python | ||
| # Preferred: Explicit cleanup | ||
| agent = Agent(name="Analyst", instructions="Analyze data.") | ||
| try: | ||
| result = agent.start("Analyze quarterly numbers.") | ||
| finally: | ||
| agent.close() # Guaranteed cleanup | ||
|
|
||
| # Better: Context manager (recommended) | ||
| with Agent(name="Analyst", instructions="Analyze data.") as agent: | ||
| result = agent.start("Analyze quarterly numbers.") | ||
| # Cleanup happens automatically here | ||
| ``` | ||
|
|
||
| ## Best Practices | ||
|
|
||
| ### 1. Use Context Managers | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -83,6 +83,7 @@ sequenceDiagram | |
| User->>Team: (exit with block) | ||
| Team->>Agents: close() each | ||
| Team->>Memory: close() | ||
| Note right of Memory: Closes SQLite, MongoDB, etc. | ||
| Team-->>User: cleanup complete | ||
| ``` | ||
|
|
||
|
|
@@ -208,6 +209,21 @@ async with PraisonAIAgents(agents=[agent]) as workflow: | |
| ``` | ||
| </Accordion> | ||
|
|
||
| <Accordion title="MongoDB connections are now included in cleanup"> | ||
| 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: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| ```python | ||
| # Explicit cleanup (preferred) | ||
| with Agent(name="Analyst", instructions="Analyze quarterly numbers.") as agent: | ||
| agent.start("Summarize Q1 revenue.") | ||
| # MongoDB / SQLite / registered connections closed here. | ||
|
|
||
| # Async form | ||
| async with Agent(name="Analyst", instructions="...") as agent: | ||
| await agent.astart("...") | ||
| ``` | ||
| </Accordion> | ||
|
|
||
| <Accordion title="Don't reuse a team after exiting its with block"> | ||
| Once you exit a `with` block, consider the AgentTeam closed. Create a new one for additional work. | ||
|
|
||
|
|
||
| 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 | |
| - `chat_history` setter now acquires the `AsyncSafeState` lock for assignments | ||
| </Note> | ||
|
|
||
| #### What changed in PR #1514 | ||
|
|
||
| <Note> | ||
| 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. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| **2. Async-Locked Workflow State**: New `_set_workflow_finished(value)` method uses async locks to safely update workflow completion status across concurrent tasks. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| **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. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| </Note> | ||
|
|
||
| #### Safe operations | ||
|
|
||
| ```python | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
retry_with_feedbackparameter is not supported by theTaskclass constructor in the current implementation. Including it in this example will result in aTypeError: __init__() got an unexpected keyword argument 'retry_with_feedback'.