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
praisonai/jobs/server.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Server for PraisonAI Async Jobs API.
|
|
3
|
+
|
|
4
|
+
Provides FastAPI application setup and server startup.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
import os
|
|
9
|
+
from typing import Optional
|
|
10
|
+
from contextlib import asynccontextmanager
|
|
11
|
+
|
|
12
|
+
from fastapi import FastAPI
|
|
13
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
14
|
+
|
|
15
|
+
from .store import InMemoryJobStore, JobStore
|
|
16
|
+
from .executor import JobExecutor
|
|
17
|
+
from .router import create_router
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
# Global instances (for single-process deployment)
|
|
22
|
+
_store: Optional[JobStore] = None
|
|
23
|
+
_executor: Optional[JobExecutor] = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_store() -> JobStore:
|
|
27
|
+
"""Get or create the job store."""
|
|
28
|
+
global _store
|
|
29
|
+
if _store is None:
|
|
30
|
+
_store = InMemoryJobStore(max_jobs=1000)
|
|
31
|
+
return _store
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_executor() -> JobExecutor:
|
|
35
|
+
"""Get or create the job executor."""
|
|
36
|
+
global _executor
|
|
37
|
+
if _executor is None:
|
|
38
|
+
_executor = JobExecutor(
|
|
39
|
+
store=get_store(),
|
|
40
|
+
max_concurrent=int(os.environ.get("PRAISONAI_MAX_CONCURRENT_JOBS", "10")),
|
|
41
|
+
default_timeout=int(os.environ.get("PRAISONAI_JOB_TIMEOUT", "3600"))
|
|
42
|
+
)
|
|
43
|
+
return _executor
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@asynccontextmanager
|
|
47
|
+
async def lifespan(app: FastAPI):
|
|
48
|
+
"""Application lifespan manager."""
|
|
49
|
+
executor = get_executor()
|
|
50
|
+
await executor.start()
|
|
51
|
+
logger.info("Jobs API server started")
|
|
52
|
+
|
|
53
|
+
yield
|
|
54
|
+
|
|
55
|
+
await executor.stop()
|
|
56
|
+
logger.info("Jobs API server stopped")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def create_app(
|
|
60
|
+
store: Optional[JobStore] = None,
|
|
61
|
+
executor: Optional[JobExecutor] = None,
|
|
62
|
+
cors_origins: Optional[list] = None
|
|
63
|
+
) -> FastAPI:
|
|
64
|
+
"""
|
|
65
|
+
Create the FastAPI application.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
store: Optional custom job store
|
|
69
|
+
executor: Optional custom executor
|
|
70
|
+
cors_origins: Optional list of allowed CORS origins
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
FastAPI application
|
|
74
|
+
"""
|
|
75
|
+
global _store, _executor
|
|
76
|
+
|
|
77
|
+
if store:
|
|
78
|
+
_store = store
|
|
79
|
+
if executor:
|
|
80
|
+
_executor = executor
|
|
81
|
+
|
|
82
|
+
app = FastAPI(
|
|
83
|
+
title="PraisonAI Jobs API",
|
|
84
|
+
description="Async Jobs API for long-running agent tasks",
|
|
85
|
+
version="1.0.0",
|
|
86
|
+
lifespan=lifespan
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Add CORS middleware
|
|
90
|
+
origins = cors_origins or ["*"]
|
|
91
|
+
app.add_middleware(
|
|
92
|
+
CORSMiddleware,
|
|
93
|
+
allow_origins=origins,
|
|
94
|
+
allow_credentials=True,
|
|
95
|
+
allow_methods=["*"],
|
|
96
|
+
allow_headers=["*"],
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Add jobs router
|
|
100
|
+
jobs_router = create_router(get_store(), get_executor())
|
|
101
|
+
app.include_router(jobs_router)
|
|
102
|
+
|
|
103
|
+
# Health check endpoint
|
|
104
|
+
@app.get("/health")
|
|
105
|
+
async def health_check():
|
|
106
|
+
"""Health check endpoint."""
|
|
107
|
+
return {
|
|
108
|
+
"status": "healthy",
|
|
109
|
+
"store": get_store().__class__.__name__,
|
|
110
|
+
"executor_stats": get_executor().get_stats()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# Stats endpoint
|
|
114
|
+
@app.get("/stats")
|
|
115
|
+
async def get_stats():
|
|
116
|
+
"""Get server statistics."""
|
|
117
|
+
store = get_store()
|
|
118
|
+
executor = get_executor()
|
|
119
|
+
|
|
120
|
+
stats = {
|
|
121
|
+
"executor": executor.get_stats()
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if hasattr(store, "get_stats"):
|
|
125
|
+
stats["store"] = store.get_stats()
|
|
126
|
+
|
|
127
|
+
return stats
|
|
128
|
+
|
|
129
|
+
return app
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def start_server(
|
|
133
|
+
host: str = "127.0.0.1",
|
|
134
|
+
port: int = 8005,
|
|
135
|
+
reload: bool = False,
|
|
136
|
+
workers: int = 1,
|
|
137
|
+
log_level: str = "info"
|
|
138
|
+
):
|
|
139
|
+
"""
|
|
140
|
+
Start the jobs API server.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
host: Host to bind to
|
|
144
|
+
port: Port to bind to
|
|
145
|
+
reload: Enable auto-reload for development
|
|
146
|
+
workers: Number of worker processes
|
|
147
|
+
log_level: Logging level
|
|
148
|
+
"""
|
|
149
|
+
try:
|
|
150
|
+
import uvicorn
|
|
151
|
+
except ImportError:
|
|
152
|
+
raise RuntimeError("uvicorn is required. Install with: pip install uvicorn")
|
|
153
|
+
|
|
154
|
+
logger.info(f"Starting PraisonAI Jobs API on {host}:{port}")
|
|
155
|
+
|
|
156
|
+
uvicorn.run(
|
|
157
|
+
"praisonai.jobs.server:create_app",
|
|
158
|
+
host=host,
|
|
159
|
+
port=port,
|
|
160
|
+
reload=reload,
|
|
161
|
+
workers=workers,
|
|
162
|
+
log_level=log_level,
|
|
163
|
+
factory=True
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# For direct module execution
|
|
168
|
+
if __name__ == "__main__":
|
|
169
|
+
import argparse
|
|
170
|
+
|
|
171
|
+
parser = argparse.ArgumentParser(description="PraisonAI Jobs API Server")
|
|
172
|
+
parser.add_argument("--host", default="127.0.0.1", help="Host to bind to")
|
|
173
|
+
parser.add_argument("--port", type=int, default=8005, help="Port to bind to")
|
|
174
|
+
parser.add_argument("--reload", action="store_true", help="Enable auto-reload")
|
|
175
|
+
parser.add_argument("--workers", type=int, default=1, help="Number of workers")
|
|
176
|
+
parser.add_argument("--log-level", default="info", help="Log level")
|
|
177
|
+
|
|
178
|
+
args = parser.parse_args()
|
|
179
|
+
|
|
180
|
+
start_server(
|
|
181
|
+
host=args.host,
|
|
182
|
+
port=args.port,
|
|
183
|
+
reload=args.reload,
|
|
184
|
+
workers=args.workers,
|
|
185
|
+
log_level=args.log_level
|
|
186
|
+
)
|
praisonai/jobs/store.py
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Job Store for PraisonAI Async Jobs API.
|
|
3
|
+
|
|
4
|
+
Provides storage backends for job state persistence.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
import logging
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
from typing import Optional, List, Dict, Any
|
|
11
|
+
from datetime import datetime, timedelta
|
|
12
|
+
|
|
13
|
+
from .models import Job, JobStatus
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class JobStore(ABC):
|
|
19
|
+
"""Abstract base class for job storage backends."""
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
async def save(self, job: Job) -> None:
|
|
23
|
+
"""Save or update a job."""
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
async def get(self, job_id: str) -> Optional[Job]:
|
|
28
|
+
"""Get a job by ID."""
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
async def get_by_idempotency_key(self, key: str) -> Optional[Job]:
|
|
33
|
+
"""Get a job by idempotency key."""
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
async def list_jobs(
|
|
38
|
+
self,
|
|
39
|
+
status: Optional[JobStatus] = None,
|
|
40
|
+
session_id: Optional[str] = None,
|
|
41
|
+
limit: int = 20,
|
|
42
|
+
offset: int = 0
|
|
43
|
+
) -> List[Job]:
|
|
44
|
+
"""List jobs with optional filters."""
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
async def count(
|
|
49
|
+
self,
|
|
50
|
+
status: Optional[JobStatus] = None,
|
|
51
|
+
session_id: Optional[str] = None
|
|
52
|
+
) -> int:
|
|
53
|
+
"""Count jobs matching filters."""
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
async def delete(self, job_id: str) -> bool:
|
|
58
|
+
"""Delete a job by ID."""
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
@abstractmethod
|
|
62
|
+
async def cleanup_old_jobs(self, max_age_seconds: int = 86400) -> int:
|
|
63
|
+
"""Remove jobs older than max_age_seconds. Returns count deleted."""
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class InMemoryJobStore(JobStore):
|
|
68
|
+
"""
|
|
69
|
+
In-memory job store.
|
|
70
|
+
|
|
71
|
+
Suitable for development and single-process deployments.
|
|
72
|
+
Jobs are lost on restart.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def __init__(self, max_jobs: int = 1000):
|
|
76
|
+
self._jobs: Dict[str, Job] = {}
|
|
77
|
+
self._idempotency_keys: Dict[str, str] = {} # key -> job_id
|
|
78
|
+
self._max_jobs = max_jobs
|
|
79
|
+
self._lock = asyncio.Lock()
|
|
80
|
+
|
|
81
|
+
async def save(self, job: Job) -> None:
|
|
82
|
+
"""Save or update a job."""
|
|
83
|
+
async with self._lock:
|
|
84
|
+
self._jobs[job.id] = job
|
|
85
|
+
|
|
86
|
+
# Track idempotency key
|
|
87
|
+
if job.idempotency_key:
|
|
88
|
+
self._idempotency_keys[job.idempotency_key] = job.id
|
|
89
|
+
|
|
90
|
+
# Enforce max jobs limit by removing oldest completed
|
|
91
|
+
if len(self._jobs) > self._max_jobs:
|
|
92
|
+
await self._evict_oldest_completed()
|
|
93
|
+
|
|
94
|
+
async def _evict_oldest_completed(self) -> None:
|
|
95
|
+
"""Remove oldest completed jobs to stay under limit."""
|
|
96
|
+
completed = [
|
|
97
|
+
(job_id, job) for job_id, job in self._jobs.items()
|
|
98
|
+
if job.is_terminal
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
if not completed:
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
# Sort by completed_at, oldest first
|
|
105
|
+
completed.sort(key=lambda x: x[1].completed_at or datetime.min)
|
|
106
|
+
|
|
107
|
+
# Remove oldest 10%
|
|
108
|
+
to_remove = max(1, len(completed) // 10)
|
|
109
|
+
for job_id, job in completed[:to_remove]:
|
|
110
|
+
del self._jobs[job_id]
|
|
111
|
+
if job.idempotency_key:
|
|
112
|
+
self._idempotency_keys.pop(job.idempotency_key, None)
|
|
113
|
+
|
|
114
|
+
async def get(self, job_id: str) -> Optional[Job]:
|
|
115
|
+
"""Get a job by ID."""
|
|
116
|
+
return self._jobs.get(job_id)
|
|
117
|
+
|
|
118
|
+
async def get_by_idempotency_key(self, key: str) -> Optional[Job]:
|
|
119
|
+
"""Get a job by idempotency key."""
|
|
120
|
+
job_id = self._idempotency_keys.get(key)
|
|
121
|
+
if job_id:
|
|
122
|
+
return self._jobs.get(job_id)
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
async def list_jobs(
|
|
126
|
+
self,
|
|
127
|
+
status: Optional[JobStatus] = None,
|
|
128
|
+
session_id: Optional[str] = None,
|
|
129
|
+
limit: int = 20,
|
|
130
|
+
offset: int = 0
|
|
131
|
+
) -> List[Job]:
|
|
132
|
+
"""List jobs with optional filters."""
|
|
133
|
+
jobs = list(self._jobs.values())
|
|
134
|
+
|
|
135
|
+
# Apply filters
|
|
136
|
+
if status:
|
|
137
|
+
jobs = [j for j in jobs if j.status == status]
|
|
138
|
+
if session_id:
|
|
139
|
+
jobs = [j for j in jobs if j.session_id == session_id]
|
|
140
|
+
|
|
141
|
+
# Sort by created_at descending (newest first)
|
|
142
|
+
jobs.sort(key=lambda j: j.created_at, reverse=True)
|
|
143
|
+
|
|
144
|
+
# Apply pagination
|
|
145
|
+
return jobs[offset:offset + limit]
|
|
146
|
+
|
|
147
|
+
async def count(
|
|
148
|
+
self,
|
|
149
|
+
status: Optional[JobStatus] = None,
|
|
150
|
+
session_id: Optional[str] = None
|
|
151
|
+
) -> int:
|
|
152
|
+
"""Count jobs matching filters."""
|
|
153
|
+
jobs = list(self._jobs.values())
|
|
154
|
+
|
|
155
|
+
if status:
|
|
156
|
+
jobs = [j for j in jobs if j.status == status]
|
|
157
|
+
if session_id:
|
|
158
|
+
jobs = [j for j in jobs if j.session_id == session_id]
|
|
159
|
+
|
|
160
|
+
return len(jobs)
|
|
161
|
+
|
|
162
|
+
async def delete(self, job_id: str) -> bool:
|
|
163
|
+
"""Delete a job by ID."""
|
|
164
|
+
async with self._lock:
|
|
165
|
+
job = self._jobs.pop(job_id, None)
|
|
166
|
+
if job:
|
|
167
|
+
if job.idempotency_key:
|
|
168
|
+
self._idempotency_keys.pop(job.idempotency_key, None)
|
|
169
|
+
return True
|
|
170
|
+
return False
|
|
171
|
+
|
|
172
|
+
async def cleanup_old_jobs(self, max_age_seconds: int = 86400) -> int:
|
|
173
|
+
"""Remove jobs older than max_age_seconds."""
|
|
174
|
+
async with self._lock:
|
|
175
|
+
cutoff = datetime.utcnow() - timedelta(seconds=max_age_seconds)
|
|
176
|
+
to_remove = []
|
|
177
|
+
|
|
178
|
+
for job_id, job in self._jobs.items():
|
|
179
|
+
if job.is_terminal and job.completed_at and job.completed_at < cutoff:
|
|
180
|
+
to_remove.append(job_id)
|
|
181
|
+
|
|
182
|
+
for job_id in to_remove:
|
|
183
|
+
job = self._jobs.pop(job_id)
|
|
184
|
+
if job.idempotency_key:
|
|
185
|
+
self._idempotency_keys.pop(job.idempotency_key, None)
|
|
186
|
+
|
|
187
|
+
if to_remove:
|
|
188
|
+
logger.info(f"Cleaned up {len(to_remove)} old jobs")
|
|
189
|
+
|
|
190
|
+
return len(to_remove)
|
|
191
|
+
|
|
192
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
193
|
+
"""Get store statistics."""
|
|
194
|
+
status_counts = {}
|
|
195
|
+
for job in self._jobs.values():
|
|
196
|
+
status_counts[job.status.value] = status_counts.get(job.status.value, 0) + 1
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
"total_jobs": len(self._jobs),
|
|
200
|
+
"idempotency_keys": len(self._idempotency_keys),
|
|
201
|
+
"max_jobs": self._max_jobs,
|
|
202
|
+
"status_counts": status_counts
|
|
203
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LLM Module for PraisonAI CLI Wrapper.
|
|
3
|
+
|
|
4
|
+
This module provides LLM provider registry and utilities for the CLI wrapper.
|
|
5
|
+
The core LLM functionality is in praisonaiagents.llm.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Lazy loading for performance
|
|
9
|
+
_lazy_cache = {}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def __getattr__(name):
|
|
13
|
+
"""Lazy load LLM registry classes."""
|
|
14
|
+
if name in _lazy_cache:
|
|
15
|
+
return _lazy_cache[name]
|
|
16
|
+
|
|
17
|
+
if name == "LLMProviderRegistry":
|
|
18
|
+
from .registry import LLMProviderRegistry
|
|
19
|
+
_lazy_cache[name] = LLMProviderRegistry
|
|
20
|
+
return LLMProviderRegistry
|
|
21
|
+
elif name == "get_default_llm_registry":
|
|
22
|
+
from .registry import get_default_llm_registry
|
|
23
|
+
_lazy_cache[name] = get_default_llm_registry
|
|
24
|
+
return get_default_llm_registry
|
|
25
|
+
elif name == "register_llm_provider":
|
|
26
|
+
from .registry import register_llm_provider
|
|
27
|
+
_lazy_cache[name] = register_llm_provider
|
|
28
|
+
return register_llm_provider
|
|
29
|
+
elif name == "unregister_llm_provider":
|
|
30
|
+
from .registry import unregister_llm_provider
|
|
31
|
+
_lazy_cache[name] = unregister_llm_provider
|
|
32
|
+
return unregister_llm_provider
|
|
33
|
+
elif name == "has_llm_provider":
|
|
34
|
+
from .registry import has_llm_provider
|
|
35
|
+
_lazy_cache[name] = has_llm_provider
|
|
36
|
+
return has_llm_provider
|
|
37
|
+
elif name == "list_llm_providers":
|
|
38
|
+
from .registry import list_llm_providers
|
|
39
|
+
_lazy_cache[name] = list_llm_providers
|
|
40
|
+
return list_llm_providers
|
|
41
|
+
elif name == "create_llm_provider":
|
|
42
|
+
from .registry import create_llm_provider
|
|
43
|
+
_lazy_cache[name] = create_llm_provider
|
|
44
|
+
return create_llm_provider
|
|
45
|
+
elif name == "parse_model_string":
|
|
46
|
+
from .registry import parse_model_string
|
|
47
|
+
_lazy_cache[name] = parse_model_string
|
|
48
|
+
return parse_model_string
|
|
49
|
+
elif name == "_reset_default_registry":
|
|
50
|
+
from .registry import _reset_default_registry
|
|
51
|
+
_lazy_cache[name] = _reset_default_registry
|
|
52
|
+
return _reset_default_registry
|
|
53
|
+
|
|
54
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
__all__ = [
|
|
58
|
+
"LLMProviderRegistry",
|
|
59
|
+
"get_default_llm_registry",
|
|
60
|
+
"register_llm_provider",
|
|
61
|
+
"unregister_llm_provider",
|
|
62
|
+
"has_llm_provider",
|
|
63
|
+
"list_llm_providers",
|
|
64
|
+
"create_llm_provider",
|
|
65
|
+
"parse_model_string",
|
|
66
|
+
]
|