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,259 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Permissions checks for the Doctor CLI module.
|
|
3
|
+
|
|
4
|
+
Validates filesystem permissions for PraisonAI directories.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import tempfile
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from ..models import (
|
|
12
|
+
CheckCategory,
|
|
13
|
+
CheckResult,
|
|
14
|
+
CheckStatus,
|
|
15
|
+
CheckSeverity,
|
|
16
|
+
DoctorConfig,
|
|
17
|
+
)
|
|
18
|
+
from ..registry import register_check
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _check_dir_writable(path: Path) -> tuple:
|
|
22
|
+
"""Check if a directory is writable."""
|
|
23
|
+
try:
|
|
24
|
+
if not path.exists():
|
|
25
|
+
return False, "does not exist"
|
|
26
|
+
|
|
27
|
+
if not path.is_dir():
|
|
28
|
+
return False, "not a directory"
|
|
29
|
+
|
|
30
|
+
# Try to create a temp file
|
|
31
|
+
test_file = path / ".praison_write_test"
|
|
32
|
+
try:
|
|
33
|
+
test_file.write_text("test")
|
|
34
|
+
test_file.unlink()
|
|
35
|
+
return True, "writable"
|
|
36
|
+
except PermissionError:
|
|
37
|
+
return False, "permission denied"
|
|
38
|
+
except Exception as e:
|
|
39
|
+
return False, str(e)
|
|
40
|
+
except Exception as e:
|
|
41
|
+
return False, str(e)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@register_check(
|
|
45
|
+
id="permissions_home_praison",
|
|
46
|
+
title="~/.praison Directory",
|
|
47
|
+
description="Check ~/.praison directory permissions",
|
|
48
|
+
category=CheckCategory.PERMISSIONS,
|
|
49
|
+
severity=CheckSeverity.MEDIUM,
|
|
50
|
+
)
|
|
51
|
+
def check_permissions_home_praison(config: DoctorConfig) -> CheckResult:
|
|
52
|
+
"""Check ~/.praison directory permissions."""
|
|
53
|
+
praison_dir = Path.home() / ".praison"
|
|
54
|
+
|
|
55
|
+
if not praison_dir.exists():
|
|
56
|
+
# Try to create it
|
|
57
|
+
try:
|
|
58
|
+
praison_dir.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
return CheckResult(
|
|
60
|
+
id="permissions_home_praison",
|
|
61
|
+
title="~/.praison Directory",
|
|
62
|
+
category=CheckCategory.PERMISSIONS,
|
|
63
|
+
status=CheckStatus.PASS,
|
|
64
|
+
message="~/.praison created successfully",
|
|
65
|
+
metadata={"path": str(praison_dir)},
|
|
66
|
+
)
|
|
67
|
+
except PermissionError:
|
|
68
|
+
return CheckResult(
|
|
69
|
+
id="permissions_home_praison",
|
|
70
|
+
title="~/.praison Directory",
|
|
71
|
+
category=CheckCategory.PERMISSIONS,
|
|
72
|
+
status=CheckStatus.FAIL,
|
|
73
|
+
message="Cannot create ~/.praison directory",
|
|
74
|
+
remediation="Check home directory permissions",
|
|
75
|
+
severity=CheckSeverity.HIGH,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
writable, reason = _check_dir_writable(praison_dir)
|
|
79
|
+
|
|
80
|
+
if writable:
|
|
81
|
+
return CheckResult(
|
|
82
|
+
id="permissions_home_praison",
|
|
83
|
+
title="~/.praison Directory",
|
|
84
|
+
category=CheckCategory.PERMISSIONS,
|
|
85
|
+
status=CheckStatus.PASS,
|
|
86
|
+
message=f"~/.praison is writable",
|
|
87
|
+
metadata={"path": str(praison_dir)},
|
|
88
|
+
)
|
|
89
|
+
else:
|
|
90
|
+
return CheckResult(
|
|
91
|
+
id="permissions_home_praison",
|
|
92
|
+
title="~/.praison Directory",
|
|
93
|
+
category=CheckCategory.PERMISSIONS,
|
|
94
|
+
status=CheckStatus.FAIL,
|
|
95
|
+
message=f"~/.praison is not writable: {reason}",
|
|
96
|
+
remediation="Fix permissions: chmod 755 ~/.praison",
|
|
97
|
+
severity=CheckSeverity.HIGH,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@register_check(
|
|
102
|
+
id="permissions_project_praison",
|
|
103
|
+
title=".praison Directory (Project)",
|
|
104
|
+
description="Check project .praison directory permissions",
|
|
105
|
+
category=CheckCategory.PERMISSIONS,
|
|
106
|
+
severity=CheckSeverity.LOW,
|
|
107
|
+
)
|
|
108
|
+
def check_permissions_project_praison(config: DoctorConfig) -> CheckResult:
|
|
109
|
+
"""Check project .praison directory permissions."""
|
|
110
|
+
praison_dir = Path.cwd() / ".praison"
|
|
111
|
+
|
|
112
|
+
if not praison_dir.exists():
|
|
113
|
+
return CheckResult(
|
|
114
|
+
id="permissions_project_praison",
|
|
115
|
+
title=".praison Directory (Project)",
|
|
116
|
+
category=CheckCategory.PERMISSIONS,
|
|
117
|
+
status=CheckStatus.SKIP,
|
|
118
|
+
message="No .praison directory in current project",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
writable, reason = _check_dir_writable(praison_dir)
|
|
122
|
+
|
|
123
|
+
if writable:
|
|
124
|
+
return CheckResult(
|
|
125
|
+
id="permissions_project_praison",
|
|
126
|
+
title=".praison Directory (Project)",
|
|
127
|
+
category=CheckCategory.PERMISSIONS,
|
|
128
|
+
status=CheckStatus.PASS,
|
|
129
|
+
message=".praison is writable",
|
|
130
|
+
metadata={"path": str(praison_dir)},
|
|
131
|
+
)
|
|
132
|
+
else:
|
|
133
|
+
return CheckResult(
|
|
134
|
+
id="permissions_project_praison",
|
|
135
|
+
title=".praison Directory (Project)",
|
|
136
|
+
category=CheckCategory.PERMISSIONS,
|
|
137
|
+
status=CheckStatus.WARN,
|
|
138
|
+
message=f".praison is not writable: {reason}",
|
|
139
|
+
remediation="Fix permissions or use ~/.praison instead",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@register_check(
|
|
144
|
+
id="permissions_temp_dir",
|
|
145
|
+
title="Temp Directory",
|
|
146
|
+
description="Check temp directory permissions",
|
|
147
|
+
category=CheckCategory.PERMISSIONS,
|
|
148
|
+
severity=CheckSeverity.MEDIUM,
|
|
149
|
+
)
|
|
150
|
+
def check_permissions_temp_dir(config: DoctorConfig) -> CheckResult:
|
|
151
|
+
"""Check temp directory permissions."""
|
|
152
|
+
temp_dir = Path(tempfile.gettempdir())
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
# Try to create a temp file
|
|
156
|
+
with tempfile.NamedTemporaryFile(delete=True) as f:
|
|
157
|
+
f.write(b"test")
|
|
158
|
+
|
|
159
|
+
return CheckResult(
|
|
160
|
+
id="permissions_temp_dir",
|
|
161
|
+
title="Temp Directory",
|
|
162
|
+
category=CheckCategory.PERMISSIONS,
|
|
163
|
+
status=CheckStatus.PASS,
|
|
164
|
+
message=f"Temp directory writable: {temp_dir}",
|
|
165
|
+
metadata={"path": str(temp_dir)},
|
|
166
|
+
)
|
|
167
|
+
except Exception as e:
|
|
168
|
+
return CheckResult(
|
|
169
|
+
id="permissions_temp_dir",
|
|
170
|
+
title="Temp Directory",
|
|
171
|
+
category=CheckCategory.PERMISSIONS,
|
|
172
|
+
status=CheckStatus.FAIL,
|
|
173
|
+
message=f"Temp directory not writable: {e}",
|
|
174
|
+
remediation="Check TMPDIR environment variable and permissions",
|
|
175
|
+
severity=CheckSeverity.HIGH,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@register_check(
|
|
180
|
+
id="permissions_cwd",
|
|
181
|
+
title="Current Working Directory",
|
|
182
|
+
description="Check current directory permissions",
|
|
183
|
+
category=CheckCategory.PERMISSIONS,
|
|
184
|
+
severity=CheckSeverity.INFO,
|
|
185
|
+
)
|
|
186
|
+
def check_permissions_cwd(config: DoctorConfig) -> CheckResult:
|
|
187
|
+
"""Check current directory permissions."""
|
|
188
|
+
cwd = Path.cwd()
|
|
189
|
+
|
|
190
|
+
writable, reason = _check_dir_writable(cwd)
|
|
191
|
+
|
|
192
|
+
if writable:
|
|
193
|
+
return CheckResult(
|
|
194
|
+
id="permissions_cwd",
|
|
195
|
+
title="Current Working Directory",
|
|
196
|
+
category=CheckCategory.PERMISSIONS,
|
|
197
|
+
status=CheckStatus.PASS,
|
|
198
|
+
message=f"Current directory writable: {cwd}",
|
|
199
|
+
)
|
|
200
|
+
else:
|
|
201
|
+
return CheckResult(
|
|
202
|
+
id="permissions_cwd",
|
|
203
|
+
title="Current Working Directory",
|
|
204
|
+
category=CheckCategory.PERMISSIONS,
|
|
205
|
+
status=CheckStatus.WARN,
|
|
206
|
+
message=f"Current directory not writable: {reason}",
|
|
207
|
+
details="Some features may not work without write access",
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@register_check(
|
|
212
|
+
id="permissions_config_dir",
|
|
213
|
+
title="Config Directory",
|
|
214
|
+
description="Check ~/.config/praison directory",
|
|
215
|
+
category=CheckCategory.PERMISSIONS,
|
|
216
|
+
severity=CheckSeverity.LOW,
|
|
217
|
+
)
|
|
218
|
+
def check_permissions_config_dir(config: DoctorConfig) -> CheckResult:
|
|
219
|
+
"""Check ~/.config/praison directory."""
|
|
220
|
+
config_dir = Path.home() / ".config" / "praison"
|
|
221
|
+
|
|
222
|
+
if not config_dir.exists():
|
|
223
|
+
# Check if we can create it
|
|
224
|
+
try:
|
|
225
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
226
|
+
return CheckResult(
|
|
227
|
+
id="permissions_config_dir",
|
|
228
|
+
title="Config Directory",
|
|
229
|
+
category=CheckCategory.PERMISSIONS,
|
|
230
|
+
status=CheckStatus.PASS,
|
|
231
|
+
message="~/.config/praison created successfully",
|
|
232
|
+
)
|
|
233
|
+
except Exception:
|
|
234
|
+
return CheckResult(
|
|
235
|
+
id="permissions_config_dir",
|
|
236
|
+
title="Config Directory",
|
|
237
|
+
category=CheckCategory.PERMISSIONS,
|
|
238
|
+
status=CheckStatus.SKIP,
|
|
239
|
+
message="~/.config/praison does not exist (will use ~/.praison)",
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
writable, reason = _check_dir_writable(config_dir)
|
|
243
|
+
|
|
244
|
+
if writable:
|
|
245
|
+
return CheckResult(
|
|
246
|
+
id="permissions_config_dir",
|
|
247
|
+
title="Config Directory",
|
|
248
|
+
category=CheckCategory.PERMISSIONS,
|
|
249
|
+
status=CheckStatus.PASS,
|
|
250
|
+
message="~/.config/praison is writable",
|
|
251
|
+
)
|
|
252
|
+
else:
|
|
253
|
+
return CheckResult(
|
|
254
|
+
id="permissions_config_dir",
|
|
255
|
+
title="Config Directory",
|
|
256
|
+
category=CheckCategory.PERMISSIONS,
|
|
257
|
+
status=CheckStatus.WARN,
|
|
258
|
+
message=f"~/.config/praison not writable: {reason}",
|
|
259
|
+
)
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Selftest checks for the Doctor CLI module.
|
|
3
|
+
|
|
4
|
+
Performs minimal agent dry-run to validate the system.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
from ..models import (
|
|
10
|
+
CheckCategory,
|
|
11
|
+
CheckResult,
|
|
12
|
+
CheckStatus,
|
|
13
|
+
CheckSeverity,
|
|
14
|
+
DoctorConfig,
|
|
15
|
+
)
|
|
16
|
+
from ..registry import register_check
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@register_check(
|
|
20
|
+
id="selftest_agent_import",
|
|
21
|
+
title="Agent Import",
|
|
22
|
+
description="Check Agent class can be imported",
|
|
23
|
+
category=CheckCategory.SELFTEST,
|
|
24
|
+
severity=CheckSeverity.HIGH,
|
|
25
|
+
)
|
|
26
|
+
def check_selftest_agent_import(config: DoctorConfig) -> CheckResult:
|
|
27
|
+
"""Check Agent class can be imported."""
|
|
28
|
+
try:
|
|
29
|
+
from praisonaiagents import Agent
|
|
30
|
+
return CheckResult(
|
|
31
|
+
id="selftest_agent_import",
|
|
32
|
+
title="Agent Import",
|
|
33
|
+
category=CheckCategory.SELFTEST,
|
|
34
|
+
status=CheckStatus.PASS,
|
|
35
|
+
message="Agent class imported successfully",
|
|
36
|
+
)
|
|
37
|
+
except ImportError as e:
|
|
38
|
+
return CheckResult(
|
|
39
|
+
id="selftest_agent_import",
|
|
40
|
+
title="Agent Import",
|
|
41
|
+
category=CheckCategory.SELFTEST,
|
|
42
|
+
status=CheckStatus.FAIL,
|
|
43
|
+
message=f"Cannot import Agent: {e}",
|
|
44
|
+
remediation="Ensure praisonaiagents is properly installed",
|
|
45
|
+
severity=CheckSeverity.CRITICAL,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@register_check(
|
|
50
|
+
id="selftest_agent_create",
|
|
51
|
+
title="Agent Creation",
|
|
52
|
+
description="Check Agent can be instantiated",
|
|
53
|
+
category=CheckCategory.SELFTEST,
|
|
54
|
+
severity=CheckSeverity.HIGH,
|
|
55
|
+
dependencies=["selftest_agent_import"],
|
|
56
|
+
)
|
|
57
|
+
def check_selftest_agent_create(config: DoctorConfig) -> CheckResult:
|
|
58
|
+
"""Check Agent can be instantiated."""
|
|
59
|
+
try:
|
|
60
|
+
from praisonaiagents import Agent
|
|
61
|
+
|
|
62
|
+
# Create a minimal agent without making API calls
|
|
63
|
+
agent = Agent(
|
|
64
|
+
name="DoctorTestAgent",
|
|
65
|
+
instructions="You are a test agent.",
|
|
66
|
+
llm="gpt-4o-mini", # Default model
|
|
67
|
+
verbose=False,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return CheckResult(
|
|
71
|
+
id="selftest_agent_create",
|
|
72
|
+
title="Agent Creation",
|
|
73
|
+
category=CheckCategory.SELFTEST,
|
|
74
|
+
status=CheckStatus.PASS,
|
|
75
|
+
message="Agent instantiated successfully",
|
|
76
|
+
metadata={"agent_name": agent.name},
|
|
77
|
+
)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
return CheckResult(
|
|
80
|
+
id="selftest_agent_create",
|
|
81
|
+
title="Agent Creation",
|
|
82
|
+
category=CheckCategory.SELFTEST,
|
|
83
|
+
status=CheckStatus.FAIL,
|
|
84
|
+
message=f"Agent creation failed: {type(e).__name__}",
|
|
85
|
+
details=str(e)[:200],
|
|
86
|
+
remediation="Check configuration and dependencies",
|
|
87
|
+
severity=CheckSeverity.HIGH,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@register_check(
|
|
92
|
+
id="selftest_llm_config",
|
|
93
|
+
title="LLM Configuration",
|
|
94
|
+
description="Check LLM configuration is valid",
|
|
95
|
+
category=CheckCategory.SELFTEST,
|
|
96
|
+
severity=CheckSeverity.MEDIUM,
|
|
97
|
+
)
|
|
98
|
+
def check_selftest_llm_config(config: DoctorConfig) -> CheckResult:
|
|
99
|
+
"""Check LLM configuration is valid."""
|
|
100
|
+
# Check for API key
|
|
101
|
+
openai_key = os.environ.get("OPENAI_API_KEY")
|
|
102
|
+
anthropic_key = os.environ.get("ANTHROPIC_API_KEY")
|
|
103
|
+
google_key = os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY")
|
|
104
|
+
ollama_host = os.environ.get("OLLAMA_HOST")
|
|
105
|
+
|
|
106
|
+
providers = []
|
|
107
|
+
if openai_key:
|
|
108
|
+
providers.append("OpenAI")
|
|
109
|
+
if anthropic_key:
|
|
110
|
+
providers.append("Anthropic")
|
|
111
|
+
if google_key:
|
|
112
|
+
providers.append("Google")
|
|
113
|
+
if ollama_host:
|
|
114
|
+
providers.append("Ollama")
|
|
115
|
+
|
|
116
|
+
if providers:
|
|
117
|
+
return CheckResult(
|
|
118
|
+
id="selftest_llm_config",
|
|
119
|
+
title="LLM Configuration",
|
|
120
|
+
category=CheckCategory.SELFTEST,
|
|
121
|
+
status=CheckStatus.PASS,
|
|
122
|
+
message=f"LLM provider(s) configured: {', '.join(providers)}",
|
|
123
|
+
metadata={"providers": providers},
|
|
124
|
+
)
|
|
125
|
+
else:
|
|
126
|
+
return CheckResult(
|
|
127
|
+
id="selftest_llm_config",
|
|
128
|
+
title="LLM Configuration",
|
|
129
|
+
category=CheckCategory.SELFTEST,
|
|
130
|
+
status=CheckStatus.FAIL,
|
|
131
|
+
message="No LLM provider configured",
|
|
132
|
+
remediation="Set OPENAI_API_KEY or another provider's API key",
|
|
133
|
+
severity=CheckSeverity.HIGH,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@register_check(
|
|
138
|
+
id="selftest_mock_chat",
|
|
139
|
+
title="Mock Chat Test",
|
|
140
|
+
description="Test agent chat with mock response",
|
|
141
|
+
category=CheckCategory.SELFTEST,
|
|
142
|
+
severity=CheckSeverity.MEDIUM,
|
|
143
|
+
requires_deep=True,
|
|
144
|
+
)
|
|
145
|
+
def check_selftest_mock_chat(config: DoctorConfig) -> CheckResult:
|
|
146
|
+
"""Test agent chat with mock response (no API call)."""
|
|
147
|
+
if not config.mock and not config.live:
|
|
148
|
+
# Default to mock in deep mode
|
|
149
|
+
config.mock = True
|
|
150
|
+
|
|
151
|
+
if config.live:
|
|
152
|
+
return CheckResult(
|
|
153
|
+
id="selftest_mock_chat",
|
|
154
|
+
title="Mock Chat Test",
|
|
155
|
+
category=CheckCategory.SELFTEST,
|
|
156
|
+
status=CheckStatus.SKIP,
|
|
157
|
+
message="Skipped (--live mode uses live API)",
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
# Test basic agent functionality without making API calls
|
|
162
|
+
from praisonaiagents import Agent
|
|
163
|
+
|
|
164
|
+
agent = Agent(
|
|
165
|
+
name="MockTestAgent",
|
|
166
|
+
instructions="You are a test agent. Always respond with 'OK'.",
|
|
167
|
+
llm="gpt-4o-mini",
|
|
168
|
+
verbose=False,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Verify agent is properly configured
|
|
172
|
+
if hasattr(agent, 'name') and hasattr(agent, 'instructions'):
|
|
173
|
+
return CheckResult(
|
|
174
|
+
id="selftest_mock_chat",
|
|
175
|
+
title="Mock Chat Test",
|
|
176
|
+
category=CheckCategory.SELFTEST,
|
|
177
|
+
status=CheckStatus.PASS,
|
|
178
|
+
message="Agent mock test passed",
|
|
179
|
+
)
|
|
180
|
+
else:
|
|
181
|
+
return CheckResult(
|
|
182
|
+
id="selftest_mock_chat",
|
|
183
|
+
title="Mock Chat Test",
|
|
184
|
+
category=CheckCategory.SELFTEST,
|
|
185
|
+
status=CheckStatus.FAIL,
|
|
186
|
+
message="Agent missing expected attributes",
|
|
187
|
+
)
|
|
188
|
+
except Exception as e:
|
|
189
|
+
return CheckResult(
|
|
190
|
+
id="selftest_mock_chat",
|
|
191
|
+
title="Mock Chat Test",
|
|
192
|
+
category=CheckCategory.SELFTEST,
|
|
193
|
+
status=CheckStatus.FAIL,
|
|
194
|
+
message=f"Mock test failed: {type(e).__name__}",
|
|
195
|
+
details=str(e)[:200],
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@register_check(
|
|
200
|
+
id="selftest_live_chat",
|
|
201
|
+
title="Live Chat Test",
|
|
202
|
+
description="Test agent chat with live API call",
|
|
203
|
+
category=CheckCategory.SELFTEST,
|
|
204
|
+
severity=CheckSeverity.LOW,
|
|
205
|
+
requires_deep=True,
|
|
206
|
+
)
|
|
207
|
+
def check_selftest_live_chat(config: DoctorConfig) -> CheckResult:
|
|
208
|
+
"""Test agent chat with live API call."""
|
|
209
|
+
if not config.live:
|
|
210
|
+
return CheckResult(
|
|
211
|
+
id="selftest_live_chat",
|
|
212
|
+
title="Live Chat Test",
|
|
213
|
+
category=CheckCategory.SELFTEST,
|
|
214
|
+
status=CheckStatus.SKIP,
|
|
215
|
+
message="Skipped (use --live to enable)",
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# Check for API key first
|
|
219
|
+
if not os.environ.get("OPENAI_API_KEY"):
|
|
220
|
+
return CheckResult(
|
|
221
|
+
id="selftest_live_chat",
|
|
222
|
+
title="Live Chat Test",
|
|
223
|
+
category=CheckCategory.SELFTEST,
|
|
224
|
+
status=CheckStatus.SKIP,
|
|
225
|
+
message="Skipped (OPENAI_API_KEY not set)",
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
from praisonaiagents import Agent
|
|
230
|
+
|
|
231
|
+
model = config.model or "gpt-4o-mini"
|
|
232
|
+
|
|
233
|
+
agent = Agent(
|
|
234
|
+
name="LiveTestAgent",
|
|
235
|
+
instructions="You are a test agent. Respond with exactly: 'Doctor test OK'",
|
|
236
|
+
llm=model,
|
|
237
|
+
verbose=False,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# Make a simple API call
|
|
241
|
+
response = agent.chat("Say hello")
|
|
242
|
+
|
|
243
|
+
if response:
|
|
244
|
+
return CheckResult(
|
|
245
|
+
id="selftest_live_chat",
|
|
246
|
+
title="Live Chat Test",
|
|
247
|
+
category=CheckCategory.SELFTEST,
|
|
248
|
+
status=CheckStatus.PASS,
|
|
249
|
+
message=f"Live API call successful (model: {model})",
|
|
250
|
+
metadata={"model": model, "response_length": len(str(response))},
|
|
251
|
+
)
|
|
252
|
+
else:
|
|
253
|
+
return CheckResult(
|
|
254
|
+
id="selftest_live_chat",
|
|
255
|
+
title="Live Chat Test",
|
|
256
|
+
category=CheckCategory.SELFTEST,
|
|
257
|
+
status=CheckStatus.FAIL,
|
|
258
|
+
message="Live API call returned empty response",
|
|
259
|
+
)
|
|
260
|
+
except Exception as e:
|
|
261
|
+
return CheckResult(
|
|
262
|
+
id="selftest_live_chat",
|
|
263
|
+
title="Live Chat Test",
|
|
264
|
+
category=CheckCategory.SELFTEST,
|
|
265
|
+
status=CheckStatus.FAIL,
|
|
266
|
+
message=f"Live API call failed: {type(e).__name__}",
|
|
267
|
+
details=str(e)[:200],
|
|
268
|
+
remediation="Check API key and network connectivity",
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
@register_check(
|
|
273
|
+
id="selftest_tools_wiring",
|
|
274
|
+
title="Tools Wiring",
|
|
275
|
+
description="Check tools can be wired to agent",
|
|
276
|
+
category=CheckCategory.SELFTEST,
|
|
277
|
+
severity=CheckSeverity.LOW,
|
|
278
|
+
)
|
|
279
|
+
def check_selftest_tools_wiring(config: DoctorConfig) -> CheckResult:
|
|
280
|
+
"""Check tools can be wired to agent."""
|
|
281
|
+
try:
|
|
282
|
+
from praisonaiagents import Agent
|
|
283
|
+
|
|
284
|
+
# Define a simple test tool
|
|
285
|
+
def test_tool(x: str) -> str:
|
|
286
|
+
"""A test tool that echoes input."""
|
|
287
|
+
return f"Echo: {x}"
|
|
288
|
+
|
|
289
|
+
agent = Agent(
|
|
290
|
+
name="ToolTestAgent",
|
|
291
|
+
instructions="You are a test agent with tools.",
|
|
292
|
+
tools=[test_tool],
|
|
293
|
+
llm="gpt-4o-mini",
|
|
294
|
+
verbose=False,
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# Check tools are registered
|
|
298
|
+
if hasattr(agent, 'tools') or hasattr(agent, '_tools'):
|
|
299
|
+
return CheckResult(
|
|
300
|
+
id="selftest_tools_wiring",
|
|
301
|
+
title="Tools Wiring",
|
|
302
|
+
category=CheckCategory.SELFTEST,
|
|
303
|
+
status=CheckStatus.PASS,
|
|
304
|
+
message="Tools wired to agent successfully",
|
|
305
|
+
)
|
|
306
|
+
else:
|
|
307
|
+
return CheckResult(
|
|
308
|
+
id="selftest_tools_wiring",
|
|
309
|
+
title="Tools Wiring",
|
|
310
|
+
category=CheckCategory.SELFTEST,
|
|
311
|
+
status=CheckStatus.WARN,
|
|
312
|
+
message="Tools wiring could not be verified",
|
|
313
|
+
)
|
|
314
|
+
except Exception as e:
|
|
315
|
+
return CheckResult(
|
|
316
|
+
id="selftest_tools_wiring",
|
|
317
|
+
title="Tools Wiring",
|
|
318
|
+
category=CheckCategory.SELFTEST,
|
|
319
|
+
status=CheckStatus.FAIL,
|
|
320
|
+
message=f"Tools wiring failed: {type(e).__name__}",
|
|
321
|
+
details=str(e)[:200],
|
|
322
|
+
)
|