PraisonAI 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- praisonai/__init__.py +54 -0
- praisonai/__main__.py +15 -0
- praisonai/acp/__init__.py +54 -0
- praisonai/acp/config.py +159 -0
- praisonai/acp/server.py +587 -0
- praisonai/acp/session.py +219 -0
- praisonai/adapters/__init__.py +50 -0
- praisonai/adapters/readers.py +395 -0
- praisonai/adapters/rerankers.py +315 -0
- praisonai/adapters/retrievers.py +394 -0
- praisonai/adapters/vector_stores.py +409 -0
- praisonai/agent_scheduler.py +337 -0
- praisonai/agents_generator.py +903 -0
- praisonai/api/call.py +292 -0
- praisonai/auto.py +1197 -0
- praisonai/capabilities/__init__.py +275 -0
- praisonai/capabilities/a2a.py +140 -0
- praisonai/capabilities/assistants.py +283 -0
- praisonai/capabilities/audio.py +320 -0
- praisonai/capabilities/batches.py +469 -0
- praisonai/capabilities/completions.py +336 -0
- praisonai/capabilities/container_files.py +155 -0
- praisonai/capabilities/containers.py +93 -0
- praisonai/capabilities/embeddings.py +158 -0
- praisonai/capabilities/files.py +467 -0
- praisonai/capabilities/fine_tuning.py +293 -0
- praisonai/capabilities/guardrails.py +182 -0
- praisonai/capabilities/images.py +330 -0
- praisonai/capabilities/mcp.py +190 -0
- praisonai/capabilities/messages.py +270 -0
- praisonai/capabilities/moderations.py +154 -0
- praisonai/capabilities/ocr.py +217 -0
- praisonai/capabilities/passthrough.py +204 -0
- praisonai/capabilities/rag.py +207 -0
- praisonai/capabilities/realtime.py +160 -0
- praisonai/capabilities/rerank.py +165 -0
- praisonai/capabilities/responses.py +266 -0
- praisonai/capabilities/search.py +109 -0
- praisonai/capabilities/skills.py +133 -0
- praisonai/capabilities/vector_store_files.py +334 -0
- praisonai/capabilities/vector_stores.py +304 -0
- praisonai/capabilities/videos.py +141 -0
- praisonai/chainlit_ui.py +304 -0
- praisonai/chat/__init__.py +106 -0
- praisonai/chat/app.py +125 -0
- praisonai/cli/__init__.py +26 -0
- praisonai/cli/app.py +213 -0
- praisonai/cli/commands/__init__.py +75 -0
- praisonai/cli/commands/acp.py +70 -0
- praisonai/cli/commands/completion.py +333 -0
- praisonai/cli/commands/config.py +166 -0
- praisonai/cli/commands/debug.py +142 -0
- praisonai/cli/commands/diag.py +55 -0
- praisonai/cli/commands/doctor.py +166 -0
- praisonai/cli/commands/environment.py +179 -0
- praisonai/cli/commands/lsp.py +112 -0
- praisonai/cli/commands/mcp.py +210 -0
- praisonai/cli/commands/profile.py +457 -0
- praisonai/cli/commands/run.py +228 -0
- praisonai/cli/commands/schedule.py +150 -0
- praisonai/cli/commands/serve.py +97 -0
- praisonai/cli/commands/session.py +212 -0
- praisonai/cli/commands/traces.py +145 -0
- praisonai/cli/commands/version.py +101 -0
- praisonai/cli/configuration/__init__.py +18 -0
- praisonai/cli/configuration/loader.py +353 -0
- praisonai/cli/configuration/paths.py +114 -0
- praisonai/cli/configuration/schema.py +164 -0
- praisonai/cli/features/__init__.py +268 -0
- praisonai/cli/features/acp.py +236 -0
- praisonai/cli/features/action_orchestrator.py +546 -0
- praisonai/cli/features/agent_scheduler.py +773 -0
- praisonai/cli/features/agent_tools.py +474 -0
- praisonai/cli/features/agents.py +375 -0
- praisonai/cli/features/at_mentions.py +471 -0
- praisonai/cli/features/auto_memory.py +182 -0
- praisonai/cli/features/autonomy_mode.py +490 -0
- praisonai/cli/features/background.py +356 -0
- praisonai/cli/features/base.py +168 -0
- praisonai/cli/features/capabilities.py +1326 -0
- praisonai/cli/features/checkpoints.py +338 -0
- praisonai/cli/features/code_intelligence.py +652 -0
- praisonai/cli/features/compaction.py +294 -0
- praisonai/cli/features/compare.py +534 -0
- praisonai/cli/features/cost_tracker.py +514 -0
- praisonai/cli/features/debug.py +810 -0
- praisonai/cli/features/deploy.py +517 -0
- praisonai/cli/features/diag.py +289 -0
- praisonai/cli/features/doctor/__init__.py +63 -0
- praisonai/cli/features/doctor/checks/__init__.py +24 -0
- praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
- praisonai/cli/features/doctor/checks/config_checks.py +366 -0
- praisonai/cli/features/doctor/checks/db_checks.py +366 -0
- praisonai/cli/features/doctor/checks/env_checks.py +543 -0
- praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
- praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
- praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
- praisonai/cli/features/doctor/checks/network_checks.py +251 -0
- praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
- praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
- praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
- praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
- praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
- praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
- praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
- praisonai/cli/features/doctor/engine.py +266 -0
- praisonai/cli/features/doctor/formatters.py +310 -0
- praisonai/cli/features/doctor/handler.py +397 -0
- praisonai/cli/features/doctor/models.py +264 -0
- praisonai/cli/features/doctor/registry.py +239 -0
- praisonai/cli/features/endpoints.py +1019 -0
- praisonai/cli/features/eval.py +560 -0
- praisonai/cli/features/external_agents.py +231 -0
- praisonai/cli/features/fast_context.py +410 -0
- praisonai/cli/features/flow_display.py +566 -0
- praisonai/cli/features/git_integration.py +651 -0
- praisonai/cli/features/guardrail.py +171 -0
- praisonai/cli/features/handoff.py +185 -0
- praisonai/cli/features/hooks.py +583 -0
- praisonai/cli/features/image.py +384 -0
- praisonai/cli/features/interactive_runtime.py +585 -0
- praisonai/cli/features/interactive_tools.py +380 -0
- praisonai/cli/features/interactive_tui.py +603 -0
- praisonai/cli/features/jobs.py +632 -0
- praisonai/cli/features/knowledge.py +531 -0
- praisonai/cli/features/lite.py +244 -0
- praisonai/cli/features/lsp_cli.py +225 -0
- praisonai/cli/features/mcp.py +169 -0
- praisonai/cli/features/message_queue.py +587 -0
- praisonai/cli/features/metrics.py +211 -0
- praisonai/cli/features/n8n.py +673 -0
- praisonai/cli/features/observability.py +293 -0
- praisonai/cli/features/ollama.py +361 -0
- praisonai/cli/features/output_style.py +273 -0
- praisonai/cli/features/package.py +631 -0
- praisonai/cli/features/performance.py +308 -0
- praisonai/cli/features/persistence.py +636 -0
- praisonai/cli/features/profile.py +226 -0
- praisonai/cli/features/profiler/__init__.py +81 -0
- praisonai/cli/features/profiler/core.py +558 -0
- praisonai/cli/features/profiler/optimizations.py +652 -0
- praisonai/cli/features/profiler/suite.py +386 -0
- praisonai/cli/features/profiling.py +350 -0
- praisonai/cli/features/queue/__init__.py +73 -0
- praisonai/cli/features/queue/manager.py +395 -0
- praisonai/cli/features/queue/models.py +286 -0
- praisonai/cli/features/queue/persistence.py +564 -0
- praisonai/cli/features/queue/scheduler.py +484 -0
- praisonai/cli/features/queue/worker.py +372 -0
- praisonai/cli/features/recipe.py +1723 -0
- praisonai/cli/features/recipes.py +449 -0
- praisonai/cli/features/registry.py +229 -0
- praisonai/cli/features/repo_map.py +860 -0
- praisonai/cli/features/router.py +466 -0
- praisonai/cli/features/sandbox_executor.py +515 -0
- praisonai/cli/features/serve.py +829 -0
- praisonai/cli/features/session.py +222 -0
- praisonai/cli/features/skills.py +856 -0
- praisonai/cli/features/slash_commands.py +650 -0
- praisonai/cli/features/telemetry.py +179 -0
- praisonai/cli/features/templates.py +1384 -0
- praisonai/cli/features/thinking.py +305 -0
- praisonai/cli/features/todo.py +334 -0
- praisonai/cli/features/tools.py +680 -0
- praisonai/cli/features/tui/__init__.py +83 -0
- praisonai/cli/features/tui/app.py +580 -0
- praisonai/cli/features/tui/cli.py +566 -0
- praisonai/cli/features/tui/debug.py +511 -0
- praisonai/cli/features/tui/events.py +99 -0
- praisonai/cli/features/tui/mock_provider.py +328 -0
- praisonai/cli/features/tui/orchestrator.py +652 -0
- praisonai/cli/features/tui/screens/__init__.py +50 -0
- praisonai/cli/features/tui/screens/main.py +245 -0
- praisonai/cli/features/tui/screens/queue.py +174 -0
- praisonai/cli/features/tui/screens/session.py +124 -0
- praisonai/cli/features/tui/screens/settings.py +148 -0
- praisonai/cli/features/tui/widgets/__init__.py +56 -0
- praisonai/cli/features/tui/widgets/chat.py +261 -0
- praisonai/cli/features/tui/widgets/composer.py +224 -0
- praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
- praisonai/cli/features/tui/widgets/status.py +167 -0
- praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
- praisonai/cli/features/workflow.py +720 -0
- praisonai/cli/legacy.py +236 -0
- praisonai/cli/main.py +5559 -0
- praisonai/cli/schedule_cli.py +54 -0
- praisonai/cli/state/__init__.py +31 -0
- praisonai/cli/state/identifiers.py +161 -0
- praisonai/cli/state/sessions.py +313 -0
- praisonai/code/__init__.py +93 -0
- praisonai/code/agent_tools.py +344 -0
- praisonai/code/diff/__init__.py +21 -0
- praisonai/code/diff/diff_strategy.py +432 -0
- praisonai/code/tools/__init__.py +27 -0
- praisonai/code/tools/apply_diff.py +221 -0
- praisonai/code/tools/execute_command.py +275 -0
- praisonai/code/tools/list_files.py +274 -0
- praisonai/code/tools/read_file.py +206 -0
- praisonai/code/tools/search_replace.py +248 -0
- praisonai/code/tools/write_file.py +217 -0
- praisonai/code/utils/__init__.py +46 -0
- praisonai/code/utils/file_utils.py +307 -0
- praisonai/code/utils/ignore_utils.py +308 -0
- praisonai/code/utils/text_utils.py +276 -0
- praisonai/db/__init__.py +64 -0
- praisonai/db/adapter.py +531 -0
- praisonai/deploy/__init__.py +62 -0
- praisonai/deploy/api.py +231 -0
- praisonai/deploy/docker.py +454 -0
- praisonai/deploy/doctor.py +367 -0
- praisonai/deploy/main.py +327 -0
- praisonai/deploy/models.py +179 -0
- praisonai/deploy/providers/__init__.py +33 -0
- praisonai/deploy/providers/aws.py +331 -0
- praisonai/deploy/providers/azure.py +358 -0
- praisonai/deploy/providers/base.py +101 -0
- praisonai/deploy/providers/gcp.py +314 -0
- praisonai/deploy/schema.py +208 -0
- praisonai/deploy.py +185 -0
- praisonai/endpoints/__init__.py +53 -0
- praisonai/endpoints/a2u_server.py +410 -0
- praisonai/endpoints/discovery.py +165 -0
- praisonai/endpoints/providers/__init__.py +28 -0
- praisonai/endpoints/providers/a2a.py +253 -0
- praisonai/endpoints/providers/a2u.py +208 -0
- praisonai/endpoints/providers/agents_api.py +171 -0
- praisonai/endpoints/providers/base.py +231 -0
- praisonai/endpoints/providers/mcp.py +263 -0
- praisonai/endpoints/providers/recipe.py +206 -0
- praisonai/endpoints/providers/tools_mcp.py +150 -0
- praisonai/endpoints/registry.py +131 -0
- praisonai/endpoints/server.py +161 -0
- praisonai/inbuilt_tools/__init__.py +24 -0
- praisonai/inbuilt_tools/autogen_tools.py +117 -0
- praisonai/inc/__init__.py +2 -0
- praisonai/inc/config.py +96 -0
- praisonai/inc/models.py +155 -0
- praisonai/integrations/__init__.py +56 -0
- praisonai/integrations/base.py +303 -0
- praisonai/integrations/claude_code.py +270 -0
- praisonai/integrations/codex_cli.py +255 -0
- praisonai/integrations/cursor_cli.py +195 -0
- praisonai/integrations/gemini_cli.py +222 -0
- praisonai/jobs/__init__.py +67 -0
- praisonai/jobs/executor.py +425 -0
- praisonai/jobs/models.py +230 -0
- praisonai/jobs/router.py +314 -0
- praisonai/jobs/server.py +186 -0
- praisonai/jobs/store.py +203 -0
- praisonai/llm/__init__.py +66 -0
- praisonai/llm/registry.py +382 -0
- praisonai/mcp_server/__init__.py +152 -0
- praisonai/mcp_server/adapters/__init__.py +74 -0
- praisonai/mcp_server/adapters/agents.py +128 -0
- praisonai/mcp_server/adapters/capabilities.py +168 -0
- praisonai/mcp_server/adapters/cli_tools.py +568 -0
- praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
- praisonai/mcp_server/adapters/knowledge.py +93 -0
- praisonai/mcp_server/adapters/memory.py +104 -0
- praisonai/mcp_server/adapters/prompts.py +306 -0
- praisonai/mcp_server/adapters/resources.py +124 -0
- praisonai/mcp_server/adapters/tools_bridge.py +280 -0
- praisonai/mcp_server/auth/__init__.py +48 -0
- praisonai/mcp_server/auth/api_key.py +291 -0
- praisonai/mcp_server/auth/oauth.py +460 -0
- praisonai/mcp_server/auth/oidc.py +289 -0
- praisonai/mcp_server/auth/scopes.py +260 -0
- praisonai/mcp_server/cli.py +852 -0
- praisonai/mcp_server/elicitation.py +445 -0
- praisonai/mcp_server/icons.py +302 -0
- praisonai/mcp_server/recipe_adapter.py +573 -0
- praisonai/mcp_server/recipe_cli.py +824 -0
- praisonai/mcp_server/registry.py +703 -0
- praisonai/mcp_server/sampling.py +422 -0
- praisonai/mcp_server/server.py +490 -0
- praisonai/mcp_server/tasks.py +443 -0
- praisonai/mcp_server/transports/__init__.py +18 -0
- praisonai/mcp_server/transports/http_stream.py +376 -0
- praisonai/mcp_server/transports/stdio.py +132 -0
- praisonai/persistence/__init__.py +84 -0
- praisonai/persistence/config.py +238 -0
- praisonai/persistence/conversation/__init__.py +25 -0
- praisonai/persistence/conversation/async_mysql.py +427 -0
- praisonai/persistence/conversation/async_postgres.py +410 -0
- praisonai/persistence/conversation/async_sqlite.py +371 -0
- praisonai/persistence/conversation/base.py +151 -0
- praisonai/persistence/conversation/json_store.py +250 -0
- praisonai/persistence/conversation/mysql.py +387 -0
- praisonai/persistence/conversation/postgres.py +401 -0
- praisonai/persistence/conversation/singlestore.py +240 -0
- praisonai/persistence/conversation/sqlite.py +341 -0
- praisonai/persistence/conversation/supabase.py +203 -0
- praisonai/persistence/conversation/surrealdb.py +287 -0
- praisonai/persistence/factory.py +301 -0
- praisonai/persistence/hooks/__init__.py +18 -0
- praisonai/persistence/hooks/agent_hooks.py +297 -0
- praisonai/persistence/knowledge/__init__.py +26 -0
- praisonai/persistence/knowledge/base.py +144 -0
- praisonai/persistence/knowledge/cassandra.py +232 -0
- praisonai/persistence/knowledge/chroma.py +295 -0
- praisonai/persistence/knowledge/clickhouse.py +242 -0
- praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
- praisonai/persistence/knowledge/couchbase.py +286 -0
- praisonai/persistence/knowledge/lancedb.py +216 -0
- praisonai/persistence/knowledge/langchain_adapter.py +291 -0
- praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
- praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
- praisonai/persistence/knowledge/milvus.py +277 -0
- praisonai/persistence/knowledge/mongodb_vector.py +306 -0
- praisonai/persistence/knowledge/pgvector.py +335 -0
- praisonai/persistence/knowledge/pinecone.py +253 -0
- praisonai/persistence/knowledge/qdrant.py +301 -0
- praisonai/persistence/knowledge/redis_vector.py +291 -0
- praisonai/persistence/knowledge/singlestore_vector.py +299 -0
- praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
- praisonai/persistence/knowledge/upstash_vector.py +266 -0
- praisonai/persistence/knowledge/weaviate.py +223 -0
- praisonai/persistence/migrations/__init__.py +10 -0
- praisonai/persistence/migrations/manager.py +251 -0
- praisonai/persistence/orchestrator.py +406 -0
- praisonai/persistence/state/__init__.py +21 -0
- praisonai/persistence/state/async_mongodb.py +200 -0
- praisonai/persistence/state/base.py +107 -0
- praisonai/persistence/state/dynamodb.py +226 -0
- praisonai/persistence/state/firestore.py +175 -0
- praisonai/persistence/state/gcs.py +155 -0
- praisonai/persistence/state/memory.py +245 -0
- praisonai/persistence/state/mongodb.py +158 -0
- praisonai/persistence/state/redis.py +190 -0
- praisonai/persistence/state/upstash.py +144 -0
- praisonai/persistence/tests/__init__.py +3 -0
- praisonai/persistence/tests/test_all_backends.py +633 -0
- praisonai/profiler.py +1214 -0
- praisonai/recipe/__init__.py +134 -0
- praisonai/recipe/bridge.py +278 -0
- praisonai/recipe/core.py +893 -0
- praisonai/recipe/exceptions.py +54 -0
- praisonai/recipe/history.py +402 -0
- praisonai/recipe/models.py +266 -0
- praisonai/recipe/operations.py +440 -0
- praisonai/recipe/policy.py +422 -0
- praisonai/recipe/registry.py +849 -0
- praisonai/recipe/runtime.py +214 -0
- praisonai/recipe/security.py +711 -0
- praisonai/recipe/serve.py +859 -0
- praisonai/recipe/server.py +613 -0
- praisonai/scheduler/__init__.py +45 -0
- praisonai/scheduler/agent_scheduler.py +552 -0
- praisonai/scheduler/base.py +124 -0
- praisonai/scheduler/daemon_manager.py +225 -0
- praisonai/scheduler/state_manager.py +155 -0
- praisonai/scheduler/yaml_loader.py +193 -0
- praisonai/scheduler.py +194 -0
- praisonai/setup/__init__.py +1 -0
- praisonai/setup/build.py +21 -0
- praisonai/setup/post_install.py +23 -0
- praisonai/setup/setup_conda_env.py +25 -0
- praisonai/setup.py +16 -0
- praisonai/templates/__init__.py +116 -0
- praisonai/templates/cache.py +364 -0
- praisonai/templates/dependency_checker.py +358 -0
- praisonai/templates/discovery.py +391 -0
- praisonai/templates/loader.py +564 -0
- praisonai/templates/registry.py +511 -0
- praisonai/templates/resolver.py +206 -0
- praisonai/templates/security.py +327 -0
- praisonai/templates/tool_override.py +498 -0
- praisonai/templates/tools_doctor.py +256 -0
- praisonai/test.py +105 -0
- praisonai/train.py +562 -0
- praisonai/train_vision.py +306 -0
- praisonai/ui/agents.py +824 -0
- praisonai/ui/callbacks.py +57 -0
- praisonai/ui/chainlit_compat.py +246 -0
- praisonai/ui/chat.py +532 -0
- praisonai/ui/code.py +717 -0
- praisonai/ui/colab.py +474 -0
- praisonai/ui/colab_chainlit.py +81 -0
- praisonai/ui/components/aicoder.py +284 -0
- praisonai/ui/context.py +283 -0
- praisonai/ui/database_config.py +56 -0
- praisonai/ui/db.py +294 -0
- praisonai/ui/realtime.py +488 -0
- praisonai/ui/realtimeclient/__init__.py +756 -0
- praisonai/ui/realtimeclient/tools.py +242 -0
- praisonai/ui/sql_alchemy.py +710 -0
- praisonai/upload_vision.py +140 -0
- praisonai/version.py +1 -0
- praisonai-3.0.0.dist-info/METADATA +3493 -0
- praisonai-3.0.0.dist-info/RECORD +393 -0
- praisonai-3.0.0.dist-info/WHEEL +5 -0
- praisonai-3.0.0.dist-info/entry_points.txt +4 -0
- praisonai-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data models for the Doctor CLI module.
|
|
3
|
+
|
|
4
|
+
Defines the core data structures for check results, reports, and configuration.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CheckStatus(Enum):
|
|
14
|
+
"""Status of a doctor check."""
|
|
15
|
+
PASS = "pass"
|
|
16
|
+
WARN = "warn"
|
|
17
|
+
FAIL = "fail"
|
|
18
|
+
SKIP = "skip"
|
|
19
|
+
ERROR = "error"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CheckCategory(Enum):
|
|
23
|
+
"""Category of a doctor check."""
|
|
24
|
+
ENVIRONMENT = "environment"
|
|
25
|
+
CONFIG = "config"
|
|
26
|
+
TOOLS = "tools"
|
|
27
|
+
DATABASE = "database"
|
|
28
|
+
MCP = "mcp"
|
|
29
|
+
OBSERVABILITY = "observability"
|
|
30
|
+
SKILLS = "skills"
|
|
31
|
+
MEMORY = "memory"
|
|
32
|
+
PERMISSIONS = "permissions"
|
|
33
|
+
NETWORK = "network"
|
|
34
|
+
PERFORMANCE = "performance"
|
|
35
|
+
SELFTEST = "selftest"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CheckSeverity(Enum):
|
|
39
|
+
"""Severity level of a check."""
|
|
40
|
+
CRITICAL = "critical"
|
|
41
|
+
HIGH = "high"
|
|
42
|
+
MEDIUM = "medium"
|
|
43
|
+
LOW = "low"
|
|
44
|
+
INFO = "info"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class CheckResult:
|
|
49
|
+
"""Result of a single doctor check."""
|
|
50
|
+
id: str
|
|
51
|
+
title: str
|
|
52
|
+
category: CheckCategory
|
|
53
|
+
status: CheckStatus
|
|
54
|
+
message: str
|
|
55
|
+
details: Optional[str] = None
|
|
56
|
+
remediation: Optional[str] = None
|
|
57
|
+
duration_ms: float = 0.0
|
|
58
|
+
severity: CheckSeverity = CheckSeverity.MEDIUM
|
|
59
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
60
|
+
|
|
61
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
62
|
+
"""Convert to dictionary for JSON serialization."""
|
|
63
|
+
return {
|
|
64
|
+
"id": self.id,
|
|
65
|
+
"title": self.title,
|
|
66
|
+
"category": self.category.value,
|
|
67
|
+
"status": self.status.value,
|
|
68
|
+
"message": self.message,
|
|
69
|
+
"details": self.details,
|
|
70
|
+
"remediation": self.remediation,
|
|
71
|
+
"duration_ms": round(self.duration_ms, 2),
|
|
72
|
+
"severity": self.severity.value,
|
|
73
|
+
"metadata": self.metadata,
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def passed(self) -> bool:
|
|
78
|
+
"""Check if this result is considered passing."""
|
|
79
|
+
return self.status in (CheckStatus.PASS, CheckStatus.SKIP)
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def is_warning(self) -> bool:
|
|
83
|
+
"""Check if this result is a warning."""
|
|
84
|
+
return self.status == CheckStatus.WARN
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def is_failure(self) -> bool:
|
|
88
|
+
"""Check if this result is a failure."""
|
|
89
|
+
return self.status in (CheckStatus.FAIL, CheckStatus.ERROR)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass
|
|
93
|
+
class CheckDefinition:
|
|
94
|
+
"""Definition of a doctor check."""
|
|
95
|
+
id: str
|
|
96
|
+
title: str
|
|
97
|
+
description: str
|
|
98
|
+
category: CheckCategory
|
|
99
|
+
severity: CheckSeverity = CheckSeverity.MEDIUM
|
|
100
|
+
requires_deep: bool = False
|
|
101
|
+
dependencies: List[str] = field(default_factory=list)
|
|
102
|
+
tags: List[str] = field(default_factory=list)
|
|
103
|
+
|
|
104
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
105
|
+
"""Convert to dictionary."""
|
|
106
|
+
return {
|
|
107
|
+
"id": self.id,
|
|
108
|
+
"title": self.title,
|
|
109
|
+
"description": self.description,
|
|
110
|
+
"category": self.category.value,
|
|
111
|
+
"severity": self.severity.value,
|
|
112
|
+
"requires_deep": self.requires_deep,
|
|
113
|
+
"dependencies": self.dependencies,
|
|
114
|
+
"tags": self.tags,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@dataclass
|
|
119
|
+
class EnvironmentSummary:
|
|
120
|
+
"""Summary of the runtime environment."""
|
|
121
|
+
python_version: str = ""
|
|
122
|
+
python_executable: str = ""
|
|
123
|
+
os_name: str = ""
|
|
124
|
+
os_version: str = ""
|
|
125
|
+
architecture: str = ""
|
|
126
|
+
praisonai_version: str = ""
|
|
127
|
+
praisonaiagents_version: str = ""
|
|
128
|
+
working_directory: str = ""
|
|
129
|
+
virtual_env: Optional[str] = None
|
|
130
|
+
|
|
131
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
132
|
+
"""Convert to dictionary."""
|
|
133
|
+
return {
|
|
134
|
+
"python_version": self.python_version,
|
|
135
|
+
"python_executable": self.python_executable,
|
|
136
|
+
"os_name": self.os_name,
|
|
137
|
+
"os_version": self.os_version,
|
|
138
|
+
"architecture": self.architecture,
|
|
139
|
+
"praisonai_version": self.praisonai_version,
|
|
140
|
+
"praisonaiagents_version": self.praisonaiagents_version,
|
|
141
|
+
"working_directory": self.working_directory,
|
|
142
|
+
"virtual_env": self.virtual_env,
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@dataclass
|
|
147
|
+
class ReportSummary:
|
|
148
|
+
"""Summary statistics for a doctor report."""
|
|
149
|
+
total: int = 0
|
|
150
|
+
passed: int = 0
|
|
151
|
+
warnings: int = 0
|
|
152
|
+
failed: int = 0
|
|
153
|
+
skipped: int = 0
|
|
154
|
+
errors: int = 0
|
|
155
|
+
|
|
156
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
157
|
+
"""Convert to dictionary."""
|
|
158
|
+
return {
|
|
159
|
+
"total": self.total,
|
|
160
|
+
"passed": self.passed,
|
|
161
|
+
"warnings": self.warnings,
|
|
162
|
+
"failed": self.failed,
|
|
163
|
+
"skipped": self.skipped,
|
|
164
|
+
"errors": self.errors,
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@dataclass
|
|
169
|
+
class DoctorReport:
|
|
170
|
+
"""Complete doctor report."""
|
|
171
|
+
version: str = "1.0.0"
|
|
172
|
+
timestamp: str = ""
|
|
173
|
+
duration_ms: float = 0.0
|
|
174
|
+
environment: EnvironmentSummary = field(default_factory=EnvironmentSummary)
|
|
175
|
+
results: List[CheckResult] = field(default_factory=list)
|
|
176
|
+
summary: ReportSummary = field(default_factory=ReportSummary)
|
|
177
|
+
exit_code: int = 0
|
|
178
|
+
mode: str = "fast"
|
|
179
|
+
filters: Dict[str, Any] = field(default_factory=dict)
|
|
180
|
+
|
|
181
|
+
def __post_init__(self):
|
|
182
|
+
if not self.timestamp:
|
|
183
|
+
from datetime import datetime, timezone
|
|
184
|
+
self.timestamp = datetime.now(timezone.utc).isoformat()
|
|
185
|
+
|
|
186
|
+
def calculate_summary(self) -> None:
|
|
187
|
+
"""Calculate summary statistics from results."""
|
|
188
|
+
self.summary = ReportSummary(
|
|
189
|
+
total=len(self.results),
|
|
190
|
+
passed=sum(1 for r in self.results if r.status == CheckStatus.PASS),
|
|
191
|
+
warnings=sum(1 for r in self.results if r.status == CheckStatus.WARN),
|
|
192
|
+
failed=sum(1 for r in self.results if r.status == CheckStatus.FAIL),
|
|
193
|
+
skipped=sum(1 for r in self.results if r.status == CheckStatus.SKIP),
|
|
194
|
+
errors=sum(1 for r in self.results if r.status == CheckStatus.ERROR),
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
def calculate_exit_code(self, strict: bool = False) -> int:
|
|
198
|
+
"""
|
|
199
|
+
Calculate exit code based on results.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
strict: If True, treat warnings as failures
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
0: All passed (warnings allowed unless strict)
|
|
206
|
+
1: Failures present
|
|
207
|
+
2: Internal errors
|
|
208
|
+
"""
|
|
209
|
+
if self.summary.errors > 0:
|
|
210
|
+
return 2
|
|
211
|
+
if self.summary.failed > 0:
|
|
212
|
+
return 1
|
|
213
|
+
if strict and self.summary.warnings > 0:
|
|
214
|
+
return 1
|
|
215
|
+
return 0
|
|
216
|
+
|
|
217
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
218
|
+
"""Convert to dictionary for JSON serialization."""
|
|
219
|
+
return {
|
|
220
|
+
"version": self.version,
|
|
221
|
+
"timestamp": self.timestamp,
|
|
222
|
+
"duration_ms": round(self.duration_ms, 2),
|
|
223
|
+
"environment": self.environment.to_dict(),
|
|
224
|
+
"results": [r.to_dict() for r in self.results],
|
|
225
|
+
"summary": self.summary.to_dict(),
|
|
226
|
+
"exit_code": self.exit_code,
|
|
227
|
+
"mode": self.mode,
|
|
228
|
+
"filters": self.filters,
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
@dataclass
|
|
233
|
+
class DoctorConfig:
|
|
234
|
+
"""Configuration for doctor execution."""
|
|
235
|
+
deep: bool = False
|
|
236
|
+
timeout: float = 10.0
|
|
237
|
+
strict: bool = False
|
|
238
|
+
quiet: bool = False
|
|
239
|
+
no_color: bool = False
|
|
240
|
+
format: str = "text"
|
|
241
|
+
output_path: Optional[str] = None
|
|
242
|
+
only: List[str] = field(default_factory=list)
|
|
243
|
+
skip: List[str] = field(default_factory=list)
|
|
244
|
+
|
|
245
|
+
# Subcommand-specific options
|
|
246
|
+
show_keys: bool = False
|
|
247
|
+
require_keys: List[str] = field(default_factory=list)
|
|
248
|
+
config_file: Optional[str] = None
|
|
249
|
+
dsn: Optional[str] = None
|
|
250
|
+
provider: Optional[str] = None
|
|
251
|
+
read_only: bool = True
|
|
252
|
+
mock: bool = True
|
|
253
|
+
live: bool = False
|
|
254
|
+
model: Optional[str] = None
|
|
255
|
+
budget_ms: Optional[int] = None
|
|
256
|
+
top_n: int = 10
|
|
257
|
+
fail_fast: bool = False
|
|
258
|
+
list_tools: bool = False
|
|
259
|
+
all_checks: bool = False
|
|
260
|
+
missing_only: bool = False
|
|
261
|
+
name: Optional[str] = None
|
|
262
|
+
category: Optional[str] = None
|
|
263
|
+
path: Optional[str] = None
|
|
264
|
+
save_report: bool = False
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Check registry for the Doctor CLI module.
|
|
3
|
+
|
|
4
|
+
Manages registration and discovery of doctor checks.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Callable, Dict, List, Optional, Set
|
|
8
|
+
from .models import CheckDefinition, CheckCategory, CheckSeverity, CheckResult
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CheckRegistry:
|
|
12
|
+
"""
|
|
13
|
+
Registry for doctor checks.
|
|
14
|
+
|
|
15
|
+
Manages check definitions and their implementations.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
_instance: Optional["CheckRegistry"] = None
|
|
19
|
+
|
|
20
|
+
def __new__(cls) -> "CheckRegistry":
|
|
21
|
+
"""Singleton pattern for global registry."""
|
|
22
|
+
if cls._instance is None:
|
|
23
|
+
cls._instance = super().__new__(cls)
|
|
24
|
+
cls._instance._checks: Dict[str, CheckDefinition] = {}
|
|
25
|
+
cls._instance._implementations: Dict[str, Callable] = {}
|
|
26
|
+
cls._instance._initialized = False
|
|
27
|
+
return cls._instance
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def get_instance(cls) -> "CheckRegistry":
|
|
31
|
+
"""Get the singleton instance."""
|
|
32
|
+
return cls()
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def reset(cls) -> None:
|
|
36
|
+
"""Reset the registry (for testing)."""
|
|
37
|
+
cls._instance = None
|
|
38
|
+
|
|
39
|
+
def register(
|
|
40
|
+
self,
|
|
41
|
+
id: str,
|
|
42
|
+
title: str,
|
|
43
|
+
description: str,
|
|
44
|
+
category: CheckCategory,
|
|
45
|
+
implementation: Callable,
|
|
46
|
+
severity: CheckSeverity = CheckSeverity.MEDIUM,
|
|
47
|
+
requires_deep: bool = False,
|
|
48
|
+
dependencies: Optional[List[str]] = None,
|
|
49
|
+
tags: Optional[List[str]] = None,
|
|
50
|
+
) -> None:
|
|
51
|
+
"""
|
|
52
|
+
Register a doctor check.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
id: Unique identifier (snake_case)
|
|
56
|
+
title: Human-readable title
|
|
57
|
+
description: Short description of what the check does
|
|
58
|
+
category: Check category
|
|
59
|
+
implementation: Callable that performs the check
|
|
60
|
+
severity: Severity level
|
|
61
|
+
requires_deep: Whether this check requires --deep mode
|
|
62
|
+
dependencies: List of check IDs this check depends on
|
|
63
|
+
tags: Optional tags for filtering
|
|
64
|
+
"""
|
|
65
|
+
definition = CheckDefinition(
|
|
66
|
+
id=id,
|
|
67
|
+
title=title,
|
|
68
|
+
description=description,
|
|
69
|
+
category=category,
|
|
70
|
+
severity=severity,
|
|
71
|
+
requires_deep=requires_deep,
|
|
72
|
+
dependencies=dependencies or [],
|
|
73
|
+
tags=tags or [],
|
|
74
|
+
)
|
|
75
|
+
self._checks[id] = definition
|
|
76
|
+
self._implementations[id] = implementation
|
|
77
|
+
|
|
78
|
+
def get_check(self, id: str) -> Optional[CheckDefinition]:
|
|
79
|
+
"""Get a check definition by ID."""
|
|
80
|
+
return self._checks.get(id)
|
|
81
|
+
|
|
82
|
+
def get_implementation(self, id: str) -> Optional[Callable]:
|
|
83
|
+
"""Get a check implementation by ID."""
|
|
84
|
+
return self._implementations.get(id)
|
|
85
|
+
|
|
86
|
+
def get_all_checks(self) -> List[CheckDefinition]:
|
|
87
|
+
"""Get all registered checks."""
|
|
88
|
+
return list(self._checks.values())
|
|
89
|
+
|
|
90
|
+
def get_check_ids(self) -> List[str]:
|
|
91
|
+
"""Get all registered check IDs."""
|
|
92
|
+
return list(self._checks.keys())
|
|
93
|
+
|
|
94
|
+
def get_checks_by_category(self, category: CheckCategory) -> List[CheckDefinition]:
|
|
95
|
+
"""Get all checks in a category."""
|
|
96
|
+
return [c for c in self._checks.values() if c.category == category]
|
|
97
|
+
|
|
98
|
+
def get_checks_by_tag(self, tag: str) -> List[CheckDefinition]:
|
|
99
|
+
"""Get all checks with a specific tag."""
|
|
100
|
+
return [c for c in self._checks.values() if tag in c.tags]
|
|
101
|
+
|
|
102
|
+
def filter_checks(
|
|
103
|
+
self,
|
|
104
|
+
only: Optional[List[str]] = None,
|
|
105
|
+
skip: Optional[List[str]] = None,
|
|
106
|
+
categories: Optional[List[CheckCategory]] = None,
|
|
107
|
+
deep_mode: bool = False,
|
|
108
|
+
) -> List[CheckDefinition]:
|
|
109
|
+
"""
|
|
110
|
+
Filter checks based on criteria.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
only: Only include these check IDs
|
|
114
|
+
skip: Skip these check IDs
|
|
115
|
+
categories: Only include checks in these categories
|
|
116
|
+
deep_mode: Include checks that require deep mode
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Filtered list of check definitions
|
|
120
|
+
"""
|
|
121
|
+
checks = list(self._checks.values())
|
|
122
|
+
|
|
123
|
+
# Filter by only
|
|
124
|
+
if only:
|
|
125
|
+
only_set = set(only)
|
|
126
|
+
checks = [c for c in checks if c.id in only_set]
|
|
127
|
+
|
|
128
|
+
# Filter by skip
|
|
129
|
+
if skip:
|
|
130
|
+
skip_set = set(skip)
|
|
131
|
+
checks = [c for c in checks if c.id not in skip_set]
|
|
132
|
+
|
|
133
|
+
# Filter by categories
|
|
134
|
+
if categories:
|
|
135
|
+
checks = [c for c in checks if c.category in categories]
|
|
136
|
+
|
|
137
|
+
# Filter by deep mode
|
|
138
|
+
if not deep_mode:
|
|
139
|
+
checks = [c for c in checks if not c.requires_deep]
|
|
140
|
+
|
|
141
|
+
return checks
|
|
142
|
+
|
|
143
|
+
def resolve_dependencies(self, check_ids: List[str]) -> List[str]:
|
|
144
|
+
"""
|
|
145
|
+
Resolve check dependencies and return ordered list.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
check_ids: List of check IDs to resolve
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Ordered list of check IDs with dependencies first
|
|
152
|
+
"""
|
|
153
|
+
resolved: List[str] = []
|
|
154
|
+
seen: Set[str] = set()
|
|
155
|
+
|
|
156
|
+
def resolve(id: str) -> None:
|
|
157
|
+
if id in seen:
|
|
158
|
+
return
|
|
159
|
+
seen.add(id)
|
|
160
|
+
|
|
161
|
+
check = self._checks.get(id)
|
|
162
|
+
if check:
|
|
163
|
+
for dep in check.dependencies:
|
|
164
|
+
resolve(dep)
|
|
165
|
+
resolved.append(id)
|
|
166
|
+
|
|
167
|
+
for id in check_ids:
|
|
168
|
+
resolve(id)
|
|
169
|
+
|
|
170
|
+
return resolved
|
|
171
|
+
|
|
172
|
+
def list_checks_text(self) -> str:
|
|
173
|
+
"""Generate text listing of all checks."""
|
|
174
|
+
lines = ["Available Doctor Checks:", ""]
|
|
175
|
+
|
|
176
|
+
# Group by category
|
|
177
|
+
by_category: Dict[CheckCategory, List[CheckDefinition]] = {}
|
|
178
|
+
for check in self._checks.values():
|
|
179
|
+
if check.category not in by_category:
|
|
180
|
+
by_category[check.category] = []
|
|
181
|
+
by_category[check.category].append(check)
|
|
182
|
+
|
|
183
|
+
for category in CheckCategory:
|
|
184
|
+
if category in by_category:
|
|
185
|
+
lines.append(f" {category.value.upper()}:")
|
|
186
|
+
for check in sorted(by_category[category], key=lambda c: c.id):
|
|
187
|
+
deep_marker = " [deep]" if check.requires_deep else ""
|
|
188
|
+
lines.append(f" {check.id:<30} {check.description}{deep_marker}")
|
|
189
|
+
lines.append("")
|
|
190
|
+
|
|
191
|
+
return "\n".join(lines)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
# Global registry instance
|
|
195
|
+
_registry = CheckRegistry()
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def register_check(
|
|
199
|
+
id: str,
|
|
200
|
+
title: str,
|
|
201
|
+
description: str,
|
|
202
|
+
category: CheckCategory,
|
|
203
|
+
severity: CheckSeverity = CheckSeverity.MEDIUM,
|
|
204
|
+
requires_deep: bool = False,
|
|
205
|
+
dependencies: Optional[List[str]] = None,
|
|
206
|
+
tags: Optional[List[str]] = None,
|
|
207
|
+
):
|
|
208
|
+
"""
|
|
209
|
+
Decorator to register a doctor check.
|
|
210
|
+
|
|
211
|
+
Usage:
|
|
212
|
+
@register_check(
|
|
213
|
+
id="python_version",
|
|
214
|
+
title="Python Version",
|
|
215
|
+
description="Check Python version is 3.9+",
|
|
216
|
+
category=CheckCategory.ENVIRONMENT,
|
|
217
|
+
)
|
|
218
|
+
def check_python_version(config: DoctorConfig) -> CheckResult:
|
|
219
|
+
...
|
|
220
|
+
"""
|
|
221
|
+
def decorator(func: Callable) -> Callable:
|
|
222
|
+
_registry.register(
|
|
223
|
+
id=id,
|
|
224
|
+
title=title,
|
|
225
|
+
description=description,
|
|
226
|
+
category=category,
|
|
227
|
+
implementation=func,
|
|
228
|
+
severity=severity,
|
|
229
|
+
requires_deep=requires_deep,
|
|
230
|
+
dependencies=dependencies,
|
|
231
|
+
tags=tags,
|
|
232
|
+
)
|
|
233
|
+
return func
|
|
234
|
+
return decorator
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def get_registry() -> CheckRegistry:
|
|
238
|
+
"""Get the global check registry."""
|
|
239
|
+
return _registry
|