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,367 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Deploy doctor - connectivity and readiness checks.
|
|
3
|
+
"""
|
|
4
|
+
import subprocess
|
|
5
|
+
import socket
|
|
6
|
+
import sys
|
|
7
|
+
from typing import Optional, List
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from .schema import validate_agents_yaml
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class DoctorCheckResult:
|
|
14
|
+
"""Result of a single doctor check."""
|
|
15
|
+
name: str
|
|
16
|
+
passed: bool
|
|
17
|
+
message: str
|
|
18
|
+
fix_suggestion: Optional[str] = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class DoctorReport:
|
|
23
|
+
"""Aggregated report of all doctor checks."""
|
|
24
|
+
checks: List[DoctorCheckResult]
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def total_checks(self) -> int:
|
|
28
|
+
return len(self.checks)
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def passed_checks(self) -> int:
|
|
32
|
+
return sum(1 for c in self.checks if c.passed)
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def failed_checks(self) -> int:
|
|
36
|
+
return sum(1 for c in self.checks if not c.passed)
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def all_passed(self) -> bool:
|
|
40
|
+
return all(c.passed for c in self.checks)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def check_python_version() -> DoctorCheckResult:
|
|
44
|
+
"""Check Python version is 3.9+."""
|
|
45
|
+
try:
|
|
46
|
+
version = sys.version_info
|
|
47
|
+
version_str = f"{version.major}.{version.minor}.{version.micro}"
|
|
48
|
+
|
|
49
|
+
if version.major >= 3 and version.minor >= 9:
|
|
50
|
+
return DoctorCheckResult(
|
|
51
|
+
name="Python Version",
|
|
52
|
+
passed=True,
|
|
53
|
+
message=f"Python {version_str} (>= 3.9 required)"
|
|
54
|
+
)
|
|
55
|
+
else:
|
|
56
|
+
return DoctorCheckResult(
|
|
57
|
+
name="Python Version",
|
|
58
|
+
passed=False,
|
|
59
|
+
message=f"Python {version_str} found, but 3.9+ required",
|
|
60
|
+
fix_suggestion="Upgrade Python to version 3.9 or higher"
|
|
61
|
+
)
|
|
62
|
+
except Exception as e:
|
|
63
|
+
return DoctorCheckResult(
|
|
64
|
+
name="Python Version",
|
|
65
|
+
passed=False,
|
|
66
|
+
message=f"Failed to check Python version: {e}",
|
|
67
|
+
fix_suggestion="Ensure Python is properly installed"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def check_docker_available() -> DoctorCheckResult:
|
|
72
|
+
"""Check if Docker is installed and running."""
|
|
73
|
+
try:
|
|
74
|
+
result = subprocess.run(
|
|
75
|
+
['docker', '--version'],
|
|
76
|
+
capture_output=True,
|
|
77
|
+
text=True,
|
|
78
|
+
timeout=5
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if result.returncode == 0:
|
|
82
|
+
version = result.stdout.strip()
|
|
83
|
+
return DoctorCheckResult(
|
|
84
|
+
name="Docker",
|
|
85
|
+
passed=True,
|
|
86
|
+
message=f"Docker available: {version}"
|
|
87
|
+
)
|
|
88
|
+
else:
|
|
89
|
+
return DoctorCheckResult(
|
|
90
|
+
name="Docker",
|
|
91
|
+
passed=False,
|
|
92
|
+
message="Docker command failed",
|
|
93
|
+
fix_suggestion="Install Docker: https://docs.docker.com/get-docker/"
|
|
94
|
+
)
|
|
95
|
+
except FileNotFoundError:
|
|
96
|
+
return DoctorCheckResult(
|
|
97
|
+
name="Docker",
|
|
98
|
+
passed=False,
|
|
99
|
+
message="Docker not found",
|
|
100
|
+
fix_suggestion="Install Docker: https://docs.docker.com/get-docker/"
|
|
101
|
+
)
|
|
102
|
+
except Exception as e:
|
|
103
|
+
return DoctorCheckResult(
|
|
104
|
+
name="Docker",
|
|
105
|
+
passed=False,
|
|
106
|
+
message=f"Docker check failed: {e}",
|
|
107
|
+
fix_suggestion="Ensure Docker is installed and running"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def check_port_available(port: int) -> DoctorCheckResult:
|
|
112
|
+
"""Check if a port is available."""
|
|
113
|
+
try:
|
|
114
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
115
|
+
result = s.connect_ex(('127.0.0.1', port))
|
|
116
|
+
|
|
117
|
+
if result != 0:
|
|
118
|
+
return DoctorCheckResult(
|
|
119
|
+
name=f"Port {port}",
|
|
120
|
+
passed=True,
|
|
121
|
+
message=f"Port {port} is available"
|
|
122
|
+
)
|
|
123
|
+
else:
|
|
124
|
+
return DoctorCheckResult(
|
|
125
|
+
name=f"Port {port}",
|
|
126
|
+
passed=False,
|
|
127
|
+
message=f"Port {port} is already in use",
|
|
128
|
+
fix_suggestion=f"Stop the service using port {port} or choose a different port"
|
|
129
|
+
)
|
|
130
|
+
except Exception as e:
|
|
131
|
+
return DoctorCheckResult(
|
|
132
|
+
name=f"Port {port}",
|
|
133
|
+
passed=False,
|
|
134
|
+
message=f"Failed to check port {port}: {e}",
|
|
135
|
+
fix_suggestion="Check network configuration"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def check_aws_cli() -> DoctorCheckResult:
|
|
140
|
+
"""Check AWS CLI configuration."""
|
|
141
|
+
try:
|
|
142
|
+
result = subprocess.run(
|
|
143
|
+
['aws', 'sts', 'get-caller-identity', '--output', 'json'],
|
|
144
|
+
capture_output=True,
|
|
145
|
+
text=True,
|
|
146
|
+
timeout=10
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
if result.returncode == 0:
|
|
150
|
+
import json
|
|
151
|
+
identity = json.loads(result.stdout)
|
|
152
|
+
account = identity.get('Account', 'unknown')
|
|
153
|
+
user_id = identity.get('UserId', 'unknown')
|
|
154
|
+
|
|
155
|
+
return DoctorCheckResult(
|
|
156
|
+
name="AWS CLI",
|
|
157
|
+
passed=True,
|
|
158
|
+
message=f"AWS CLI configured (Account: {account[:4]}...{account[-4:]})"
|
|
159
|
+
)
|
|
160
|
+
else:
|
|
161
|
+
return DoctorCheckResult(
|
|
162
|
+
name="AWS CLI",
|
|
163
|
+
passed=False,
|
|
164
|
+
message="AWS CLI not configured or credentials invalid",
|
|
165
|
+
fix_suggestion="Run: aws configure"
|
|
166
|
+
)
|
|
167
|
+
except FileNotFoundError:
|
|
168
|
+
return DoctorCheckResult(
|
|
169
|
+
name="AWS CLI",
|
|
170
|
+
passed=False,
|
|
171
|
+
message="AWS CLI not installed",
|
|
172
|
+
fix_suggestion="Install AWS CLI: https://aws.amazon.com/cli/"
|
|
173
|
+
)
|
|
174
|
+
except Exception as e:
|
|
175
|
+
return DoctorCheckResult(
|
|
176
|
+
name="AWS CLI",
|
|
177
|
+
passed=False,
|
|
178
|
+
message=f"AWS CLI check failed: {e}",
|
|
179
|
+
fix_suggestion="Run: aws configure"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def check_azure_cli() -> DoctorCheckResult:
|
|
184
|
+
"""Check Azure CLI configuration."""
|
|
185
|
+
try:
|
|
186
|
+
result = subprocess.run(
|
|
187
|
+
['az', 'account', 'show', '--output', 'json'],
|
|
188
|
+
capture_output=True,
|
|
189
|
+
text=True,
|
|
190
|
+
timeout=10
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
if result.returncode == 0:
|
|
194
|
+
import json
|
|
195
|
+
account = json.loads(result.stdout)
|
|
196
|
+
sub_id = account.get('id', 'unknown')
|
|
197
|
+
name = account.get('name', 'unknown')
|
|
198
|
+
|
|
199
|
+
return DoctorCheckResult(
|
|
200
|
+
name="Azure CLI",
|
|
201
|
+
passed=True,
|
|
202
|
+
message=f"Azure CLI logged in (Subscription: {sub_id[:8]}...)"
|
|
203
|
+
)
|
|
204
|
+
else:
|
|
205
|
+
return DoctorCheckResult(
|
|
206
|
+
name="Azure CLI",
|
|
207
|
+
passed=False,
|
|
208
|
+
message="Azure CLI not logged in",
|
|
209
|
+
fix_suggestion="Run: az login"
|
|
210
|
+
)
|
|
211
|
+
except FileNotFoundError:
|
|
212
|
+
return DoctorCheckResult(
|
|
213
|
+
name="Azure CLI",
|
|
214
|
+
passed=False,
|
|
215
|
+
message="Azure CLI not installed",
|
|
216
|
+
fix_suggestion="Install Azure CLI: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"
|
|
217
|
+
)
|
|
218
|
+
except Exception as e:
|
|
219
|
+
return DoctorCheckResult(
|
|
220
|
+
name="Azure CLI",
|
|
221
|
+
passed=False,
|
|
222
|
+
message=f"Azure CLI check failed: {e}",
|
|
223
|
+
fix_suggestion="Run: az login"
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def check_gcp_cli() -> DoctorCheckResult:
|
|
228
|
+
"""Check GCP CLI configuration."""
|
|
229
|
+
try:
|
|
230
|
+
result = subprocess.run(
|
|
231
|
+
['gcloud', 'config', 'get-value', 'project'],
|
|
232
|
+
capture_output=True,
|
|
233
|
+
text=True,
|
|
234
|
+
timeout=10
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
238
|
+
project_id = result.stdout.strip()
|
|
239
|
+
|
|
240
|
+
return DoctorCheckResult(
|
|
241
|
+
name="GCP CLI",
|
|
242
|
+
passed=True,
|
|
243
|
+
message=f"GCP CLI configured (Project: {project_id})"
|
|
244
|
+
)
|
|
245
|
+
else:
|
|
246
|
+
return DoctorCheckResult(
|
|
247
|
+
name="GCP CLI",
|
|
248
|
+
passed=False,
|
|
249
|
+
message="GCP CLI not configured or no project set",
|
|
250
|
+
fix_suggestion="Run: gcloud init"
|
|
251
|
+
)
|
|
252
|
+
except FileNotFoundError:
|
|
253
|
+
return DoctorCheckResult(
|
|
254
|
+
name="GCP CLI",
|
|
255
|
+
passed=False,
|
|
256
|
+
message="GCP CLI not installed",
|
|
257
|
+
fix_suggestion="Install gcloud CLI: https://cloud.google.com/sdk/docs/install"
|
|
258
|
+
)
|
|
259
|
+
except Exception as e:
|
|
260
|
+
return DoctorCheckResult(
|
|
261
|
+
name="GCP CLI",
|
|
262
|
+
passed=False,
|
|
263
|
+
message=f"GCP CLI check failed: {e}",
|
|
264
|
+
fix_suggestion="Run: gcloud init"
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def check_agents_yaml(file_path: str) -> DoctorCheckResult:
|
|
269
|
+
"""Check if agents.yaml exists and has valid deploy config."""
|
|
270
|
+
try:
|
|
271
|
+
config = validate_agents_yaml(file_path)
|
|
272
|
+
|
|
273
|
+
if config:
|
|
274
|
+
return DoctorCheckResult(
|
|
275
|
+
name="agents.yaml",
|
|
276
|
+
passed=True,
|
|
277
|
+
message=f"Valid deploy configuration found (type: {config.type.value})"
|
|
278
|
+
)
|
|
279
|
+
else:
|
|
280
|
+
return DoctorCheckResult(
|
|
281
|
+
name="agents.yaml",
|
|
282
|
+
passed=False,
|
|
283
|
+
message="No deploy section found in agents.yaml",
|
|
284
|
+
fix_suggestion="Add deploy configuration to agents.yaml or run: praisonai deploy init"
|
|
285
|
+
)
|
|
286
|
+
except FileNotFoundError:
|
|
287
|
+
return DoctorCheckResult(
|
|
288
|
+
name="agents.yaml",
|
|
289
|
+
passed=False,
|
|
290
|
+
message=f"File not found: {file_path}",
|
|
291
|
+
fix_suggestion="Create agents.yaml or run: praisonai deploy init"
|
|
292
|
+
)
|
|
293
|
+
except ValueError as e:
|
|
294
|
+
return DoctorCheckResult(
|
|
295
|
+
name="agents.yaml",
|
|
296
|
+
passed=False,
|
|
297
|
+
message=f"Invalid deploy configuration: {e}",
|
|
298
|
+
fix_suggestion="Fix deploy configuration in agents.yaml or run: praisonai deploy validate"
|
|
299
|
+
)
|
|
300
|
+
except Exception as e:
|
|
301
|
+
return DoctorCheckResult(
|
|
302
|
+
name="agents.yaml",
|
|
303
|
+
passed=False,
|
|
304
|
+
message=f"Failed to validate agents.yaml: {e}",
|
|
305
|
+
fix_suggestion="Check agents.yaml syntax"
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def run_local_checks(port: int = 8005, agents_file: Optional[str] = None) -> DoctorReport:
|
|
310
|
+
"""Run local environment checks."""
|
|
311
|
+
checks = [
|
|
312
|
+
check_python_version(),
|
|
313
|
+
check_port_available(port),
|
|
314
|
+
]
|
|
315
|
+
|
|
316
|
+
if agents_file:
|
|
317
|
+
checks.append(check_agents_yaml(agents_file))
|
|
318
|
+
|
|
319
|
+
return DoctorReport(checks=checks)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def run_aws_checks() -> DoctorReport:
|
|
323
|
+
"""Run AWS-specific checks."""
|
|
324
|
+
checks = [
|
|
325
|
+
check_aws_cli(),
|
|
326
|
+
]
|
|
327
|
+
return DoctorReport(checks=checks)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def run_azure_checks() -> DoctorReport:
|
|
331
|
+
"""Run Azure-specific checks."""
|
|
332
|
+
checks = [
|
|
333
|
+
check_azure_cli(),
|
|
334
|
+
]
|
|
335
|
+
return DoctorReport(checks=checks)
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def run_gcp_checks() -> DoctorReport:
|
|
339
|
+
"""Run GCP-specific checks."""
|
|
340
|
+
checks = [
|
|
341
|
+
check_gcp_cli(),
|
|
342
|
+
]
|
|
343
|
+
return DoctorReport(checks=checks)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def run_all_checks(agents_file: Optional[str] = None) -> DoctorReport:
|
|
347
|
+
"""Run all available checks."""
|
|
348
|
+
checks = []
|
|
349
|
+
|
|
350
|
+
# Local checks
|
|
351
|
+
local_report = run_local_checks(agents_file=agents_file)
|
|
352
|
+
checks.extend(local_report.checks)
|
|
353
|
+
|
|
354
|
+
# Docker check
|
|
355
|
+
checks.append(check_docker_available())
|
|
356
|
+
|
|
357
|
+
# Cloud provider checks
|
|
358
|
+
aws_report = run_aws_checks()
|
|
359
|
+
checks.extend(aws_report.checks)
|
|
360
|
+
|
|
361
|
+
azure_report = run_azure_checks()
|
|
362
|
+
checks.extend(azure_report.checks)
|
|
363
|
+
|
|
364
|
+
gcp_report = run_gcp_checks()
|
|
365
|
+
checks.extend(gcp_report.checks)
|
|
366
|
+
|
|
367
|
+
return DoctorReport(checks=checks)
|
praisonai/deploy/main.py
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Main Deploy class for unified deployment interface.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Dict, Any
|
|
5
|
+
from .models import DeployConfig, DeployResult, DeployType, DeployStatus, DestroyResult, ServiceState
|
|
6
|
+
from .schema import validate_agents_yaml
|
|
7
|
+
from .api import start_api_server, generate_api_server_code
|
|
8
|
+
from .docker import (
|
|
9
|
+
build_docker_image, run_docker_container, push_docker_image, save_dockerfile,
|
|
10
|
+
get_docker_container_status, remove_docker_container
|
|
11
|
+
)
|
|
12
|
+
from .providers import get_provider
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Deploy:
|
|
16
|
+
"""
|
|
17
|
+
Unified deployment interface for PraisonAI agents.
|
|
18
|
+
|
|
19
|
+
Supports:
|
|
20
|
+
- API server deployment (local/production)
|
|
21
|
+
- Docker containerization
|
|
22
|
+
- Cloud deployment (AWS, Azure, GCP)
|
|
23
|
+
|
|
24
|
+
Examples:
|
|
25
|
+
# From YAML
|
|
26
|
+
deploy = Deploy.from_yaml("agents.yaml")
|
|
27
|
+
result = deploy.deploy()
|
|
28
|
+
|
|
29
|
+
# Programmatic
|
|
30
|
+
from praisonai.deploy import Deploy, DeployConfig, DeployType
|
|
31
|
+
|
|
32
|
+
config = DeployConfig(type=DeployType.API)
|
|
33
|
+
deploy = Deploy(config, agents_file="agents.yaml")
|
|
34
|
+
result = deploy.deploy()
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, config: DeployConfig, agents_file: str = "agents.yaml"):
|
|
38
|
+
"""
|
|
39
|
+
Initialize Deploy with configuration.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
config: Deployment configuration
|
|
43
|
+
agents_file: Path to agents.yaml file
|
|
44
|
+
"""
|
|
45
|
+
self.config = config
|
|
46
|
+
self.agents_file = agents_file
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def from_yaml(cls, agents_file: str = "agents.yaml") -> 'Deploy':
|
|
50
|
+
"""
|
|
51
|
+
Create Deploy instance from agents.yaml file.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
agents_file: Path to agents.yaml file
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Deploy instance
|
|
58
|
+
|
|
59
|
+
Raises:
|
|
60
|
+
ValueError: If no deploy configuration found in YAML
|
|
61
|
+
"""
|
|
62
|
+
config = validate_agents_yaml(agents_file)
|
|
63
|
+
|
|
64
|
+
if config is None:
|
|
65
|
+
raise ValueError(f"No deploy configuration found in {agents_file}")
|
|
66
|
+
|
|
67
|
+
return cls(config, agents_file)
|
|
68
|
+
|
|
69
|
+
def deploy(self, background: bool = False) -> DeployResult:
|
|
70
|
+
"""
|
|
71
|
+
Execute deployment based on configuration.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
background: Run in background mode (for API deployments)
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
DeployResult with deployment information
|
|
78
|
+
"""
|
|
79
|
+
if self.config.type == DeployType.API:
|
|
80
|
+
return self._deploy_api(background)
|
|
81
|
+
elif self.config.type == DeployType.DOCKER:
|
|
82
|
+
return self._deploy_docker()
|
|
83
|
+
elif self.config.type == DeployType.CLOUD:
|
|
84
|
+
return self._deploy_cloud()
|
|
85
|
+
else:
|
|
86
|
+
return DeployResult(
|
|
87
|
+
success=False,
|
|
88
|
+
message=f"Unsupported deployment type: {self.config.type}",
|
|
89
|
+
error="Invalid deployment type"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def _deploy_api(self, background: bool = False) -> DeployResult:
|
|
93
|
+
"""Deploy as API server."""
|
|
94
|
+
return start_api_server(
|
|
95
|
+
self.agents_file,
|
|
96
|
+
self.config.api,
|
|
97
|
+
background=background
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def _deploy_docker(self) -> DeployResult:
|
|
101
|
+
"""Deploy as Docker container."""
|
|
102
|
+
# Generate and save Dockerfile
|
|
103
|
+
save_dockerfile(self.agents_file, self.config.docker)
|
|
104
|
+
|
|
105
|
+
# Generate API server code
|
|
106
|
+
api_code = generate_api_server_code(self.agents_file, None)
|
|
107
|
+
with open("api_server.py", 'w') as f:
|
|
108
|
+
f.write(api_code)
|
|
109
|
+
|
|
110
|
+
# Build image
|
|
111
|
+
build_result = build_docker_image(self.config.docker)
|
|
112
|
+
|
|
113
|
+
if not build_result.success:
|
|
114
|
+
return build_result
|
|
115
|
+
|
|
116
|
+
# Push if configured
|
|
117
|
+
if self.config.docker.push and self.config.docker.registry:
|
|
118
|
+
push_result = push_docker_image(self.config.docker)
|
|
119
|
+
if not push_result.success:
|
|
120
|
+
return push_result
|
|
121
|
+
|
|
122
|
+
# Run container
|
|
123
|
+
return run_docker_container(self.config.docker)
|
|
124
|
+
|
|
125
|
+
def _deploy_cloud(self) -> DeployResult:
|
|
126
|
+
"""Deploy to cloud provider."""
|
|
127
|
+
provider = get_provider(self.config.cloud)
|
|
128
|
+
return provider.deploy()
|
|
129
|
+
|
|
130
|
+
def plan(self) -> Dict[str, Any]:
|
|
131
|
+
"""
|
|
132
|
+
Generate deployment plan without executing.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Dictionary with planned deployment configuration
|
|
136
|
+
"""
|
|
137
|
+
if self.config.type == DeployType.API:
|
|
138
|
+
return {
|
|
139
|
+
"type": "api",
|
|
140
|
+
"host": self.config.api.host,
|
|
141
|
+
"port": self.config.api.port,
|
|
142
|
+
"workers": self.config.api.workers,
|
|
143
|
+
"agents_file": self.agents_file
|
|
144
|
+
}
|
|
145
|
+
elif self.config.type == DeployType.DOCKER:
|
|
146
|
+
return {
|
|
147
|
+
"type": "docker",
|
|
148
|
+
"image": f"{self.config.docker.image_name}:{self.config.docker.tag}",
|
|
149
|
+
"registry": self.config.docker.registry,
|
|
150
|
+
"push": self.config.docker.push,
|
|
151
|
+
"ports": self.config.docker.expose
|
|
152
|
+
}
|
|
153
|
+
elif self.config.type == DeployType.CLOUD:
|
|
154
|
+
provider = get_provider(self.config.cloud)
|
|
155
|
+
return provider.plan()
|
|
156
|
+
else:
|
|
157
|
+
return {"error": "Invalid deployment type"}
|
|
158
|
+
|
|
159
|
+
def doctor(self):
|
|
160
|
+
"""
|
|
161
|
+
Run health checks for deployment.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
DoctorReport with check results
|
|
165
|
+
"""
|
|
166
|
+
from .doctor import run_local_checks, run_all_checks, DoctorReport
|
|
167
|
+
|
|
168
|
+
if self.config.type == DeployType.API:
|
|
169
|
+
return run_local_checks(
|
|
170
|
+
port=self.config.api.port,
|
|
171
|
+
agents_file=self.agents_file
|
|
172
|
+
)
|
|
173
|
+
elif self.config.type == DeployType.DOCKER:
|
|
174
|
+
from .doctor import check_docker_available, DoctorReport
|
|
175
|
+
checks = run_local_checks(agents_file=self.agents_file).checks
|
|
176
|
+
checks.append(check_docker_available())
|
|
177
|
+
return DoctorReport(checks=checks)
|
|
178
|
+
elif self.config.type == DeployType.CLOUD:
|
|
179
|
+
provider = get_provider(self.config.cloud)
|
|
180
|
+
return provider.doctor()
|
|
181
|
+
else:
|
|
182
|
+
return run_all_checks(self.agents_file)
|
|
183
|
+
|
|
184
|
+
def status(self) -> DeployStatus:
|
|
185
|
+
"""
|
|
186
|
+
Get current deployment status.
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
DeployStatus with current state and information
|
|
190
|
+
"""
|
|
191
|
+
if self.config.type == DeployType.API:
|
|
192
|
+
return self._status_api()
|
|
193
|
+
elif self.config.type == DeployType.DOCKER:
|
|
194
|
+
return self._status_docker()
|
|
195
|
+
elif self.config.type == DeployType.CLOUD:
|
|
196
|
+
return self._status_cloud()
|
|
197
|
+
else:
|
|
198
|
+
return DeployStatus(
|
|
199
|
+
state=ServiceState.UNKNOWN,
|
|
200
|
+
message=f"Unsupported deployment type: {self.config.type}"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
def _status_api(self) -> DeployStatus:
|
|
204
|
+
"""Get status of local API server."""
|
|
205
|
+
import socket
|
|
206
|
+
port = self.config.api.port if self.config.api else 8005
|
|
207
|
+
|
|
208
|
+
try:
|
|
209
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
210
|
+
result = sock.connect_ex(('127.0.0.1', port))
|
|
211
|
+
sock.close()
|
|
212
|
+
|
|
213
|
+
if result == 0:
|
|
214
|
+
return DeployStatus(
|
|
215
|
+
state=ServiceState.RUNNING,
|
|
216
|
+
url=f"http://127.0.0.1:{port}",
|
|
217
|
+
message=f"API server running on port {port}",
|
|
218
|
+
service_name="praisonai-api",
|
|
219
|
+
provider="api",
|
|
220
|
+
healthy=True,
|
|
221
|
+
instances_running=1,
|
|
222
|
+
instances_desired=1
|
|
223
|
+
)
|
|
224
|
+
else:
|
|
225
|
+
return DeployStatus(
|
|
226
|
+
state=ServiceState.STOPPED,
|
|
227
|
+
message=f"No service running on port {port}",
|
|
228
|
+
service_name="praisonai-api",
|
|
229
|
+
provider="api",
|
|
230
|
+
healthy=False,
|
|
231
|
+
instances_running=0,
|
|
232
|
+
instances_desired=1
|
|
233
|
+
)
|
|
234
|
+
except Exception as e:
|
|
235
|
+
return DeployStatus(
|
|
236
|
+
state=ServiceState.UNKNOWN,
|
|
237
|
+
message=f"Failed to check status: {e}",
|
|
238
|
+
service_name="praisonai-api",
|
|
239
|
+
provider="api"
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
def _status_docker(self) -> DeployStatus:
|
|
243
|
+
"""Get status of Docker container."""
|
|
244
|
+
return get_docker_container_status(self.config.docker)
|
|
245
|
+
|
|
246
|
+
def _status_cloud(self) -> DeployStatus:
|
|
247
|
+
"""Get status of cloud deployment."""
|
|
248
|
+
provider = get_provider(self.config.cloud)
|
|
249
|
+
return provider.status()
|
|
250
|
+
|
|
251
|
+
def destroy(self, force: bool = False) -> DestroyResult:
|
|
252
|
+
"""
|
|
253
|
+
Destroy/delete the deployment.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
force: Force deletion without confirmation
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
DestroyResult with deletion information
|
|
260
|
+
"""
|
|
261
|
+
if self.config.type == DeployType.API:
|
|
262
|
+
return self._destroy_api()
|
|
263
|
+
elif self.config.type == DeployType.DOCKER:
|
|
264
|
+
return self._destroy_docker(force)
|
|
265
|
+
elif self.config.type == DeployType.CLOUD:
|
|
266
|
+
return self._destroy_cloud(force)
|
|
267
|
+
else:
|
|
268
|
+
return DestroyResult(
|
|
269
|
+
success=False,
|
|
270
|
+
message=f"Unsupported deployment type: {self.config.type}",
|
|
271
|
+
error="Invalid deployment type"
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
def _destroy_api(self) -> DestroyResult:
|
|
275
|
+
"""Stop local API server."""
|
|
276
|
+
import subprocess
|
|
277
|
+
import signal
|
|
278
|
+
import os
|
|
279
|
+
|
|
280
|
+
port = self.config.api.port if self.config.api else 8005
|
|
281
|
+
|
|
282
|
+
try:
|
|
283
|
+
# Find process using the port
|
|
284
|
+
result = subprocess.run(
|
|
285
|
+
['lsof', '-ti', f':{port}'],
|
|
286
|
+
capture_output=True,
|
|
287
|
+
text=True,
|
|
288
|
+
timeout=5
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
292
|
+
pids = result.stdout.strip().split('\n')
|
|
293
|
+
deleted_resources = []
|
|
294
|
+
|
|
295
|
+
for pid in pids:
|
|
296
|
+
try:
|
|
297
|
+
os.kill(int(pid), signal.SIGTERM)
|
|
298
|
+
deleted_resources.append(f"process:{pid}")
|
|
299
|
+
except (ProcessLookupError, ValueError):
|
|
300
|
+
pass
|
|
301
|
+
|
|
302
|
+
return DestroyResult(
|
|
303
|
+
success=True,
|
|
304
|
+
message=f"Stopped API server on port {port}",
|
|
305
|
+
resources_deleted=deleted_resources
|
|
306
|
+
)
|
|
307
|
+
else:
|
|
308
|
+
return DestroyResult(
|
|
309
|
+
success=True,
|
|
310
|
+
message=f"No API server running on port {port}",
|
|
311
|
+
resources_deleted=[]
|
|
312
|
+
)
|
|
313
|
+
except Exception as e:
|
|
314
|
+
return DestroyResult(
|
|
315
|
+
success=False,
|
|
316
|
+
message="Failed to stop API server",
|
|
317
|
+
error=str(e)
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
def _destroy_docker(self, force: bool = False) -> DestroyResult:
|
|
321
|
+
"""Remove Docker container."""
|
|
322
|
+
return remove_docker_container(self.config.docker, force)
|
|
323
|
+
|
|
324
|
+
def _destroy_cloud(self, force: bool = False) -> DestroyResult:
|
|
325
|
+
"""Destroy cloud deployment."""
|
|
326
|
+
provider = get_provider(self.config.cloud)
|
|
327
|
+
return provider.destroy(force)
|