Skip to content

refactor: SDK Architecture - Centralize Logging and Retry Logic#1212

Merged
MervinPraison merged 4 commits into
mainfrom
fix/logging-retry-architecture
Mar 31, 2026
Merged

refactor: SDK Architecture - Centralize Logging and Retry Logic#1212
MervinPraison merged 4 commits into
mainfrom
fix/logging-retry-architecture

Conversation

@MervinPraison

Copy link
Copy Markdown
Owner

Fixes #1131, Fixes #1132. @[/review-chain] please review.

Copilot AI review requested due to automatic review settings March 31, 2026 07:59
@coderabbitai

coderabbitai Bot commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 166 files, which is 16 over the limit of 150.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 57243823-9ea6-4bf8-a81f-14c71fd1bd45

📥 Commits

Reviewing files that changed from the base of the PR and between 64ae40e and ba3a3c3.

⛔ Files ignored due to path filters (2)
  • src/praisonai-agents/uv.lock is excluded by !**/*.lock
  • src/praisonai/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (166)
  • .github/workflows/test-core.yml
  • .github/workflows/test-optimized.yml
  • docker/Dockerfile.chat
  • docker/Dockerfile.dev
  • docker/Dockerfile.ui
  • src/praisonai-agents/praisonaiagents/agent/agent.py
  • src/praisonai-agents/praisonaiagents/agent/audio_agent.py
  • src/praisonai-agents/praisonaiagents/agent/autonomy.py
  • src/praisonai-agents/praisonaiagents/agent/code_agent.py
  • src/praisonai-agents/praisonaiagents/agent/context_agent.py
  • src/praisonai-agents/praisonaiagents/agent/cost_persistence.py
  • src/praisonai-agents/praisonaiagents/agent/deep_research_agent.py
  • src/praisonai-agents/praisonaiagents/agent/embedding_agent.py
  • src/praisonai-agents/praisonaiagents/agent/handoff.py
  • src/praisonai-agents/praisonaiagents/agent/heartbeat.py
  • src/praisonai-agents/praisonaiagents/agent/image_agent.py
  • src/praisonai-agents/praisonaiagents/agent/loop_detection.py
  • src/praisonai-agents/praisonaiagents/agent/message_queue.py
  • src/praisonai-agents/praisonaiagents/agent/ocr_agent.py
  • src/praisonai-agents/praisonaiagents/agent/prompt_expander_agent.py
  • src/praisonai-agents/praisonaiagents/agent/query_rewriter_agent.py
  • src/praisonai-agents/praisonaiagents/agent/realtime_agent.py
  • src/praisonai-agents/praisonaiagents/agent/router_agent.py
  • src/praisonai-agents/praisonaiagents/agent/summarization.py
  • src/praisonai-agents/praisonaiagents/agent/video_agent.py
  • src/praisonai-agents/praisonaiagents/agent/vision_agent.py
  • src/praisonai-agents/praisonaiagents/agents/agents.py
  • src/praisonai-agents/praisonaiagents/agents/auto_rag_agent.py
  • src/praisonai-agents/praisonaiagents/agents/autoagents.py
  • src/praisonai-agents/praisonaiagents/agents/delegator.py
  • src/praisonai-agents/praisonaiagents/approval/__init__.py
  • src/praisonai-agents/praisonaiagents/approval/backends.py
  • src/praisonai-agents/praisonaiagents/approval/registry.py
  • src/praisonai-agents/praisonaiagents/background/runner.py
  • src/praisonai-agents/praisonaiagents/background/task.py
  • src/praisonai-agents/praisonaiagents/bus/bus.py
  • src/praisonai-agents/praisonaiagents/checkpoints/service.py
  • src/praisonai-agents/praisonaiagents/conditions/evaluator.py
  • src/praisonai-agents/praisonaiagents/context/aggregator.py
  • src/praisonai-agents/praisonaiagents/context/fast/async_file_ops.py
  • src/praisonai-agents/praisonaiagents/context/fast/compressor.py
  • src/praisonai-agents/praisonaiagents/context/fast/context_injector.py
  • src/praisonai-agents/praisonaiagents/context/fast/fast_context.py
  • src/praisonai-agents/praisonaiagents/context/fast/fast_context_agent.py
  • src/praisonai-agents/praisonaiagents/context/fast/index_manager.py
  • src/praisonai-agents/praisonaiagents/context/fast/indexer/file_indexer.py
  • src/praisonai-agents/praisonaiagents/context/fast/indexer/file_watcher.py
  • src/praisonai-agents/praisonaiagents/context/fast/indexer/symbol_indexer.py
  • src/praisonai-agents/praisonaiagents/context/fast/parallel_executor.py
  • src/praisonai-agents/praisonaiagents/context/fast/search_backends.py
  • src/praisonai-agents/praisonaiagents/context/fast/search_strategy.py
  • src/praisonai-agents/praisonaiagents/context/fast/search_tools.py
  • src/praisonai-agents/praisonaiagents/context/instrumentation.py
  • src/praisonai-agents/praisonaiagents/context/manager.py
  • src/praisonai-agents/praisonaiagents/context/session_tracker.py
  • src/praisonai-agents/praisonaiagents/context/store.py
  • src/praisonai-agents/praisonaiagents/escalation/doom_loop.py
  • src/praisonai-agents/praisonaiagents/escalation/observability.py
  • src/praisonai-agents/praisonaiagents/escalation/pipeline.py
  • src/praisonai-agents/praisonaiagents/eval/accuracy.py
  • src/praisonai-agents/praisonaiagents/eval/base.py
  • src/praisonai-agents/praisonaiagents/eval/criteria.py
  • src/praisonai-agents/praisonaiagents/eval/grader.py
  • src/praisonai-agents/praisonaiagents/eval/judge.py
  • src/praisonai-agents/praisonaiagents/eval/loop.py
  • src/praisonai-agents/praisonaiagents/eval/media.py
  • src/praisonai-agents/praisonaiagents/eval/performance.py
  • src/praisonai-agents/praisonaiagents/eval/reliability.py
  • src/praisonai-agents/praisonaiagents/eval/tokens.py
  • src/praisonai-agents/praisonaiagents/eval/utils.py
  • src/praisonai-agents/praisonaiagents/guardrails/llm_guardrail.py
  • src/praisonai-agents/praisonaiagents/hooks/registry.py
  • src/praisonai-agents/praisonaiagents/hooks/runner.py
  • src/praisonai-agents/praisonaiagents/knowledge/adapters/mem0_adapter.py
  • src/praisonai-agents/praisonaiagents/knowledge/adapters/mongodb_adapter.py
  • src/praisonai-agents/praisonaiagents/knowledge/index.py
  • src/praisonai-agents/praisonaiagents/knowledge/knowledge.py
  • src/praisonai-agents/praisonaiagents/knowledge/query_engine.py
  • src/praisonai-agents/praisonaiagents/knowledge/readers.py
  • src/praisonai-agents/praisonaiagents/knowledge/rerankers.py
  • src/praisonai-agents/praisonaiagents/knowledge/retrieval.py
  • src/praisonai-agents/praisonaiagents/knowledge/vector_store.py
  • src/praisonai-agents/praisonaiagents/llm/failover.py
  • src/praisonai-agents/praisonaiagents/llm/llm.py
  • src/praisonai-agents/praisonaiagents/llm/model_router.py
  • src/praisonai-agents/praisonaiagents/llm/openai_client.py
  • src/praisonai-agents/praisonaiagents/llm/rate_limiter.py
  • src/praisonai-agents/praisonaiagents/lsp/client.py
  • src/praisonai-agents/praisonaiagents/main.py
  • src/praisonai-agents/praisonaiagents/mcp/mcp.py
  • src/praisonai-agents/praisonaiagents/mcp/mcp_http_stream.py
  • src/praisonai-agents/praisonaiagents/mcp/mcp_server.py
  • src/praisonai-agents/praisonaiagents/mcp/mcp_sse.py
  • src/praisonai-agents/praisonaiagents/mcp/mcp_websocket.py
  • src/praisonai-agents/praisonaiagents/memory/adapters/sqlite_adapter.py
  • src/praisonai-agents/praisonaiagents/memory/auto_memory.py
  • src/praisonai-agents/praisonaiagents/memory/docs_manager.py
  • src/praisonai-agents/praisonaiagents/memory/file_memory.py
  • src/praisonai-agents/praisonaiagents/memory/hooks.py
  • src/praisonai-agents/praisonaiagents/memory/mcp_config.py
  • src/praisonai-agents/praisonaiagents/memory/memory.py
  • src/praisonai-agents/praisonaiagents/memory/rules_manager.py
  • src/praisonai-agents/praisonaiagents/memory/workflows.py
  • src/praisonai-agents/praisonaiagents/permissions/doom_loop.py
  • src/praisonai-agents/praisonaiagents/permissions/manager.py
  • src/praisonai-agents/praisonaiagents/planning/approval.py
  • src/praisonai-agents/praisonaiagents/planning/plan.py
  • src/praisonai-agents/praisonaiagents/planning/planner.py
  • src/praisonai-agents/praisonaiagents/planning/storage.py
  • src/praisonai-agents/praisonaiagents/planning/todo.py
  • src/praisonai-agents/praisonaiagents/plugins/discovery.py
  • src/praisonai-agents/praisonaiagents/plugins/loop_detection_plugin.py
  • src/praisonai-agents/praisonaiagents/plugins/manager.py
  • src/praisonai-agents/praisonaiagents/plugins/plugin.py
  • src/praisonai-agents/praisonaiagents/policy/config.py
  • src/praisonai-agents/praisonaiagents/policy/engine.py
  • src/praisonai-agents/praisonaiagents/rag/pipeline.py
  • src/praisonai-agents/praisonaiagents/scheduler/config_store.py
  • src/praisonai-agents/praisonaiagents/scheduler/loop.py
  • src/praisonai-agents/praisonaiagents/scheduler/runner.py
  • src/praisonai-agents/praisonaiagents/scheduler/store.py
  • src/praisonai-agents/praisonaiagents/server/server.py
  • src/praisonai-agents/praisonaiagents/session/hierarchy.py
  • src/praisonai-agents/praisonaiagents/session/store.py
  • src/praisonai-agents/praisonaiagents/snapshot/snapshot.py
  • src/praisonai-agents/praisonaiagents/storage/backends.py
  • src/praisonai-agents/praisonaiagents/storage/base.py
  • src/praisonai-agents/praisonaiagents/streaming/logging.py
  • src/praisonai-agents/praisonaiagents/task/task.py
  • src/praisonai-agents/praisonaiagents/telemetry/performance_cli.py
  • src/praisonai-agents/praisonaiagents/telemetry/performance_monitor.py
  • src/praisonai-agents/praisonaiagents/telemetry/performance_utils.py
  • src/praisonai-agents/praisonaiagents/telemetry/telemetry.py
  • src/praisonai-agents/praisonaiagents/telemetry/token_telemetry.py
  • src/praisonai-agents/praisonaiagents/tools/ast_grep_tool.py
  • src/praisonai-agents/praisonaiagents/tools/circuit_breaker_integrations.py
  • src/praisonai-agents/praisonaiagents/tools/crawl4ai_tools.py
  • src/praisonai-agents/praisonaiagents/tools/duckduckgo_tools.py
  • src/praisonai-agents/praisonaiagents/tools/email_tools.py
  • src/praisonai-agents/praisonaiagents/tools/exa_tools.py
  • src/praisonai-agents/praisonaiagents/tools/health_monitor.py
  • src/praisonai-agents/praisonaiagents/tools/mentions.py
  • src/praisonai-agents/praisonaiagents/tools/rules_tools.py
  • src/praisonai-agents/praisonaiagents/tools/schedule_tools.py
  • src/praisonai-agents/praisonaiagents/tools/skill_bridge.py
  • src/praisonai-agents/praisonaiagents/tools/subagent_tool.py
  • src/praisonai-agents/praisonaiagents/tools/train/data/generatecot.py
  • src/praisonai-agents/praisonaiagents/tools/web_crawl_tools.py
  • src/praisonai-agents/praisonaiagents/tools/web_search.py
  • src/praisonai-agents/praisonaiagents/ui/a2a/a2a.py
  • src/praisonai-agents/praisonaiagents/ui/agui/agui.py
  • src/praisonai-agents/praisonaiagents/ui/agui/conversion.py
  • src/praisonai-agents/praisonaiagents/utils/resilience.py
  • src/praisonai-agents/praisonaiagents/utils/task_execution.py
  • src/praisonai-agents/praisonaiagents/workflows/workflows.py
  • src/praisonai-agents/pyproject.toml
  • src/praisonai-agents/refactor_logging.py
  • src/praisonai-agents/tests/integration/test_agent_decomposition_real.py
  • src/praisonai-agents/tests/test_embedding_logging.py
  • src/praisonai-agents/tests/unit/test_tools_reliability.py
  • src/praisonai/praisonai.rb
  • src/praisonai/praisonai/deploy.py
  • src/praisonai/praisonai/version.py
  • src/praisonai/pyproject.toml
  • src/praisonai/tests/integration/test_serve_integration.py
  • src/praisonai/tests/integration/test_tracker_complex_tasks.py

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/logging-retry-architecture

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review

Copy link
Copy Markdown
ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Review Summary by Qodo

SDK Architecture Refactor - Centralize Logging and Retry Logic

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• **Centralized logging infrastructure**: Created new _logging.py module providing get_logger()
  function to replace direct logging.getLogger() calls across the entire codebase
• **Centralized resilience policies**: Implemented new utils/resilience.py module with
  @retry_with_backoff and @async_retry_with_backoff decorators supporting exponential backoff and
  jitter
• **Comprehensive refactoring**: Migrated 150+ modules to use centralized logging, improving
  maintainability and enabling unified logging configuration
• **Simplified retry logic**: Refactored web_search.py and duckduckgo_tools.py to use resilience
  decorators instead of manual retry loops
• **Integration test suite**: Added comprehensive test_agent_decomposition_real.py validating all
  34 Agent __init__ parameters and 142 original methods/properties after refactoring
• **Automation script**: Created refactor_logging.py utility for automated logging migration
  across codebase
• **Code cleanup**: Removed redundant logger configuration lines and extra blank lines throughout
  codebase
Diagram
flowchart LR
  A["Direct logging.getLogger<br/>calls across codebase"] -->|"Centralize"| B["_logging.py<br/>get_logger function"]
  C["Manual retry loops<br/>in tools"] -->|"Delegate to"| D["utils/resilience.py<br/>@retry_with_backoff"]
  B -->|"Used by"| E["150+ modules<br/>migrated"]
  D -->|"Used by"| F["web_search.py<br/>duckduckgo_tools.py"]
  E -->|"Validated by"| G["test_agent_decomposition_real.py<br/>Integration tests"]
Loading

Grey Divider

File Changes

1. src/praisonai-agents/tests/integration/test_agent_decomposition_real.py 🧪 Tests +551/-0

Comprehensive Agent decomposition validation test suite

• New comprehensive integration test file with 551 lines validating Agent class decomposition
• Tests all 34 Agent __init__ parameters with smoke tests and real LLM calls
• Verifies 142 original methods and properties still exist after refactoring
• Includes tests for mixin methods (ToolExecutionMixin, ChatHandlerMixin, SessionManagerMixin)

src/praisonai-agents/tests/integration/test_agent_decomposition_real.py


2. src/praisonai-agents/praisonaiagents/utils/resilience.py ✨ Enhancement +120/-0

Centralized resilience and retry policy decorators

• New module providing centralized retry and resilience policies
• Implements retry_with_backoff decorator with exponential backoff and jitter
• Implements async_retry_with_backoff for async operations
• Supports configurable retries, backoff delays, and exception handling

src/praisonai-agents/praisonaiagents/utils/resilience.py


3. src/praisonai-agents/praisonaiagents/_logging.py ✨ Enhancement +0/-0

Centralized logging infrastructure module

• Centralized logging module providing get_logger() function
• Replaces direct logging.getLogger() calls across codebase
• Enables unified logging configuration and management

src/praisonai-agents/praisonaiagents/_logging.py


View more (150)
4. src/praisonai-agents/praisonaiagents/tools/email_tools.py Refactoring +2/-43

Migrate to centralized logging infrastructure

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/tools/email_tools.py


5. src/praisonai-agents/praisonaiagents/agent/agent.py Refactoring +20/-21

Migrate Agent class to centralized logging

• Replaced all logging.getLogger() calls with get_logger() from centralized module
• Added import for centralized logging
• Updated logging configuration methods to use get_logger()
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/agent/agent.py


6. src/praisonai-agents/praisonaiagents/context/manager.py Refactoring +3/-19

Migrate context manager to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Removed extra blank lines between class definitions
• Consolidated logging calls for deduplication and estimation

src/praisonai-agents/praisonaiagents/context/manager.py


7. src/praisonai-agents/praisonaiagents/approval/__init__.py Refactoring +2/-27

Migrate approval module to centralized logging

• Added import for centralized get_logger function
• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/approval/init.py


8. src/praisonai-agents/praisonaiagents/tools/web_search.py Refactoring +21/-48

Migrate web search to centralized logging and resilience

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Refactored _search_duckduckgo() to use @retry_with_backoff decorator
• Simplified retry logic by delegating to resilience decorator
• Removed manual retry loop and exponential backoff implementation

src/praisonai-agents/praisonaiagents/tools/web_search.py


9. src/praisonai-agents/praisonaiagents/agent/loop_detection.py Refactoring +2/-16

Migrate loop detection to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/agent/loop_detection.py


10. src/praisonai-agents/praisonaiagents/agent/handoff.py Refactoring +2/-19

Migrate handoff module to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/agent/handoff.py


11. src/praisonai-agents/praisonaiagents/agent/autonomy.py Refactoring +2/-9

Migrate autonomy module to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module

src/praisonai-agents/praisonaiagents/agent/autonomy.py


12. src/praisonai-agents/praisonaiagents/context/instrumentation.py Refactoring +2/-15

Migrate instrumentation to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/context/instrumentation.py


13. src/praisonai-agents/praisonaiagents/context/fast/indexer/symbol_indexer.py Refactoring +2/-10

Migrate symbol indexer to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/context/fast/indexer/symbol_indexer.py


14. src/praisonai-agents/praisonaiagents/llm/llm.py Refactoring +15/-16

Migrate LLM class to centralized logging

• Replaced all logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Updated logging configuration methods to use get_logger()
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/llm/llm.py


15. src/praisonai-agents/praisonaiagents/workflows/workflows.py Refactoring +2/-20

Migrate workflows to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/workflows/workflows.py


16. src/praisonai-agents/praisonaiagents/agent/deep_research_agent.py Refactoring +2/-10

Migrate deep research agent to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank lines between dataclass definitions

src/praisonai-agents/praisonaiagents/agent/deep_research_agent.py


17. src/praisonai-agents/praisonaiagents/context/fast/compressor.py Refactoring +2/-8

Migrate compressor to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/context/fast/compressor.py


18. src/praisonai-agents/praisonaiagents/context/fast/search_tools.py Refactoring +2/-10

Migrate search tools to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/context/fast/search_tools.py


19. src/praisonai-agents/praisonaiagents/eval/judge.py Refactoring +2/-19

Migrate judge module to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/eval/judge.py


20. src/praisonai-agents/praisonaiagents/agents/agents.py Refactoring +9/-12

Migrate agents manager to centralized logging

• Replaced logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Removed extra blank lines for code formatting
• Cleaned up logger level setting code (removed redundant setLevel calls)

src/praisonai-agents/praisonaiagents/agents/agents.py


21. src/praisonai-agents/praisonaiagents/tools/duckduckgo_tools.py Refactoring +32/-40

Refactor DuckDuckGo search with resilience decorator

• Refactored internet_search() to use @retry_with_backoff decorator
• Extracted core search logic into _do_duckduckgo_search() function
• Simplified retry handling by delegating to resilience decorator
• Removed manual retry loop implementation

src/praisonai-agents/praisonaiagents/tools/duckduckgo_tools.py


22. src/praisonai-agents/praisonaiagents/context/fast/async_file_ops.py Refactoring +2/-7

Migrate async file ops to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/context/fast/async_file_ops.py


23. src/praisonai-agents/praisonaiagents/context/fast/search_backends.py Refactoring +2/-8

Migrate search backends to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/context/fast/search_backends.py


24. src/praisonai-agents/praisonaiagents/approval/backends.py Refactoring +2/-8

Migrate approval backends to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/approval/backends.py


25. src/praisonai-agents/praisonaiagents/mcp/mcp.py Refactoring +19/-19

Migrate MCP module to centralized logging

• Replaced all logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Updated logging configuration to use get_logger()
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/mcp/mcp.py


26. src/praisonai-agents/praisonaiagents/telemetry/telemetry.py Refactoring +4/-10

Migrate telemetry to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/telemetry/telemetry.py


27. src/praisonai-agents/praisonaiagents/tools/crawl4ai_tools.py Refactoring +3/-11

Migrate Crawl4AI tools to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/tools/crawl4ai_tools.py


28. src/praisonai-agents/praisonaiagents/llm/openai_client.py Refactoring +5/-8

Migrate OpenAI client to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/llm/openai_client.py


29. src/praisonai-agents/praisonaiagents/agent/context_agent.py Refactoring +3/-4

Migrate context agent to centralized logging

• Replaced logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/agent/context_agent.py


30. src/praisonai-agents/praisonaiagents/tools/exa_tools.py Refactoring +2/-12

Migrate Exa tools to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/tools/exa_tools.py


31. src/praisonai-agents/praisonaiagents/agent/image_agent.py Refactoring +11/-10

Migrate image agent to centralized logging

• Replaced all logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Updated logging configuration to use get_logger()

src/praisonai-agents/praisonaiagents/agent/image_agent.py


32. src/praisonai-agents/praisonaiagents/tools/health_monitor.py Refactoring +2/-11

Migrate health monitor to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/tools/health_monitor.py


33. src/praisonai-agents/praisonaiagents/agent/video_agent.py Refactoring +5/-6

Migrate video agent to centralized logging

• Replaced all logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Updated logging configuration to use get_logger()
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/agent/video_agent.py


34. src/praisonai-agents/praisonaiagents/agent/audio_agent.py Refactoring +4/-5

Migrate audio agent to centralized logging

• Replaced all logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Updated logging configuration to use get_logger()
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/agent/audio_agent.py


35. src/praisonai-agents/praisonaiagents/agents/delegator.py Refactoring +2/-7

Migrate delegator to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/agents/delegator.py


36. src/praisonai-agents/praisonaiagents/context/fast/index_manager.py Refactoring +2/-6

Migrate index manager to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/context/fast/index_manager.py


37. src/praisonai-agents/praisonaiagents/agent/cost_persistence.py Refactoring +2/-5

Migrate cost persistence to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/agent/cost_persistence.py


38. src/praisonai-agents/praisonaiagents/main.py Refactoring +3/-6

Migrate main module to centralized logging

• Replaced logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/main.py


39. src/praisonai-agents/praisonaiagents/knowledge/query_engine.py Refactoring +2/-12

Migrate query engine to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/knowledge/query_engine.py


40. src/praisonai-agents/praisonaiagents/memory/memory.py Refactoring +11/-12

Migrate memory module to centralized logging

• Replaced all logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Removed extra blank lines and cleaned up logger level setting

src/praisonai-agents/praisonaiagents/memory/memory.py


41. src/praisonai-agents/praisonaiagents/tools/skill_bridge.py Refactoring +2/-9

Migrate skill bridge to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/tools/skill_bridge.py


42. src/praisonai-agents/praisonaiagents/agent/query_rewriter_agent.py Refactoring +2/-4

Migrate query rewriter agent to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/agent/query_rewriter_agent.py


43. src/praisonai-agents/praisonaiagents/memory/workflows.py Refactoring +2/-11

Migrate memory workflows to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/memory/workflows.py


44. src/praisonai-agents/praisonaiagents/agent/ocr_agent.py Refactoring +4/-5

Migrate OCR agent to centralized logging

• Replaced all logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Updated logging configuration to use get_logger()
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/agent/ocr_agent.py


45. src/praisonai-agents/refactor_logging.py Miscellaneous +47/-0

Logging refactoring automation script

• New utility script for automated logging refactoring
• Replaces logging.getLogger() with get_logger() across codebase
• Adds centralized logging imports automatically
• Removes redundant logger configuration lines

src/praisonai-agents/refactor_logging.py


46. src/praisonai-agents/praisonaiagents/mcp/mcp_websocket.py Refactoring +4/-11

Migrate MCP WebSocket to centralized logging

• Replaced logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Removed extra blank lines for code formatting
• Cleaned up logger level setting code

src/praisonai-agents/praisonaiagents/mcp/mcp_websocket.py


47. src/praisonai-agents/praisonaiagents/telemetry/performance_monitor.py Refactoring +2/-12

Migrate performance monitor to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/telemetry/performance_monitor.py


48. src/praisonai-agents/praisonaiagents/tools/rules_tools.py Refactoring +2/-8

Migrate rules tools to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/tools/rules_tools.py


49. src/praisonai-agents/praisonaiagents/plugins/discovery.py Refactoring +2/-9

Migrate plugin discovery to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/plugins/discovery.py


50. src/praisonai-agents/praisonaiagents/telemetry/performance_utils.py Refactoring +3/-9

Migrate performance utils to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/telemetry/performance_utils.py


51. src/praisonai-agents/praisonaiagents/agent/embedding_agent.py Refactoring +5/-6

Migrate embedding agent to centralized logging

• Replaced all logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Updated logging configuration to use get_logger()
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/agent/embedding_agent.py


52. src/praisonai-agents/praisonaiagents/agent/vision_agent.py Refactoring +5/-6

Migrate vision agent to centralized logging

• Replaced all logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Updated logging configuration to use get_logger()
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/agent/vision_agent.py


53. src/praisonai-agents/praisonaiagents/mcp/mcp_http_stream.py Refactoring +4/-9

Migrate MCP HTTP stream to centralized logging

• Replaced logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Removed extra blank lines for code formatting
• Cleaned up logger level setting code

src/praisonai-agents/praisonaiagents/mcp/mcp_http_stream.py


54. src/praisonai-agents/praisonaiagents/tools/ast_grep_tool.py Refactoring +2/-8

Migrate ast-grep tool to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/tools/ast_grep_tool.py


55. src/praisonai-agents/praisonaiagents/agent/prompt_expander_agent.py Refactoring +2/-3

Migrate prompt expander agent to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/agent/prompt_expander_agent.py


56. src/praisonai-agents/praisonaiagents/agent/code_agent.py Refactoring +3/-4

Migrate code agent to centralized logging

• Replaced logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/agent/code_agent.py


57. src/praisonai-agents/praisonaiagents/eval/utils.py Refactoring +2/-8

Migrate eval utils to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/eval/utils.py


58. src/praisonai-agents/praisonaiagents/tools/circuit_breaker_integrations.py Refactoring +2/-8

Migrate circuit breaker integrations to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/tools/circuit_breaker_integrations.py


59. src/praisonai-agents/praisonaiagents/tools/web_crawl_tools.py Refactoring +2/-8

Migrate web crawl tools to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/tools/web_crawl_tools.py


60. src/praisonai-agents/praisonaiagents/bus/bus.py Refactoring +2/-6

Migrate event bus to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/bus/bus.py


61. src/praisonai-agents/praisonaiagents/session/store.py Refactoring +2/-7

Migrate session store to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module

src/praisonai-agents/praisonaiagents/session/store.py


62. src/praisonai-agents/praisonaiagents/context/store.py Refactoring +2/-8

Migrate context store to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/context/store.py


63. src/praisonai-agents/praisonaiagents/knowledge/retrieval.py Refactoring +2/-9

Migrate retrieval module to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/knowledge/retrieval.py


64. src/praisonai-agents/praisonaiagents/tools/schedule_tools.py Refactoring +2/-9

Migrate schedule tools to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/tools/schedule_tools.py


65. src/praisonai-agents/praisonaiagents/agent/summarization.py Refactoring +2/-5

Migrate summarization to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/agent/summarization.py


66. src/praisonai-agents/praisonaiagents/agents/auto_rag_agent.py Refactoring +2/-4

Migrate auto RAG agent to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/agents/auto_rag_agent.py


67. src/praisonai-agents/praisonaiagents/escalation/observability.py Refactoring +2/-9

Migrate escalation observability to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/escalation/observability.py


68. src/praisonai-agents/praisonaiagents/eval/tokens.py Refactoring +2/-8

Migrate eval tokens to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/eval/tokens.py


69. src/praisonai-agents/praisonaiagents/escalation/doom_loop.py Refactoring +2/-7

Migrate doom loop detection to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/escalation/doom_loop.py


70. src/praisonai-agents/praisonaiagents/context/aggregator.py Refactoring +2/-4

Migrate context aggregator to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/context/aggregator.py


71. src/praisonai-agents/praisonaiagents/hooks/registry.py Refactoring +2/-8

Migrate hooks registry to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/hooks/registry.py


72. src/praisonai-agents/praisonaiagents/knowledge/index.py Refactoring +2/-9

Migrate knowledge index to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/knowledge/index.py


73. src/praisonai-agents/praisonaiagents/knowledge/readers.py Refactoring +2/-8

Migrate knowledge readers to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/knowledge/readers.py


74. src/praisonai-agents/praisonaiagents/context/fast/indexer/file_watcher.py Refactoring +2/-5

Migrate file watcher to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/context/fast/indexer/file_watcher.py


75. src/praisonai-agents/praisonaiagents/context/fast/search_strategy.py Refactoring +2/-4

Migrate search strategy to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank lines for code formatting

src/praisonai-agents/praisonaiagents/context/fast/search_strategy.py


76. src/praisonai-agents/praisonaiagents/knowledge/rerankers.py Refactoring +2/-8

Migrate rerankers to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/knowledge/rerankers.py


77. src/praisonai-agents/praisonaiagents/approval/registry.py Refactoring +2/-2

Migrate approval registry to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module

src/praisonai-agents/praisonaiagents/approval/registry.py


78. src/praisonai-agents/praisonaiagents/conditions/evaluator.py Refactoring +2/-4

Migrate conditions evaluator to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/conditions/evaluator.py


79. src/praisonai-agents/praisonaiagents/agents/autoagents.py Refactoring +2/-1

Migrate autoagents to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module

src/praisonai-agents/praisonaiagents/agents/autoagents.py


80. src/praisonai-agents/praisonaiagents/knowledge/vector_store.py Refactoring +2/-8

Migrate vector store to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/knowledge/vector_store.py


81. src/praisonai-agents/praisonaiagents/context/fast/context_injector.py Refactoring +2/-4

Migrate context injector to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/context/fast/context_injector.py


82. src/praisonai-agents/praisonaiagents/storage/backends.py Refactoring +2/-7

Migrate storage backends to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/storage/backends.py


83. src/praisonai-agents/praisonaiagents/storage/base.py Refactoring +2/-7

Migrate storage base to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/storage/base.py


84. src/praisonai-agents/praisonaiagents/agent/message_queue.py Refactoring +2/-5

Migrate message queue to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/agent/message_queue.py


85. src/praisonai-agents/praisonaiagents/mcp/mcp_sse.py Refactoring +4/-6

Migrate MCP SSE to centralized logging

• Replaced logging.getLogger() calls with get_logger()
• Added import for centralized logging module
• Removed extra blank lines for code formatting
• Cleaned up logger level setting code

src/praisonai-agents/praisonaiagents/mcp/mcp_sse.py


86. src/praisonai-agents/praisonaiagents/llm/failover.py Refactoring +2/-6

Migrate LLM failover to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/llm/failover.py


87. src/praisonai-agents/praisonaiagents/ui/agui/conversion.py Refactoring +2/-5

Migrate AGUI conversion to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/ui/agui/conversion.py


88. src/praisonai-agents/praisonaiagents/session/hierarchy.py Refactoring +2/-6

Migrate session hierarchy to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/session/hierarchy.py


89. src/praisonai-agents/praisonaiagents/plugins/plugin.py Refactoring +2/-5

Migrate plugins to centralized logging

• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Added import for centralized logging module
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/plugins/plugin.py


90. src/praisonai-agents/praisonaiagents/task/task.py Refactoring +7/-7

Centralize logging initialization in task module

• Replaced logging.getLogger(__name__) with get_logger(__name__) from centralized logging module
• Removed manual logger level configuration for verbose mode
• Updated third-party logger initialization to use get_logger() instead of logging.getLogger()

src/praisonai-agents/praisonaiagents/task/task.py


91. src/praisonai-agents/praisonaiagents/agent/realtime_agent.py Refactoring +2/-3

Centralize logging in realtime agent module

• Added import for get_logger from centralized logging module
• Replaced logging.getLogger() with get_logger() for logger initialization
• Removed extra blank line for code formatting

src/praisonai-agents/praisonaiagents/agent/realtime_agent.py


92. src/praisonai-agents/praisonaiagents/memory/file_memory.py Refactoring +2/-5

Centralize logging in file memory module

• Added import for get_logger from centralized logging module
• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Removed extra blank line

src/praisonai-agents/praisonaiagents/memory/file_memory.py


93. src/praisonai-agents/praisonaiagents/memory/hooks.py Refactoring +2/-5

Centralize logging in hooks module

• Added import for get_logger from centralized logging module
• Replaced logging.getLogger(__name__) with get_logger(__name__)

src/praisonai-agents/praisonaiagents/memory/hooks.py


94. src/praisonai-agents/praisonaiagents/llm/model_router.py Refactoring +2/-5

Centralize logging in model router module

• Added import for get_logger from centralized logging module
• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Removed extra blank line

src/praisonai-agents/praisonaiagents/llm/model_router.py


95. src/praisonai-agents/praisonaiagents/context/fast/parallel_executor.py Refactoring +2/-4

Centralize logging in parallel executor module

• Added import for get_logger from centralized logging module
• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Removed extra blank line

src/praisonai-agents/praisonaiagents/context/fast/parallel_executor.py


96. src/praisonai-agents/praisonaiagents/agent/heartbeat.py Refactoring +2/-3

Centralize logging in heartbeat module

• Added import for get_logger from centralized logging module
• Replaced logging.getLogger(__name__) with get_logger(__name__)
• Removed extra blank line

src/praisonai-agents/praisonaiagents/agent/heartbeat.py


97. src/praisonai-agents/praisonaiagents/plugins/loop_detection_plugin.py Refactoring +2/-5

Centralize logging in loop detection plugin

• Added import for get_logger from centralized logging module
• Replaced logging.getLogger(__name__) with get_logger(__name__)

src/praisonai-agents/praisonaiagents/plugins/loop_detection_plugin.py


98. src/praisonai-agents/praisonaiagents/checkpoints/service.py Refactoring

@qodo-code-review

qodo-code-review Bot commented Mar 31, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (0) 📎 Requirement gaps (2)

Grey Divider


Action required

1. New retry_with_backoff decorators 📎 Requirement gap ⚙ Maintainability
Description
A new retry/backoff implementation is introduced in praisonaiagents/utils/resilience.py using
bespoke retry loops with jitter and time.sleep/asyncio.sleep. This violates the requirement to
centralize retry/backoff logic in the shared retry utility (or a dedicated core retry module) rather
than creating additional implementations elsewhere.
Code

src/praisonai-agents/praisonaiagents/utils/resilience.py[R17-116]

+def retry_with_backoff(
+    retries: int = 3,
+    backoff_in_seconds: float = 1.0,
+    max_backoff_in_seconds: float = 30.0,
+    exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = (Exception,),
+    jitter_factor: float = 0.25,
+) -> Callable:
+    """
+    Synchronous exponential backoff decorator with jitter to prevent thundering herd.
+
+    Args:
+        retries: Maximum number of retry attempts.
+        backoff_in_seconds: Initial backoff base in seconds.
+        max_backoff_in_seconds: Maximum allowed backoff delay in seconds.
+        exceptions: Exceptions to catch and retry (can be tuple of types).
+        jitter_factor: Randomness factor (e.g., 0.25 = ±25% random jitter).
+    """
+
+    def decorator(func: Callable) -> Callable:
+        @wraps(func)
+        def wrapper(*args: Any, **kwargs: Any) -> Any:
+            attempt = 0
+            while True:
+                try:
+                    return func(*args, **kwargs)
+                except exceptions as e:
+                    if attempt >= retries:
+                        logger.error(
+                            f"Execution failed permanently after {attempt} retries "
+                            f"in '{func.__name__}': {str(e)}",
+                            exc_info=True
+                        )
+                        raise
+
+                    # Calculate exponential backoff
+                    delay = backoff_in_seconds * (2 ** attempt)
+                    delay = min(delay, max_backoff_in_seconds)
+
+                    # Add random jitter
+                    jitter_range = delay * jitter_factor
+                    delay = delay + random.uniform(-jitter_range, jitter_range)
+                    delay = max(0.0, delay)
+                    
+                    attempt += 1
+                    logger.warning(
+                        f"Transient error '{e.__class__.__name__}' in '{func.__name__}'. "
+                        f"Retrying in {delay:.2f}s (Attempt {attempt}/{retries})..."
+                    )
+                    time.sleep(delay)
+
+        return wrapper
+
+    return decorator
+
+
+def async_retry_with_backoff(
+    retries: int = 3,
+    backoff_in_seconds: float = 1.0,
+    max_backoff_in_seconds: float = 30.0,
+    exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = (Exception,),
+    jitter_factor: float = 0.25,
+) -> Callable:
+    """
+    Asynchronous exponential backoff decorator with jitter.
+    
+    Identical semantics to `retry_with_backoff` but uses asyncio.sleep
+    for non-blocking concurrent multi-agent executions.
+    """
+
+    def decorator(func: Callable) -> Callable:
+        @wraps(func)
+        async def wrapper(*args: Any, **kwargs: Any) -> Any:
+            attempt = 0
+            while True:
+                try:
+                    return await func(*args, **kwargs)
+                except exceptions as e:
+                    if attempt >= retries:
+                        logger.error(
+                            f"Async execution failed permanently after {attempt} retries "
+                            f"in '{func.__name__}': {str(e)}",
+                            exc_info=True
+                        )
+                        raise
+
+                    # Calculate exponential backoff
+                    delay = backoff_in_seconds * (2 ** attempt)
+                    delay = min(delay, max_backoff_in_seconds)
+
+                    # Add random jitter
+                    jitter_range = delay * jitter_factor
+                    delay = delay + random.uniform(-jitter_range, jitter_range)
+                    delay = max(0.0, delay)
+                    
+                    attempt += 1
+                    logger.warning(
+                        f"Transient async error '{e.__class__.__name__}' in '{func.__name__}'. "
+                        f"Retrying in {delay:.2f}s (Attempt {attempt}/{retries})..."
+                    )
+                    await asyncio.sleep(delay)
Evidence
PR Compliance ID 1 requires retry/backoff behavior to be implemented only via the centralized retry
utility (e.g., praisonaiagents/tools/retry.py) or a dedicated core retry module; the PR adds a new
module that implements its own exponential backoff + jitter retry loops and sleep calls.

Centralize retry/backoff logic using the shared retry utility
src/praisonai-agents/praisonaiagents/utils/resilience.py[17-116]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`praisonaiagents/utils/resilience.py` introduces a new ad-hoc retry/backoff implementation (sync + async) instead of using/expanding the centralized retry utility.

## Issue Context
The repository already has `praisonaiagents/tools/retry.py`; the compliance requirement is to avoid multiple retry implementations scattered across modules.

## Fix Focus Areas
- src/praisonai-agents/praisonaiagents/utils/resilience.py[17-116]
- src/praisonai-agents/praisonaiagents/tools/retry.py[1-94]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. refactor_logging.py uses print() 📎 Requirement gap ✧ Quality
Description
The newly added refactor_logging.py emits output via print(), bypassing standardized logging.
This violates the requirement to replace console debugging with the standardized logger so output is
centrally formatted/routed.
Code

src/praisonai-agents/refactor_logging.py[R20-47]

+    # Look for logging.getLogger(
+    if 'logging.getLogger' in content:
+        print(f"Refactoring: {path}")
+
+        # Safely insert the new import if it hasn't been added yet
+        if 'from praisonaiagents._logging import get_logger' not in content:
+            # Find a good place to insert it: Replace "import logging" if exists
+            if 'import logging' in content:
+                content = re.sub(r'import logging\n', 'import logging\nfrom praisonaiagents._logging import get_logger\n', content, count=1)
+            else:
+                # Fallback injection at top
+                content = 'from praisonaiagents._logging import get_logger\n' + content
+        
+        # Replace logging.getLogger( -> get_logger(
+        content = re.sub(r'logging\.getLogger\(', 'get_logger(', content)
+
+    # Strip manual setLevel unless it's a specific logic block that explicitly changes it.
+    content = re.sub(r'^[ \t]*logger\.setLevel\(logging\.[A-Z]+\)\s*$', '', content, flags=re.MULTILINE)
+    content = re.sub(r'^[ \t]*logger\.addHandler\(logging\.StreamHandler\(\)\)\s*$', '', content, flags=re.MULTILINE)
+
+    if content != original_content:
+        # Final cleanup for empty lines generated by strip
+        content = content.replace('\n\n\n', '\n\n')
+        with open(path, 'w') as f:
+            f.write(content)
+        changed_files += 1
+
+print(f"\nSuccessfully refactored {changed_files} files!")
Evidence
PR Compliance ID 5 requires using the standardized logger instead of print()/console.print();
the added file contains print(...) statements for operational output.

Replace print/console debugging with standardized logger usage
src/praisonai-agents/refactor_logging.py[20-47]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new `src/praisonai-agents/refactor_logging.py` uses `print()` for status output, which bypasses centralized logging.

## Issue Context
This PR is refactoring logging usage across the codebase and should not introduce new direct console output paths.

## Fix Focus Areas
- src/praisonai-agents/refactor_logging.py[20-47]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. External log levels ignored 🐞 Bug ≡ Correctness
Description
Calls like Agent._configure_logging() now use get_logger("httpx"/"litellm"/"httpcore"), but
get_logger() prefixes these names to "praisonaiagents.<name>", so setLevel() no longer applies to
the real third‑party loggers and the intended noise suppression / debug enabling won’t work.
Code

src/praisonai-agents/praisonaiagents/agent/agent.py[R255-267]

    def _configure_logging(cls):
        """Configure logging settings once for all agent instances."""
        # Configure logging to suppress unwanted outputs
-        logging.getLogger("litellm").setLevel(logging.WARNING)
+        get_logger("litellm").setLevel(logging.WARNING)
        
        # Allow httpx logging when LOGLEVEL=debug, otherwise suppress it
        loglevel = os.environ.get('LOGLEVEL', 'INFO').upper()
        if loglevel == 'DEBUG':
-            logging.getLogger("httpx").setLevel(logging.INFO)
-            logging.getLogger("httpcore").setLevel(logging.INFO)
+            get_logger("httpx").setLevel(logging.INFO)
+            get_logger("httpcore").setLevel(logging.INFO)
        else:
-            logging.getLogger("httpx").setLevel(logging.WARNING)
-            logging.getLogger("httpcore").setLevel(logging.WARNING)
+            get_logger("httpx").setLevel(logging.WARNING)
+            get_logger("httpcore").setLevel(logging.WARNING)
Evidence
Agent._configure_logging attempts to change levels for third-party loggers using
get_logger("httpx"/"httpcore"/"litellm"). However, get_logger() rewrites any name not starting with
"praisonaiagents." into "praisonaiagents.<name>", meaning these setLevel() calls target different
logger names than the actual libraries emit to (e.g., "httpx"). This breaks the PR’s stated goal of
centralized logging control for those dependencies.

src/praisonai-agents/praisonaiagents/agent/agent.py[255-267]
src/praisonai-agents/praisonaiagents/_logging.py[241-299]
src/praisonai-agents/praisonaiagents/mcp/mcp.py[213-238]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`get_logger(name)` currently prefixes any non-`praisonaiagents.*` name to `praisonaiagents.<name>`. After this refactor, many call sites pass explicit third-party logger names (e.g., `"httpx"`, `"httpcore"`, `"litellm"`) into `get_logger()` and then call `.setLevel(...)`. Because the name is rewritten, these calls no longer affect the real third-party loggers.

## Issue Context
The goal of this PR is centralized logging control. Current behavior prevents runtime suppression/enabling of third-party logs.

## Fix Focus Areas
- src/praisonai-agents/praisonaiagents/_logging.py[241-299]
- src/praisonai-agents/praisonaiagents/agent/agent.py[255-267]
- src/praisonai-agents/praisonaiagents/mcp/mcp.py[213-238]

## Expected fix
Adjust `get_logger()` so that when a **name is explicitly provided**, it returns `logging.getLogger(name)` without rewriting/prefixing (or add an opt-out flag and update third-party call sites). Keep the auto-prefix behavior only for the `name is None` auto-detected module-name path (or when the name already starts with `praisonaiagents.`). Then verify the affected call sites actually target the intended third-party logger names.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. Live tests not gated 🐞 Bug ☼ Reliability
Description
tests/integration/test_agent_decomposition_real.py is collected by default and is explicitly
designed for real LLM calls, but it is not marked with pytest’s "live" marker, so conftest.py’s
PRAISONAI_LIVE_TESTS gating will not skip it when API keys are present.
Code

src/praisonai-agents/tests/integration/test_agent_decomposition_real.py[R1-57]

+"""
+Comprehensive real agentic tests validating that the Agent class decomposition
+(tool_execution.py, chat_handler.py, session_manager.py) did not remove any
+features. Tests every single __init__ parameter with real LLM calls.
+
+34 Agent __init__ parameters verified:
+  Core identity: name, role, goal, backstory, instructions
+  LLM config: llm, model, base_url, api_key
+  Tools: tools, allow_delegation, allow_code_execution, code_execution_mode, handoffs
+  Session: auto_save, rate_limiter
+  Consolidated: memory, knowledge, planning, reflection, guardrails, web,
+                context, autonomy, verification_hooks, output, execution,
+                templates, caching, hooks, skills, approval, tool_timeout, learn
+"""
+import os
+import pytest
+import time
+from typing import Any, Dict, Optional
+from praisonaiagents import Agent, tool
+from praisonaiagents.config.feature_configs import (
+    OutputConfig, ExecutionConfig, ReflectionConfig,
+    TemplateConfig, CachingConfig,
+)
+
+
+# ────────────────────────────────────────────────────────────────
+# Test Tools
+# ────────────────────────────────────────────────────────────────
+
+@tool
+def calculate_vault_code(base_number: int, multiplier: int) -> int:
+    """Calculates the secret vault code by multiplying base_number by multiplier."""
+    return base_number * multiplier
+
+
+@tool
+def get_weather(city: str) -> str:
+    """Get current weather for a city."""
+    return f"The weather in {city} is sunny and 22°C."
+
+
+@tool
+def echo_tool(message: str) -> str:
+    """Echoes back the message."""
+    return f"Echo: {message}"
+
+
+# ────────────────────────────────────────────────────────────────
+# Fixtures
+# ────────────────────────────────────────────────────────────────
+
+@pytest.fixture
+def api_key_check():
+    """Ensure an API key is available for real LLM testing."""
+    if not os.environ.get("OPENAI_API_KEY") and not os.environ.get("ANTHROPIC_API_KEY"):
+        pytest.skip("Requires OPENAI_API_KEY or ANTHROPIC_API_KEY")
+
Evidence
The test module states it runs “real LLM calls” and only checks for API keys; meanwhile conftest.py
only auto-skips tests that have the live marker when PRAISONAI_LIVE_TESTS != 1. Without marking
this module/tests as live, it will run whenever keys exist, even if live tests are intended to be
disabled (risking unintended network calls, cost, and CI instability).

src/praisonai-agents/tests/conftest.py[70-77]
src/praisonai-agents/tests/integration/test_agent_decomposition_real.py[1-14]
src/praisonai-agents/tests/integration/test_agent_decomposition_real.py[52-57]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new integration test module intended for real LLM calls is not gated by the repo’s `PRAISONAI_LIVE_TESTS` mechanism because it lacks the `@pytest.mark.live` marker.

## Issue Context
`pytest_collection_modifyitems` in `tests/conftest.py` only skips items with the `live` keyword unless `PRAISONAI_LIVE_TESTS=1`.

## Fix Focus Areas
- src/praisonai-agents/tests/integration/test_agent_decomposition_real.py[1-60]
- src/praisonai-agents/tests/conftest.py[70-77]

## Expected fix
Add module-level gating, e.g.:
- `pytestmark = [pytest.mark.live, pytest.mark.network, pytest.mark.slow]`

Optionally also require the existing `live_test_enabled` fixture for real-call tests (in addition to API-key presence), so the module never makes outbound calls unless explicitly opted in.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. DuckDuckGo retries regression 🐞 Bug ≡ Correctness
Description
internet_search(..., retries=...) still exposes a retries parameter but the refactor hard-codes
retry behavior via @retry_with_backoff(retries=3), so caller-specified retry counts are ignored and
the function’s documented behavior is no longer true.
Code

src/praisonai-agents/praisonaiagents/tools/duckduckgo_tools.py[R21-49]

+from praisonaiagents.utils.resilience import retry_with_backoff
+
+@retry_with_backoff(retries=3, backoff_in_seconds=1.0, exceptions=(Exception,), jitter_factor=0.25)
+def _do_duckduckgo_search(query: str, max_results: int) -> List[Dict]:
+    """Inner core logic wrapped by resilience decorator."""
+    from ddgs import DDGS
+    results = []
+    ddgs = DDGS()
+    
+    # Try text search (use positional 'query' for v8+ compatibility)
+    search_results = list(ddgs.text(query, max_results=max_results))
+    
+    for result in search_results:
+        results.append({
+            "title": result.get("title", ""),
+            "url": result.get("href", ""),
+            "snippet": result.get("body", "")
+        })
+    
+    # If we got results, return them
+    if results:
+        return results
+        
+    raise Exception("DuckDuckGo returned empty results")
+
+
def internet_search(query: str, max_results: int = 5, retries: int = MAX_RETRIES) -> List[Dict]:
    """Perform an internet search using DuckDuckGo with retry logic.
    
Evidence
The helper is decorated with @retry_with_backoff(retries=3, ...), but internet_search() accepts
retries and never uses it—calls always execute _do_duckduckgo_search() with the fixed decorator
settings. This is a silent behavior change from the previous implementation where retries
controlled the loop.

src/praisonai-agents/praisonaiagents/tools/duckduckgo_tools.py[21-69]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`internet_search()` documents and accepts a `retries` parameter, but the refactor moved retry logic to a decorator that is hard-coded to 3 retries. The public API parameter is now ignored.

## Issue Context
This is a regression introduced by replacing the previous in-function retry loop.

## Fix Focus Areas
- src/praisonai-agents/praisonaiagents/tools/duckduckgo_tools.py[17-69]

## Expected fix
Choose one:
1) Remove the `retries` parameter (and unused retry constants/imports) to match the new fixed behavior.
2) Preserve the API by applying the decorator dynamically inside `internet_search`, e.g. wrap a local callable with `retry_with_backoff(retries=retries, ...)` so caller-provided retries are honored.

Also clean up now-unused imports/constants (`time`, `RETRY_DELAY`) if no longer needed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

6. Hard-coded refactor path 🐞 Bug ⚙ Maintainability
Description
refactor_logging.py contains a hard-coded developer absolute path, making the script non-portable
and noisy to keep in the repo as-is.
Code

src/praisonai-agents/refactor_logging.py[R1-5]

+import os
+import re
+
+target_dir = '/Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents'
+
Evidence
The script’s target_dir is set to an absolute /Users/... path, so it will not run for other
developers and is easy to misinterpret as a supported tool.

src/praisonai-agents/refactor_logging.py[1-5]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A committed helper script hard-codes a local filesystem path.

## Issue Context
While not part of the package runtime, keeping non-portable scripts in-tree increases confusion/maintenance overhead.

## Fix Focus Areas
- src/praisonai-agents/refactor_logging.py[1-12]

## Expected fix
Either delete the script from the repo (preferred) or change it to accept `target_dir` via CLI arg/env var and default to a repo-relative path.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a centralized logging system using a new get_logger utility and introduces a resilience module for standardized retry logic. While the architectural direction is sound, the PR is currently in a broken state because the _logging.py module was not included in the file set, which will trigger immediate import errors. Furthermore, the automated refactoring script used for this migration has introduced multiple syntax errors by leaving conditional blocks empty after removing setLevel calls, and the script itself contains hardcoded local directory paths that limit its portability.

import time
import json
import logging
from praisonaiagents._logging import get_logger

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The module praisonaiagents._logging is imported here and throughout the refactored files, but the file _logging.py itself is missing from this pull request. This will cause an ImportError and break the package.

Comment on lines 451 to +456
if _verbose >= 5:
logger.setLevel(logging.INFO)

elif _verbose >= 3:
logger.setLevel(logging.DEBUG)

else:
logger.setLevel(logging.WARNING)


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The if/elif/else blocks are empty after the refactor, which will cause an IndentationError. These blocks should be removed if manual level setting is no longer required.

Comment on lines 507 to +511
if debug:
logger.setLevel(logging.DEBUG)

else:
# Set to WARNING by default to hide INFO messages
logger.setLevel(logging.WARNING)


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Empty if/else blocks will cause an IndentationError. These should be removed.

Comment on lines 64 to +65
if debug:
logger.setLevel(logging.DEBUG)


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Empty if block will cause an IndentationError. This should be removed.

Comment on lines 153 to +157
if debug:
logger.setLevel(logging.DEBUG)

else:
# Set to WARNING by default to hide INFO messages
logger.setLevel(logging.WARNING)


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Empty if/else blocks will cause an IndentationError. These should be removed.

Comment on lines 70 to +73
if verbose >= 5:
logger.setLevel(logging.INFO)

else:
logger.setLevel(logging.WARNING)


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Empty if/else blocks will cause an IndentationError. These should be removed.

Comment on lines 256 to +259
if verbose >= 5:
logger.setLevel(logging.INFO)

else:
logger.setLevel(logging.WARNING)


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Empty if/else blocks will cause an IndentationError. These should be removed.

Comment on lines 339 to 342
if verbose >= 5:
logger.setLevel(logging.INFO)

else:
logger.setLevel(logging.WARNING)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Empty if/else blocks will cause an IndentationError. These should be removed.

import os
import re

target_dir = '/Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The target_dir is hardcoded to a specific local path on the author's machine. This script will fail on any other environment. It should be refactored to use relative paths or removed if it was only intended for a one-time local refactor.

content = re.sub(r'logging\.getLogger\(', 'get_logger(', content)

# Strip manual setLevel unless it's a specific logic block that explicitly changes it.
content = re.sub(r'^[ \t]*logger\.setLevel\(logging\.[A-Z]+\)\s*$', '', content, flags=re.MULTILINE)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This regex-based removal of logger.setLevel calls is responsible for the multiple IndentationError issues found in this PR. It removes the statement but leaves the parent if/else blocks empty. The script should be improved to detect and remove the entire conditional block if it becomes empty.

Comment on lines +17 to +116
def retry_with_backoff(
retries: int = 3,
backoff_in_seconds: float = 1.0,
max_backoff_in_seconds: float = 30.0,
exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = (Exception,),
jitter_factor: float = 0.25,
) -> Callable:
"""
Synchronous exponential backoff decorator with jitter to prevent thundering herd.

Args:
retries: Maximum number of retry attempts.
backoff_in_seconds: Initial backoff base in seconds.
max_backoff_in_seconds: Maximum allowed backoff delay in seconds.
exceptions: Exceptions to catch and retry (can be tuple of types).
jitter_factor: Randomness factor (e.g., 0.25 = ±25% random jitter).
"""

def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> Any:
attempt = 0
while True:
try:
return func(*args, **kwargs)
except exceptions as e:
if attempt >= retries:
logger.error(
f"Execution failed permanently after {attempt} retries "
f"in '{func.__name__}': {str(e)}",
exc_info=True
)
raise

# Calculate exponential backoff
delay = backoff_in_seconds * (2 ** attempt)
delay = min(delay, max_backoff_in_seconds)

# Add random jitter
jitter_range = delay * jitter_factor
delay = delay + random.uniform(-jitter_range, jitter_range)
delay = max(0.0, delay)

attempt += 1
logger.warning(
f"Transient error '{e.__class__.__name__}' in '{func.__name__}'. "
f"Retrying in {delay:.2f}s (Attempt {attempt}/{retries})..."
)
time.sleep(delay)

return wrapper

return decorator


def async_retry_with_backoff(
retries: int = 3,
backoff_in_seconds: float = 1.0,
max_backoff_in_seconds: float = 30.0,
exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = (Exception,),
jitter_factor: float = 0.25,
) -> Callable:
"""
Asynchronous exponential backoff decorator with jitter.

Identical semantics to `retry_with_backoff` but uses asyncio.sleep
for non-blocking concurrent multi-agent executions.
"""

def decorator(func: Callable) -> Callable:
@wraps(func)
async def wrapper(*args: Any, **kwargs: Any) -> Any:
attempt = 0
while True:
try:
return await func(*args, **kwargs)
except exceptions as e:
if attempt >= retries:
logger.error(
f"Async execution failed permanently after {attempt} retries "
f"in '{func.__name__}': {str(e)}",
exc_info=True
)
raise

# Calculate exponential backoff
delay = backoff_in_seconds * (2 ** attempt)
delay = min(delay, max_backoff_in_seconds)

# Add random jitter
jitter_range = delay * jitter_factor
delay = delay + random.uniform(-jitter_range, jitter_range)
delay = max(0.0, delay)

attempt += 1
logger.warning(
f"Transient async error '{e.__class__.__name__}' in '{func.__name__}'. "
f"Retrying in {delay:.2f}s (Attempt {attempt}/{retries})..."
)
await asyncio.sleep(delay)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. New retry_with_backoff decorators 📎 Requirement gap ⚙ Maintainability

A new retry/backoff implementation is introduced in praisonaiagents/utils/resilience.py using
bespoke retry loops with jitter and time.sleep/asyncio.sleep. This violates the requirement to
centralize retry/backoff logic in the shared retry utility (or a dedicated core retry module) rather
than creating additional implementations elsewhere.
Agent Prompt
## Issue description
`praisonaiagents/utils/resilience.py` introduces a new ad-hoc retry/backoff implementation (sync + async) instead of using/expanding the centralized retry utility.

## Issue Context
The repository already has `praisonaiagents/tools/retry.py`; the compliance requirement is to avoid multiple retry implementations scattered across modules.

## Fix Focus Areas
- src/praisonai-agents/praisonaiagents/utils/resilience.py[17-116]
- src/praisonai-agents/praisonaiagents/tools/retry.py[1-94]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +20 to +47
# Look for logging.getLogger(
if 'logging.getLogger' in content:
print(f"Refactoring: {path}")

# Safely insert the new import if it hasn't been added yet
if 'from praisonaiagents._logging import get_logger' not in content:
# Find a good place to insert it: Replace "import logging" if exists
if 'import logging' in content:
content = re.sub(r'import logging\n', 'import logging\nfrom praisonaiagents._logging import get_logger\n', content, count=1)
else:
# Fallback injection at top
content = 'from praisonaiagents._logging import get_logger\n' + content

# Replace logging.getLogger( -> get_logger(
content = re.sub(r'logging\.getLogger\(', 'get_logger(', content)

# Strip manual setLevel unless it's a specific logic block that explicitly changes it.
content = re.sub(r'^[ \t]*logger\.setLevel\(logging\.[A-Z]+\)\s*$', '', content, flags=re.MULTILINE)
content = re.sub(r'^[ \t]*logger\.addHandler\(logging\.StreamHandler\(\)\)\s*$', '', content, flags=re.MULTILINE)

if content != original_content:
# Final cleanup for empty lines generated by strip
content = content.replace('\n\n\n', '\n\n')
with open(path, 'w') as f:
f.write(content)
changed_files += 1

print(f"\nSuccessfully refactored {changed_files} files!")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. refactor_logging.py uses print() 📎 Requirement gap ✧ Quality

The newly added refactor_logging.py emits output via print(), bypassing standardized logging.
This violates the requirement to replace console debugging with the standardized logger so output is
centrally formatted/routed.
Agent Prompt
## Issue description
The new `src/praisonai-agents/refactor_logging.py` uses `print()` for status output, which bypasses centralized logging.

## Issue Context
This PR is refactoring logging usage across the codebase and should not introduce new direct console output paths.

## Fix Focus Areas
- src/praisonai-agents/refactor_logging.py[20-47]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines 255 to +267
def _configure_logging(cls):
"""Configure logging settings once for all agent instances."""
# Configure logging to suppress unwanted outputs
logging.getLogger("litellm").setLevel(logging.WARNING)
get_logger("litellm").setLevel(logging.WARNING)

# Allow httpx logging when LOGLEVEL=debug, otherwise suppress it
loglevel = os.environ.get('LOGLEVEL', 'INFO').upper()
if loglevel == 'DEBUG':
logging.getLogger("httpx").setLevel(logging.INFO)
logging.getLogger("httpcore").setLevel(logging.INFO)
get_logger("httpx").setLevel(logging.INFO)
get_logger("httpcore").setLevel(logging.INFO)
else:
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING)
get_logger("httpx").setLevel(logging.WARNING)
get_logger("httpcore").setLevel(logging.WARNING)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. External log levels ignored 🐞 Bug ≡ Correctness

Calls like Agent._configure_logging() now use get_logger("httpx"/"litellm"/"httpcore"), but
get_logger() prefixes these names to "praisonaiagents.<name>", so setLevel() no longer applies to
the real third‑party loggers and the intended noise suppression / debug enabling won’t work.
Agent Prompt
## Issue description
`get_logger(name)` currently prefixes any non-`praisonaiagents.*` name to `praisonaiagents.<name>`. After this refactor, many call sites pass explicit third-party logger names (e.g., `"httpx"`, `"httpcore"`, `"litellm"`) into `get_logger()` and then call `.setLevel(...)`. Because the name is rewritten, these calls no longer affect the real third-party loggers.

## Issue Context
The goal of this PR is centralized logging control. Current behavior prevents runtime suppression/enabling of third-party logs.

## Fix Focus Areas
- src/praisonai-agents/praisonaiagents/_logging.py[241-299]
- src/praisonai-agents/praisonaiagents/agent/agent.py[255-267]
- src/praisonai-agents/praisonaiagents/mcp/mcp.py[213-238]

## Expected fix
Adjust `get_logger()` so that when a **name is explicitly provided**, it returns `logging.getLogger(name)` without rewriting/prefixing (or add an opt-out flag and update third-party call sites). Keep the auto-prefix behavior only for the `name is None` auto-detected module-name path (or when the name already starts with `praisonaiagents.`). Then verify the affected call sites actually target the intended third-party logger names.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1 to +57
"""
Comprehensive real agentic tests validating that the Agent class decomposition
(tool_execution.py, chat_handler.py, session_manager.py) did not remove any
features. Tests every single __init__ parameter with real LLM calls.

34 Agent __init__ parameters verified:
Core identity: name, role, goal, backstory, instructions
LLM config: llm, model, base_url, api_key
Tools: tools, allow_delegation, allow_code_execution, code_execution_mode, handoffs
Session: auto_save, rate_limiter
Consolidated: memory, knowledge, planning, reflection, guardrails, web,
context, autonomy, verification_hooks, output, execution,
templates, caching, hooks, skills, approval, tool_timeout, learn
"""
import os
import pytest
import time
from typing import Any, Dict, Optional
from praisonaiagents import Agent, tool
from praisonaiagents.config.feature_configs import (
OutputConfig, ExecutionConfig, ReflectionConfig,
TemplateConfig, CachingConfig,
)


# ────────────────────────────────────────────────────────────────
# Test Tools
# ────────────────────────────────────────────────────────────────

@tool
def calculate_vault_code(base_number: int, multiplier: int) -> int:
"""Calculates the secret vault code by multiplying base_number by multiplier."""
return base_number * multiplier


@tool
def get_weather(city: str) -> str:
"""Get current weather for a city."""
return f"The weather in {city} is sunny and 22°C."


@tool
def echo_tool(message: str) -> str:
"""Echoes back the message."""
return f"Echo: {message}"


# ────────────────────────────────────────────────────────────────
# Fixtures
# ────────────────────────────────────────────────────────────────

@pytest.fixture
def api_key_check():
"""Ensure an API key is available for real LLM testing."""
if not os.environ.get("OPENAI_API_KEY") and not os.environ.get("ANTHROPIC_API_KEY"):
pytest.skip("Requires OPENAI_API_KEY or ANTHROPIC_API_KEY")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Live tests not gated 🐞 Bug ☼ Reliability

tests/integration/test_agent_decomposition_real.py is collected by default and is explicitly
designed for real LLM calls, but it is not marked with pytest’s "live" marker, so conftest.py’s
PRAISONAI_LIVE_TESTS gating will not skip it when API keys are present.
Agent Prompt
## Issue description
A new integration test module intended for real LLM calls is not gated by the repo’s `PRAISONAI_LIVE_TESTS` mechanism because it lacks the `@pytest.mark.live` marker.

## Issue Context
`pytest_collection_modifyitems` in `tests/conftest.py` only skips items with the `live` keyword unless `PRAISONAI_LIVE_TESTS=1`.

## Fix Focus Areas
- src/praisonai-agents/tests/integration/test_agent_decomposition_real.py[1-60]
- src/praisonai-agents/tests/conftest.py[70-77]

## Expected fix
Add module-level gating, e.g.:
- `pytestmark = [pytest.mark.live, pytest.mark.network, pytest.mark.slow]`

Optionally also require the existing `live_test_enabled` fixture for real-call tests (in addition to API-key presence), so the module never makes outbound calls unless explicitly opted in.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@github-actions

Copy link
Copy Markdown
Contributor

@copilot Do a thorough review of this PR. Read ALL existing reviewer comments above first.

Review areas:

  1. Bloat check: Are changes minimal and focused?
  2. Security: Any hardcoded secrets, unsafe eval/exec, missing input validation?
  3. Performance: Any module-level heavy imports? Hot-path regressions?
  4. Tests: Are tests included? Do they cover the changes adequately?
  5. Backward compat: Any public API changes without deprecation?
  6. Code quality: DRY violations, naming conventions, error handling?
  7. Suggest specific improvements with code examples where possible

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to standardize logging across the SDK by routing modules through praisonaiagents._logging.get_logger, and to reduce duplicated retry/backoff logic by introducing a shared retry decorator and applying it to select tools.

Changes:

  • Replaced many logging.getLogger(...) usages with centralized get_logger(...) across agents, tools, and subsystems.
  • Added praisonaiagents/utils/resilience.py providing sync/async retry-with-backoff decorators.
  • Refactored DuckDuckGo search retry logic (and web_search’s DuckDuckGo provider) to use the new decorator.

Reviewed changes

Copilot reviewed 152 out of 152 changed files in this pull request and generated 20 comments.

Show a summary per file
File Description
src/praisonai-agents/refactor_logging.py Adds a refactor helper script (currently non-portable due to absolute paths).
src/praisonai-agents/praisonaiagents/workflows/workflows.py Switch workflow module logging to get_logger.
src/praisonai-agents/praisonaiagents/utils/task_execution.py Switch utility logging to get_logger.
src/praisonai-agents/praisonaiagents/utils/resilience.py New retry/backoff decorators (sync + async).
src/praisonai-agents/praisonaiagents/ui/agui/conversion.py Switch UI conversion logging to get_logger.
src/praisonai-agents/praisonaiagents/ui/agui/agui.py Switch AGUI logging to get_logger.
src/praisonai-agents/praisonaiagents/ui/a2a/a2a.py Switch A2A logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/web_search.py Switch logging to get_logger; DuckDuckGo provider uses retry decorator.
src/praisonai-agents/praisonaiagents/tools/web_crawl_tools.py Switch crawler tool logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/train/data/generatecot.py Switch training script logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/subagent_tool.py Switch tool logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/skill_bridge.py Switch skill bridge logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/schedule_tools.py Switch schedule tools logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/rules_tools.py Switch rules tools logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/mentions.py Switch mentions parser logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/health_monitor.py Switch health monitor logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/exa_tools.py Switch Exa tools logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/email_tools.py Switch email tools logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/duckduckgo_tools.py Refactor DuckDuckGo retry logic to decorator (but currently ignores retries argument).
src/praisonai-agents/praisonaiagents/tools/crawl4ai_tools.py Switch Crawl4AI tools logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/circuit_breaker_integrations.py Switch integrations logging to get_logger.
src/praisonai-agents/praisonaiagents/tools/ast_grep_tool.py Switch ast-grep tool logging to get_logger.
src/praisonai-agents/praisonaiagents/telemetry/token_telemetry.py Switch telemetry bridge logging to get_logger.
src/praisonai-agents/praisonaiagents/telemetry/telemetry.py Switch telemetry logging to get_logger.
src/praisonai-agents/praisonaiagents/telemetry/performance_utils.py Switch performance utils logging to get_logger.
src/praisonai-agents/praisonaiagents/telemetry/performance_monitor.py Switch performance monitor logging to get_logger.
src/praisonai-agents/praisonaiagents/telemetry/performance_cli.py Switch performance CLI logging to get_logger.
src/praisonai-agents/praisonaiagents/task/task.py Switch task logging to get_logger and adjust logger-level handling (currently introduces empty blocks).
src/praisonai-agents/praisonaiagents/streaming/logging.py Switch stream logger default to get_logger.
src/praisonai-agents/praisonaiagents/storage/base.py Switch storage base logging to get_logger.
src/praisonai-agents/praisonaiagents/storage/backends.py Switch storage backends logging to get_logger.
src/praisonai-agents/praisonaiagents/snapshot/snapshot.py Switch snapshot logging to get_logger.
src/praisonai-agents/praisonaiagents/session/store.py Switch session store logging to get_logger.
src/praisonai-agents/praisonaiagents/session/hierarchy.py Switch session hierarchy logging to get_logger.
src/praisonai-agents/praisonaiagents/server/server.py Switch server logging to get_logger.
src/praisonai-agents/praisonaiagents/scheduler/store.py Switch scheduler store logging to get_logger.
src/praisonai-agents/praisonaiagents/scheduler/runner.py Switch scheduler runner logging to get_logger.
src/praisonai-agents/praisonaiagents/scheduler/loop.py Switch scheduler loop logging to get_logger.
src/praisonai-agents/praisonaiagents/scheduler/config_store.py Switch scheduler config store logging to get_logger.
src/praisonai-agents/praisonaiagents/rag/pipeline.py Switch RAG pipeline logging to get_logger.
src/praisonai-agents/praisonaiagents/policy/engine.py Switch policy engine logging to get_logger.
src/praisonai-agents/praisonaiagents/policy/config.py Switch policy config logging to get_logger.
src/praisonai-agents/praisonaiagents/plugins/plugin.py Switch plugin base logging to get_logger.
src/praisonai-agents/praisonaiagents/plugins/manager.py Switch plugin manager logging to get_logger.
src/praisonai-agents/praisonaiagents/plugins/loop_detection_plugin.py Switch loop detection plugin logging to get_logger.
src/praisonai-agents/praisonaiagents/plugins/discovery.py Switch plugin discovery logging to get_logger.
src/praisonai-agents/praisonaiagents/planning/todo.py Switch todo logging to get_logger.
src/praisonai-agents/praisonaiagents/planning/storage.py Switch planning storage logging to get_logger.
src/praisonai-agents/praisonaiagents/planning/planner.py Switch planner logging to get_logger.
src/praisonai-agents/praisonaiagents/planning/plan.py Switch plan logging to get_logger.
src/praisonai-agents/praisonaiagents/planning/approval.py Switch planning approval logging to get_logger.
src/praisonai-agents/praisonaiagents/permissions/manager.py Switch permissions manager logging to get_logger.
src/praisonai-agents/praisonaiagents/permissions/doom_loop.py Switch doom loop logging to get_logger.
src/praisonai-agents/praisonaiagents/memory/workflows.py Switch memory workflows logging to get_logger.
src/praisonai-agents/praisonaiagents/memory/rules_manager.py Switch rules manager logging to get_logger.
src/praisonai-agents/praisonaiagents/memory/memory.py Switch memory logging + logger-level handling (currently introduces empty blocks).
src/praisonai-agents/praisonaiagents/memory/mcp_config.py Switch MCP config logging to get_logger.
src/praisonai-agents/praisonaiagents/memory/hooks.py Switch memory hooks logging to get_logger.
src/praisonai-agents/praisonaiagents/memory/file_memory.py Switch file memory logging to get_logger.
src/praisonai-agents/praisonaiagents/memory/docs_manager.py Switch docs manager logging to get_logger.
src/praisonai-agents/praisonaiagents/memory/auto_memory.py Switch auto memory logging to get_logger.
src/praisonai-agents/praisonaiagents/memory/adapters/sqlite_adapter.py Switch adapter logging + logger-level handling (currently introduces empty blocks).
src/praisonai-agents/praisonaiagents/mcp/mcp.py Switch MCP logging configuration to get_logger.
src/praisonai-agents/praisonaiagents/mcp/mcp_websocket.py Switch logging + logger-level handling (currently introduces empty blocks).
src/praisonai-agents/praisonaiagents/mcp/mcp_sse.py Switch logging + logger-level handling (currently introduces empty blocks).
src/praisonai-agents/praisonaiagents/mcp/mcp_server.py Switch logging + logger-level handling (currently introduces empty blocks).
src/praisonai-agents/praisonaiagents/mcp/mcp_http_stream.py Switch logging + logger-level handling (currently introduces empty blocks).
src/praisonai-agents/praisonaiagents/main.py Switch debug-level checks to use get_logger.
src/praisonai-agents/praisonaiagents/lsp/client.py Switch LSP client logging to get_logger.
src/praisonai-agents/praisonaiagents/llm/rate_limiter.py Switch rate limiter logging to get_logger.
src/praisonai-agents/praisonaiagents/llm/openai_client.py Switch OpenAI client logging to get_logger.
src/praisonai-agents/praisonaiagents/llm/model_router.py Switch model router logging to get_logger.
src/praisonai-agents/praisonaiagents/llm/llm.py Switch LLM logging + configure external logger levels (currently using get_logger for third-party names).
src/praisonai-agents/praisonaiagents/llm/failover.py Switch failover logging to get_logger.
src/praisonai-agents/praisonaiagents/knowledge/vector_store.py Switch knowledge logging to get_logger.
src/praisonai-agents/praisonaiagents/knowledge/retrieval.py Switch retrieval logging to get_logger.
src/praisonai-agents/praisonaiagents/knowledge/rerankers.py Switch reranker logging to get_logger.
src/praisonai-agents/praisonaiagents/knowledge/readers.py Switch readers logging to get_logger.
src/praisonai-agents/praisonaiagents/knowledge/query_engine.py Switch query engine logging to get_logger.
src/praisonai-agents/praisonaiagents/knowledge/knowledge.py Switch knowledge module logging to get_logger.
src/praisonai-agents/praisonaiagents/knowledge/index.py Switch index logging to get_logger.
src/praisonai-agents/praisonaiagents/knowledge/adapters/mongodb_adapter.py Switch adapter logging to get_logger.
src/praisonai-agents/praisonaiagents/knowledge/adapters/mem0_adapter.py Switch adapter logging to get_logger.
src/praisonai-agents/praisonaiagents/hooks/runner.py Switch hook runner logging to get_logger.
src/praisonai-agents/praisonaiagents/hooks/registry.py Switch hook registry logging to get_logger.
src/praisonai-agents/praisonaiagents/guardrails/llm_guardrail.py Switch guardrail logging to get_logger.
src/praisonai-agents/praisonaiagents/eval/utils.py Switch eval utils logging to get_logger.
src/praisonai-agents/praisonaiagents/eval/tokens.py Switch token eval logging to get_logger.
src/praisonai-agents/praisonaiagents/eval/reliability.py Switch reliability evaluator logging to get_logger.
src/praisonai-agents/praisonaiagents/eval/performance.py Switch performance evaluator logging to get_logger.
src/praisonai-agents/praisonaiagents/eval/media.py Switch media evaluator logging to get_logger.
src/praisonai-agents/praisonaiagents/eval/loop.py Switch eval loop logging to get_logger.
src/praisonai-agents/praisonaiagents/eval/judge.py Switch judge logging to get_logger.
src/praisonai-agents/praisonaiagents/eval/grader.py Switch grader logging to get_logger.
src/praisonai-agents/praisonaiagents/eval/criteria.py Switch criteria evaluator logging to get_logger.
src/praisonai-agents/praisonaiagents/eval/base.py Switch base evaluator logging to get_logger.
src/praisonai-agents/praisonaiagents/eval/accuracy.py Switch accuracy evaluator logging to get_logger.
src/praisonai-agents/praisonaiagents/escalation/pipeline.py Switch escalation pipeline logging to get_logger.
src/praisonai-agents/praisonaiagents/escalation/observability.py Switch observability logging to get_logger.
src/praisonai-agents/praisonaiagents/escalation/doom_loop.py Switch doom loop logging to get_logger.
src/praisonai-agents/praisonaiagents/context/store.py Switch context store logging to get_logger.
src/praisonai-agents/praisonaiagents/context/session_tracker.py Switch session tracker logging to get_logger.
src/praisonai-agents/praisonaiagents/context/manager.py Adjust logging in dedup/token mismatch paths (currently missing get_logger import).
src/praisonai-agents/praisonaiagents/context/instrumentation.py Switch instrumentation logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/search_tools.py Switch fast search tools logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/search_strategy.py Switch fast search strategy logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/search_backends.py Switch search backends logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/parallel_executor.py Switch parallel executor logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/indexer/symbol_indexer.py Switch symbol indexer logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/indexer/file_watcher.py Switch file watcher logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/indexer/file_indexer.py Switch file indexer logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/index_manager.py Switch index manager logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/fast_context.py Switch fast context logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/fast_context_agent.py Switch fast context agent logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/context_injector.py Switch context injector logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/compressor.py Switch compressor logging to get_logger.
src/praisonai-agents/praisonaiagents/context/fast/async_file_ops.py Switch async file ops logging to get_logger.
src/praisonai-agents/praisonaiagents/context/aggregator.py Switch context aggregator logging to get_logger.
src/praisonai-agents/praisonaiagents/conditions/evaluator.py Switch condition evaluator logging to get_logger.
src/praisonai-agents/praisonaiagents/checkpoints/service.py Switch checkpoint service logging to get_logger.
src/praisonai-agents/praisonaiagents/bus/bus.py Switch event bus logging to get_logger.
src/praisonai-agents/praisonaiagents/background/task.py Switch background task logging to get_logger.
src/praisonai-agents/praisonaiagents/background/runner.py Switch background runner logging to get_logger.
src/praisonai-agents/praisonaiagents/approval/registry.py Switch approval registry logging to get_logger.
src/praisonai-agents/praisonaiagents/approval/backends.py Switch approval backends logging to get_logger.
src/praisonai-agents/praisonaiagents/approval/init.py Switch approval module logging to get_logger.
src/praisonai-agents/praisonaiagents/agents/delegator.py Switch delegator logging to get_logger.
src/praisonai-agents/praisonaiagents/agents/autoagents.py Switch autoagents debug logging to get_logger.
src/praisonai-agents/praisonaiagents/agents/auto_rag_agent.py Switch auto RAG logging to get_logger.
src/praisonai-agents/praisonaiagents/agents/agents.py Switch manager logging + verbosity logic (currently introduces empty blocks).
src/praisonai-agents/praisonaiagents/agent/vision_agent.py Switch vision agent logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/video_agent.py Switch video agent logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/summarization.py Switch summarization logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/router_agent.py Switch router agent logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/realtime_agent.py Switch realtime agent logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/query_rewriter_agent.py Switch query rewriter logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/prompt_expander_agent.py Switch prompt expander logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/ocr_agent.py Switch OCR agent logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/message_queue.py Switch message queue logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/loop_detection.py Switch loop detection logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/image_agent.py Switch image agent logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/heartbeat.py Switch heartbeat logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/handoff.py Switch handoff logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/embedding_agent.py Switch embedding agent logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/deep_research_agent.py Switch deep research agent logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/cost_persistence.py Switch cost persistence logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/context_agent.py Switch context agent logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/code_agent.py Switch code agent logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/autonomy.py Switch autonomy logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/audio_agent.py Switch audio agent logging to get_logger.
src/praisonai-agents/praisonaiagents/agent/agent.py Switch agent logging + attempts to reconfigure external logger levels via get_logger.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +6
import os
import re

target_dir = '/Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents'

changed_files = 0

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script hard-codes a local absolute path ("/Users/praison/..."), and performs in-place refactors across the repo. It looks like a one-off migration helper and is not portable or safe to ship as part of the package. Consider removing it from the repo (or moving it to internal dev tooling with a configurable target_dir / CLI args and clear safeguards).

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +45
attempt = 0
while True:
try:
return func(*args, **kwargs)
except exceptions as e:
if attempt >= retries:
logger.error(
f"Execution failed permanently after {attempt} retries "

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The retry counter is off by one relative to the docstring/typical semantics. With attempt starting at 0 and incremented after computing the delay, retries=3 results in 4 total executions (initial + 3 sleeps) before the permanent failure branch triggers. Either rename the parameter to max_retries (retries after the initial attempt) and update messaging, or change the condition/increment so retries truly caps total attempts as documented.

Copilot uses AI. Check for mistakes.
Comment on lines +89 to +96
attempt = 0
while True:
try:
return await func(*args, **kwargs)
except exceptions as e:
if attempt >= retries:
logger.error(
f"Async execution failed permanently after {attempt} retries "

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same off-by-one retry semantics issue exists in the async decorator: retries=3 yields 4 total attempts. Align the implementation with the documented meaning of retries (or update naming/docs to reflect 'number of retries after the first attempt').

Copilot uses AI. Check for mistakes.
Comment on lines 337 to 342
# Set logger level based on config verbose level
verbose = self.config.get("verbose", 0)
if verbose >= 5:
logger.setLevel(logging.INFO)

else:
logger.setLevel(logging.WARNING)

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if verbose >= 5: ... else: ... block is now empty, which makes the module invalid Python (SyntaxError) and will break imports. If logger-level overrides are intentionally removed in favor of centralized config, delete the conditional entirely; otherwise add the intended statements (or at least pass).

Copilot uses AI. Check for mistakes.
Comment on lines +343 to +347
# Also set third-party loggers to WARNING
logging.getLogger('chromadb').setLevel(logging.WARNING)
logging.getLogger('openai').setLevel(logging.WARNING)
logging.getLogger('httpx').setLevel(logging.WARNING)
logging.getLogger('httpcore').setLevel(logging.WARNING)
get_logger('chromadb').setLevel(logging.WARNING)
get_logger('openai').setLevel(logging.WARNING)
get_logger('httpx').setLevel(logging.WARNING)
get_logger('httpcore').setLevel(logging.WARNING)

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_logger('chromadb'/'openai'/'httpx'/'httpcore') will prefix these names to praisonaiagents.* (per _logging.get_logger), so it will NOT configure the actual third-party loggers and will leave their output unsuppressed. Use logging.getLogger('chromadb') (etc.) for external libraries, or update get_logger to support returning un-prefixed external loggers when explicitly requested.

Copilot uses AI. Check for mistakes.
Comment on lines 62 to 66
self._debug = debug

if debug:
logger.setLevel(logging.DEBUG)


# Register initial tools if provided

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if debug: now has an empty body, which is a SyntaxError and will prevent this module from importing. Either remove the conditional or restore the intended debug log-level configuration (or add pass).

Copilot uses AI. Check for mistakes.
Comment on lines 69 to +73
# Set logger level based on verbose
if verbose >= 5:
logger.setLevel(logging.INFO)

else:
logger.setLevel(logging.WARNING)


Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if verbose >= 5: ... else: ... block is empty now, which is a SyntaxError and will prevent this adapter from importing. Remove the conditional or restore the intended logger.setLevel(...) statements (or add pass).

Copilot uses AI. Check for mistakes.
Comment on lines 238 to 243
# Always suppress litellm's internal debug messages
logging.getLogger("litellm.utils").setLevel(logging.WARNING)
logging.getLogger("litellm.main").setLevel(logging.WARNING)
logging.getLogger("litellm.litellm_logging").setLevel(logging.WARNING)
logging.getLogger("litellm.transformation").setLevel(logging.WARNING)
get_logger("litellm.utils").setLevel(logging.WARNING)
get_logger("litellm.main").setLevel(logging.WARNING)
get_logger("litellm.litellm_logging").setLevel(logging.WARNING)
get_logger("litellm.transformation").setLevel(logging.WARNING)

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_logger("litellm.*") will prefix these to praisonaiagents.litellm.*, so these setLevel(...) calls won't affect the actual LiteLLM loggers. For third-party logger configuration, use logging.getLogger("litellm.utils") (etc.) or provide a way for get_logger to bypass prefixing for external names.

Copilot uses AI. Check for mistakes.
Comment on lines 251 to +253
# Keep asyncio at WARNING unless explicitly in high debug mode
logging.getLogger("asyncio").setLevel(logging.WARNING)
logging.getLogger("selector_events").setLevel(logging.WARNING)
get_logger("asyncio").setLevel(logging.WARNING)
get_logger("selector_events").setLevel(logging.WARNING)

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue for these external loggers: get_logger("asyncio") / get_logger("selector_events") will not target the real stdlib loggers and therefore won't suppress them as intended.

Copilot uses AI. Check for mistakes.
Comment on lines 257 to +267
# Configure logging to suppress unwanted outputs
logging.getLogger("litellm").setLevel(logging.WARNING)
get_logger("litellm").setLevel(logging.WARNING)

# Allow httpx logging when LOGLEVEL=debug, otherwise suppress it
loglevel = os.environ.get('LOGLEVEL', 'INFO').upper()
if loglevel == 'DEBUG':
logging.getLogger("httpx").setLevel(logging.INFO)
logging.getLogger("httpcore").setLevel(logging.INFO)
get_logger("httpx").setLevel(logging.INFO)
get_logger("httpcore").setLevel(logging.INFO)
else:
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING)
get_logger("httpx").setLevel(logging.WARNING)
get_logger("httpcore").setLevel(logging.WARNING)

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_logger("litellm"/"httpx"/"httpcore") prefixes names to praisonaiagents.*, so these setLevel(...) calls won't affect the real third-party loggers and may reintroduce noisy output. Use logging.getLogger("httpx") / logging.getLogger("litellm") for external libraries, or add an explicit way to bypass prefixing in get_logger for external logger names.

Copilot uses AI. Check for mistakes.
Updated logger level settings to use consistent DEBUG and WARNING levels
based on the verbosity of the application. This enhances logging clarity
and ensures that third-party loggers are set to WARNING by default.
Adjusted imports to maintain consistent logging behavior across various
modules for better maintainability. Additionally, bumped version in
pyproject.toml to 1.5.89.
- Remove unittest.yml (517-line debug file, always failed exit 5)
- Fix test-core.yml: deprecated codecov 'file:' -> 'files:' input
- Fix test-optimized.yml: move secrets from inline shell expressions
  to env: blocks to resolve linter context access warnings
- Fix test_serve_integration.py: replace 6x hardcoded /Users/praison paths
  with dynamic pathlib resolution (portable on any CI runner)
- Fix test_tracker_complex_tasks.py: DEFAULT_TOOLS -> AUTONOMY_DEFAULT_TOOLS
  (symbol was renamed in tracker.py, causing ImportError in CI)

Resolves GitHub Actions lint IDs:
7c7e1668 1d881864 aa30b182 a28bb9f7 ca2c8cc1 132d4548
a2735061 d3729ccb 333ae3f5 f3aca47c 7353e2c3 6d3216de
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inconsistent logging: 53+ logger instances with no unified configuration Retry logic duplicated across 40+ files instead of using centralized utility

2 participants