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.
Files changed (393) hide show
  1. praisonai/__init__.py +54 -0
  2. praisonai/__main__.py +15 -0
  3. praisonai/acp/__init__.py +54 -0
  4. praisonai/acp/config.py +159 -0
  5. praisonai/acp/server.py +587 -0
  6. praisonai/acp/session.py +219 -0
  7. praisonai/adapters/__init__.py +50 -0
  8. praisonai/adapters/readers.py +395 -0
  9. praisonai/adapters/rerankers.py +315 -0
  10. praisonai/adapters/retrievers.py +394 -0
  11. praisonai/adapters/vector_stores.py +409 -0
  12. praisonai/agent_scheduler.py +337 -0
  13. praisonai/agents_generator.py +903 -0
  14. praisonai/api/call.py +292 -0
  15. praisonai/auto.py +1197 -0
  16. praisonai/capabilities/__init__.py +275 -0
  17. praisonai/capabilities/a2a.py +140 -0
  18. praisonai/capabilities/assistants.py +283 -0
  19. praisonai/capabilities/audio.py +320 -0
  20. praisonai/capabilities/batches.py +469 -0
  21. praisonai/capabilities/completions.py +336 -0
  22. praisonai/capabilities/container_files.py +155 -0
  23. praisonai/capabilities/containers.py +93 -0
  24. praisonai/capabilities/embeddings.py +158 -0
  25. praisonai/capabilities/files.py +467 -0
  26. praisonai/capabilities/fine_tuning.py +293 -0
  27. praisonai/capabilities/guardrails.py +182 -0
  28. praisonai/capabilities/images.py +330 -0
  29. praisonai/capabilities/mcp.py +190 -0
  30. praisonai/capabilities/messages.py +270 -0
  31. praisonai/capabilities/moderations.py +154 -0
  32. praisonai/capabilities/ocr.py +217 -0
  33. praisonai/capabilities/passthrough.py +204 -0
  34. praisonai/capabilities/rag.py +207 -0
  35. praisonai/capabilities/realtime.py +160 -0
  36. praisonai/capabilities/rerank.py +165 -0
  37. praisonai/capabilities/responses.py +266 -0
  38. praisonai/capabilities/search.py +109 -0
  39. praisonai/capabilities/skills.py +133 -0
  40. praisonai/capabilities/vector_store_files.py +334 -0
  41. praisonai/capabilities/vector_stores.py +304 -0
  42. praisonai/capabilities/videos.py +141 -0
  43. praisonai/chainlit_ui.py +304 -0
  44. praisonai/chat/__init__.py +106 -0
  45. praisonai/chat/app.py +125 -0
  46. praisonai/cli/__init__.py +26 -0
  47. praisonai/cli/app.py +213 -0
  48. praisonai/cli/commands/__init__.py +75 -0
  49. praisonai/cli/commands/acp.py +70 -0
  50. praisonai/cli/commands/completion.py +333 -0
  51. praisonai/cli/commands/config.py +166 -0
  52. praisonai/cli/commands/debug.py +142 -0
  53. praisonai/cli/commands/diag.py +55 -0
  54. praisonai/cli/commands/doctor.py +166 -0
  55. praisonai/cli/commands/environment.py +179 -0
  56. praisonai/cli/commands/lsp.py +112 -0
  57. praisonai/cli/commands/mcp.py +210 -0
  58. praisonai/cli/commands/profile.py +457 -0
  59. praisonai/cli/commands/run.py +228 -0
  60. praisonai/cli/commands/schedule.py +150 -0
  61. praisonai/cli/commands/serve.py +97 -0
  62. praisonai/cli/commands/session.py +212 -0
  63. praisonai/cli/commands/traces.py +145 -0
  64. praisonai/cli/commands/version.py +101 -0
  65. praisonai/cli/configuration/__init__.py +18 -0
  66. praisonai/cli/configuration/loader.py +353 -0
  67. praisonai/cli/configuration/paths.py +114 -0
  68. praisonai/cli/configuration/schema.py +164 -0
  69. praisonai/cli/features/__init__.py +268 -0
  70. praisonai/cli/features/acp.py +236 -0
  71. praisonai/cli/features/action_orchestrator.py +546 -0
  72. praisonai/cli/features/agent_scheduler.py +773 -0
  73. praisonai/cli/features/agent_tools.py +474 -0
  74. praisonai/cli/features/agents.py +375 -0
  75. praisonai/cli/features/at_mentions.py +471 -0
  76. praisonai/cli/features/auto_memory.py +182 -0
  77. praisonai/cli/features/autonomy_mode.py +490 -0
  78. praisonai/cli/features/background.py +356 -0
  79. praisonai/cli/features/base.py +168 -0
  80. praisonai/cli/features/capabilities.py +1326 -0
  81. praisonai/cli/features/checkpoints.py +338 -0
  82. praisonai/cli/features/code_intelligence.py +652 -0
  83. praisonai/cli/features/compaction.py +294 -0
  84. praisonai/cli/features/compare.py +534 -0
  85. praisonai/cli/features/cost_tracker.py +514 -0
  86. praisonai/cli/features/debug.py +810 -0
  87. praisonai/cli/features/deploy.py +517 -0
  88. praisonai/cli/features/diag.py +289 -0
  89. praisonai/cli/features/doctor/__init__.py +63 -0
  90. praisonai/cli/features/doctor/checks/__init__.py +24 -0
  91. praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
  92. praisonai/cli/features/doctor/checks/config_checks.py +366 -0
  93. praisonai/cli/features/doctor/checks/db_checks.py +366 -0
  94. praisonai/cli/features/doctor/checks/env_checks.py +543 -0
  95. praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
  96. praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
  97. praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
  98. praisonai/cli/features/doctor/checks/network_checks.py +251 -0
  99. praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
  100. praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
  101. praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
  102. praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
  103. praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
  104. praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
  105. praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
  106. praisonai/cli/features/doctor/engine.py +266 -0
  107. praisonai/cli/features/doctor/formatters.py +310 -0
  108. praisonai/cli/features/doctor/handler.py +397 -0
  109. praisonai/cli/features/doctor/models.py +264 -0
  110. praisonai/cli/features/doctor/registry.py +239 -0
  111. praisonai/cli/features/endpoints.py +1019 -0
  112. praisonai/cli/features/eval.py +560 -0
  113. praisonai/cli/features/external_agents.py +231 -0
  114. praisonai/cli/features/fast_context.py +410 -0
  115. praisonai/cli/features/flow_display.py +566 -0
  116. praisonai/cli/features/git_integration.py +651 -0
  117. praisonai/cli/features/guardrail.py +171 -0
  118. praisonai/cli/features/handoff.py +185 -0
  119. praisonai/cli/features/hooks.py +583 -0
  120. praisonai/cli/features/image.py +384 -0
  121. praisonai/cli/features/interactive_runtime.py +585 -0
  122. praisonai/cli/features/interactive_tools.py +380 -0
  123. praisonai/cli/features/interactive_tui.py +603 -0
  124. praisonai/cli/features/jobs.py +632 -0
  125. praisonai/cli/features/knowledge.py +531 -0
  126. praisonai/cli/features/lite.py +244 -0
  127. praisonai/cli/features/lsp_cli.py +225 -0
  128. praisonai/cli/features/mcp.py +169 -0
  129. praisonai/cli/features/message_queue.py +587 -0
  130. praisonai/cli/features/metrics.py +211 -0
  131. praisonai/cli/features/n8n.py +673 -0
  132. praisonai/cli/features/observability.py +293 -0
  133. praisonai/cli/features/ollama.py +361 -0
  134. praisonai/cli/features/output_style.py +273 -0
  135. praisonai/cli/features/package.py +631 -0
  136. praisonai/cli/features/performance.py +308 -0
  137. praisonai/cli/features/persistence.py +636 -0
  138. praisonai/cli/features/profile.py +226 -0
  139. praisonai/cli/features/profiler/__init__.py +81 -0
  140. praisonai/cli/features/profiler/core.py +558 -0
  141. praisonai/cli/features/profiler/optimizations.py +652 -0
  142. praisonai/cli/features/profiler/suite.py +386 -0
  143. praisonai/cli/features/profiling.py +350 -0
  144. praisonai/cli/features/queue/__init__.py +73 -0
  145. praisonai/cli/features/queue/manager.py +395 -0
  146. praisonai/cli/features/queue/models.py +286 -0
  147. praisonai/cli/features/queue/persistence.py +564 -0
  148. praisonai/cli/features/queue/scheduler.py +484 -0
  149. praisonai/cli/features/queue/worker.py +372 -0
  150. praisonai/cli/features/recipe.py +1723 -0
  151. praisonai/cli/features/recipes.py +449 -0
  152. praisonai/cli/features/registry.py +229 -0
  153. praisonai/cli/features/repo_map.py +860 -0
  154. praisonai/cli/features/router.py +466 -0
  155. praisonai/cli/features/sandbox_executor.py +515 -0
  156. praisonai/cli/features/serve.py +829 -0
  157. praisonai/cli/features/session.py +222 -0
  158. praisonai/cli/features/skills.py +856 -0
  159. praisonai/cli/features/slash_commands.py +650 -0
  160. praisonai/cli/features/telemetry.py +179 -0
  161. praisonai/cli/features/templates.py +1384 -0
  162. praisonai/cli/features/thinking.py +305 -0
  163. praisonai/cli/features/todo.py +334 -0
  164. praisonai/cli/features/tools.py +680 -0
  165. praisonai/cli/features/tui/__init__.py +83 -0
  166. praisonai/cli/features/tui/app.py +580 -0
  167. praisonai/cli/features/tui/cli.py +566 -0
  168. praisonai/cli/features/tui/debug.py +511 -0
  169. praisonai/cli/features/tui/events.py +99 -0
  170. praisonai/cli/features/tui/mock_provider.py +328 -0
  171. praisonai/cli/features/tui/orchestrator.py +652 -0
  172. praisonai/cli/features/tui/screens/__init__.py +50 -0
  173. praisonai/cli/features/tui/screens/main.py +245 -0
  174. praisonai/cli/features/tui/screens/queue.py +174 -0
  175. praisonai/cli/features/tui/screens/session.py +124 -0
  176. praisonai/cli/features/tui/screens/settings.py +148 -0
  177. praisonai/cli/features/tui/widgets/__init__.py +56 -0
  178. praisonai/cli/features/tui/widgets/chat.py +261 -0
  179. praisonai/cli/features/tui/widgets/composer.py +224 -0
  180. praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
  181. praisonai/cli/features/tui/widgets/status.py +167 -0
  182. praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
  183. praisonai/cli/features/workflow.py +720 -0
  184. praisonai/cli/legacy.py +236 -0
  185. praisonai/cli/main.py +5559 -0
  186. praisonai/cli/schedule_cli.py +54 -0
  187. praisonai/cli/state/__init__.py +31 -0
  188. praisonai/cli/state/identifiers.py +161 -0
  189. praisonai/cli/state/sessions.py +313 -0
  190. praisonai/code/__init__.py +93 -0
  191. praisonai/code/agent_tools.py +344 -0
  192. praisonai/code/diff/__init__.py +21 -0
  193. praisonai/code/diff/diff_strategy.py +432 -0
  194. praisonai/code/tools/__init__.py +27 -0
  195. praisonai/code/tools/apply_diff.py +221 -0
  196. praisonai/code/tools/execute_command.py +275 -0
  197. praisonai/code/tools/list_files.py +274 -0
  198. praisonai/code/tools/read_file.py +206 -0
  199. praisonai/code/tools/search_replace.py +248 -0
  200. praisonai/code/tools/write_file.py +217 -0
  201. praisonai/code/utils/__init__.py +46 -0
  202. praisonai/code/utils/file_utils.py +307 -0
  203. praisonai/code/utils/ignore_utils.py +308 -0
  204. praisonai/code/utils/text_utils.py +276 -0
  205. praisonai/db/__init__.py +64 -0
  206. praisonai/db/adapter.py +531 -0
  207. praisonai/deploy/__init__.py +62 -0
  208. praisonai/deploy/api.py +231 -0
  209. praisonai/deploy/docker.py +454 -0
  210. praisonai/deploy/doctor.py +367 -0
  211. praisonai/deploy/main.py +327 -0
  212. praisonai/deploy/models.py +179 -0
  213. praisonai/deploy/providers/__init__.py +33 -0
  214. praisonai/deploy/providers/aws.py +331 -0
  215. praisonai/deploy/providers/azure.py +358 -0
  216. praisonai/deploy/providers/base.py +101 -0
  217. praisonai/deploy/providers/gcp.py +314 -0
  218. praisonai/deploy/schema.py +208 -0
  219. praisonai/deploy.py +185 -0
  220. praisonai/endpoints/__init__.py +53 -0
  221. praisonai/endpoints/a2u_server.py +410 -0
  222. praisonai/endpoints/discovery.py +165 -0
  223. praisonai/endpoints/providers/__init__.py +28 -0
  224. praisonai/endpoints/providers/a2a.py +253 -0
  225. praisonai/endpoints/providers/a2u.py +208 -0
  226. praisonai/endpoints/providers/agents_api.py +171 -0
  227. praisonai/endpoints/providers/base.py +231 -0
  228. praisonai/endpoints/providers/mcp.py +263 -0
  229. praisonai/endpoints/providers/recipe.py +206 -0
  230. praisonai/endpoints/providers/tools_mcp.py +150 -0
  231. praisonai/endpoints/registry.py +131 -0
  232. praisonai/endpoints/server.py +161 -0
  233. praisonai/inbuilt_tools/__init__.py +24 -0
  234. praisonai/inbuilt_tools/autogen_tools.py +117 -0
  235. praisonai/inc/__init__.py +2 -0
  236. praisonai/inc/config.py +96 -0
  237. praisonai/inc/models.py +155 -0
  238. praisonai/integrations/__init__.py +56 -0
  239. praisonai/integrations/base.py +303 -0
  240. praisonai/integrations/claude_code.py +270 -0
  241. praisonai/integrations/codex_cli.py +255 -0
  242. praisonai/integrations/cursor_cli.py +195 -0
  243. praisonai/integrations/gemini_cli.py +222 -0
  244. praisonai/jobs/__init__.py +67 -0
  245. praisonai/jobs/executor.py +425 -0
  246. praisonai/jobs/models.py +230 -0
  247. praisonai/jobs/router.py +314 -0
  248. praisonai/jobs/server.py +186 -0
  249. praisonai/jobs/store.py +203 -0
  250. praisonai/llm/__init__.py +66 -0
  251. praisonai/llm/registry.py +382 -0
  252. praisonai/mcp_server/__init__.py +152 -0
  253. praisonai/mcp_server/adapters/__init__.py +74 -0
  254. praisonai/mcp_server/adapters/agents.py +128 -0
  255. praisonai/mcp_server/adapters/capabilities.py +168 -0
  256. praisonai/mcp_server/adapters/cli_tools.py +568 -0
  257. praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
  258. praisonai/mcp_server/adapters/knowledge.py +93 -0
  259. praisonai/mcp_server/adapters/memory.py +104 -0
  260. praisonai/mcp_server/adapters/prompts.py +306 -0
  261. praisonai/mcp_server/adapters/resources.py +124 -0
  262. praisonai/mcp_server/adapters/tools_bridge.py +280 -0
  263. praisonai/mcp_server/auth/__init__.py +48 -0
  264. praisonai/mcp_server/auth/api_key.py +291 -0
  265. praisonai/mcp_server/auth/oauth.py +460 -0
  266. praisonai/mcp_server/auth/oidc.py +289 -0
  267. praisonai/mcp_server/auth/scopes.py +260 -0
  268. praisonai/mcp_server/cli.py +852 -0
  269. praisonai/mcp_server/elicitation.py +445 -0
  270. praisonai/mcp_server/icons.py +302 -0
  271. praisonai/mcp_server/recipe_adapter.py +573 -0
  272. praisonai/mcp_server/recipe_cli.py +824 -0
  273. praisonai/mcp_server/registry.py +703 -0
  274. praisonai/mcp_server/sampling.py +422 -0
  275. praisonai/mcp_server/server.py +490 -0
  276. praisonai/mcp_server/tasks.py +443 -0
  277. praisonai/mcp_server/transports/__init__.py +18 -0
  278. praisonai/mcp_server/transports/http_stream.py +376 -0
  279. praisonai/mcp_server/transports/stdio.py +132 -0
  280. praisonai/persistence/__init__.py +84 -0
  281. praisonai/persistence/config.py +238 -0
  282. praisonai/persistence/conversation/__init__.py +25 -0
  283. praisonai/persistence/conversation/async_mysql.py +427 -0
  284. praisonai/persistence/conversation/async_postgres.py +410 -0
  285. praisonai/persistence/conversation/async_sqlite.py +371 -0
  286. praisonai/persistence/conversation/base.py +151 -0
  287. praisonai/persistence/conversation/json_store.py +250 -0
  288. praisonai/persistence/conversation/mysql.py +387 -0
  289. praisonai/persistence/conversation/postgres.py +401 -0
  290. praisonai/persistence/conversation/singlestore.py +240 -0
  291. praisonai/persistence/conversation/sqlite.py +341 -0
  292. praisonai/persistence/conversation/supabase.py +203 -0
  293. praisonai/persistence/conversation/surrealdb.py +287 -0
  294. praisonai/persistence/factory.py +301 -0
  295. praisonai/persistence/hooks/__init__.py +18 -0
  296. praisonai/persistence/hooks/agent_hooks.py +297 -0
  297. praisonai/persistence/knowledge/__init__.py +26 -0
  298. praisonai/persistence/knowledge/base.py +144 -0
  299. praisonai/persistence/knowledge/cassandra.py +232 -0
  300. praisonai/persistence/knowledge/chroma.py +295 -0
  301. praisonai/persistence/knowledge/clickhouse.py +242 -0
  302. praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
  303. praisonai/persistence/knowledge/couchbase.py +286 -0
  304. praisonai/persistence/knowledge/lancedb.py +216 -0
  305. praisonai/persistence/knowledge/langchain_adapter.py +291 -0
  306. praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
  307. praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
  308. praisonai/persistence/knowledge/milvus.py +277 -0
  309. praisonai/persistence/knowledge/mongodb_vector.py +306 -0
  310. praisonai/persistence/knowledge/pgvector.py +335 -0
  311. praisonai/persistence/knowledge/pinecone.py +253 -0
  312. praisonai/persistence/knowledge/qdrant.py +301 -0
  313. praisonai/persistence/knowledge/redis_vector.py +291 -0
  314. praisonai/persistence/knowledge/singlestore_vector.py +299 -0
  315. praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
  316. praisonai/persistence/knowledge/upstash_vector.py +266 -0
  317. praisonai/persistence/knowledge/weaviate.py +223 -0
  318. praisonai/persistence/migrations/__init__.py +10 -0
  319. praisonai/persistence/migrations/manager.py +251 -0
  320. praisonai/persistence/orchestrator.py +406 -0
  321. praisonai/persistence/state/__init__.py +21 -0
  322. praisonai/persistence/state/async_mongodb.py +200 -0
  323. praisonai/persistence/state/base.py +107 -0
  324. praisonai/persistence/state/dynamodb.py +226 -0
  325. praisonai/persistence/state/firestore.py +175 -0
  326. praisonai/persistence/state/gcs.py +155 -0
  327. praisonai/persistence/state/memory.py +245 -0
  328. praisonai/persistence/state/mongodb.py +158 -0
  329. praisonai/persistence/state/redis.py +190 -0
  330. praisonai/persistence/state/upstash.py +144 -0
  331. praisonai/persistence/tests/__init__.py +3 -0
  332. praisonai/persistence/tests/test_all_backends.py +633 -0
  333. praisonai/profiler.py +1214 -0
  334. praisonai/recipe/__init__.py +134 -0
  335. praisonai/recipe/bridge.py +278 -0
  336. praisonai/recipe/core.py +893 -0
  337. praisonai/recipe/exceptions.py +54 -0
  338. praisonai/recipe/history.py +402 -0
  339. praisonai/recipe/models.py +266 -0
  340. praisonai/recipe/operations.py +440 -0
  341. praisonai/recipe/policy.py +422 -0
  342. praisonai/recipe/registry.py +849 -0
  343. praisonai/recipe/runtime.py +214 -0
  344. praisonai/recipe/security.py +711 -0
  345. praisonai/recipe/serve.py +859 -0
  346. praisonai/recipe/server.py +613 -0
  347. praisonai/scheduler/__init__.py +45 -0
  348. praisonai/scheduler/agent_scheduler.py +552 -0
  349. praisonai/scheduler/base.py +124 -0
  350. praisonai/scheduler/daemon_manager.py +225 -0
  351. praisonai/scheduler/state_manager.py +155 -0
  352. praisonai/scheduler/yaml_loader.py +193 -0
  353. praisonai/scheduler.py +194 -0
  354. praisonai/setup/__init__.py +1 -0
  355. praisonai/setup/build.py +21 -0
  356. praisonai/setup/post_install.py +23 -0
  357. praisonai/setup/setup_conda_env.py +25 -0
  358. praisonai/setup.py +16 -0
  359. praisonai/templates/__init__.py +116 -0
  360. praisonai/templates/cache.py +364 -0
  361. praisonai/templates/dependency_checker.py +358 -0
  362. praisonai/templates/discovery.py +391 -0
  363. praisonai/templates/loader.py +564 -0
  364. praisonai/templates/registry.py +511 -0
  365. praisonai/templates/resolver.py +206 -0
  366. praisonai/templates/security.py +327 -0
  367. praisonai/templates/tool_override.py +498 -0
  368. praisonai/templates/tools_doctor.py +256 -0
  369. praisonai/test.py +105 -0
  370. praisonai/train.py +562 -0
  371. praisonai/train_vision.py +306 -0
  372. praisonai/ui/agents.py +824 -0
  373. praisonai/ui/callbacks.py +57 -0
  374. praisonai/ui/chainlit_compat.py +246 -0
  375. praisonai/ui/chat.py +532 -0
  376. praisonai/ui/code.py +717 -0
  377. praisonai/ui/colab.py +474 -0
  378. praisonai/ui/colab_chainlit.py +81 -0
  379. praisonai/ui/components/aicoder.py +284 -0
  380. praisonai/ui/context.py +283 -0
  381. praisonai/ui/database_config.py +56 -0
  382. praisonai/ui/db.py +294 -0
  383. praisonai/ui/realtime.py +488 -0
  384. praisonai/ui/realtimeclient/__init__.py +756 -0
  385. praisonai/ui/realtimeclient/tools.py +242 -0
  386. praisonai/ui/sql_alchemy.py +710 -0
  387. praisonai/upload_vision.py +140 -0
  388. praisonai/version.py +1 -0
  389. praisonai-3.0.0.dist-info/METADATA +3493 -0
  390. praisonai-3.0.0.dist-info/RECORD +393 -0
  391. praisonai-3.0.0.dist-info/WHEEL +5 -0
  392. praisonai-3.0.0.dist-info/entry_points.txt +4 -0
  393. praisonai-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,443 @@
1
+ """
2
+ MCP Tasks API Implementation
3
+
4
+ Implements the Tasks API per MCP 2025-11-25 specification.
5
+ Tasks are durable state machines for tracking long-running operations.
6
+
7
+ Features:
8
+ - Task creation, update, cancellation
9
+ - Polling and deferred result retrieval
10
+ - In-memory storage (default) with optional DB adapters
11
+ - Session-scoped task management
12
+ """
13
+
14
+ import asyncio
15
+ import logging
16
+ import time
17
+ import uuid
18
+ from dataclasses import dataclass, field
19
+ from datetime import datetime, timezone
20
+ from enum import Enum
21
+ from typing import Any, Callable, Dict, List, Optional
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ def _iso_now() -> str:
27
+ """Get current time as ISO 8601 string."""
28
+ return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
29
+
30
+
31
+ class TaskStatus(str, Enum):
32
+ """Task status values per MCP 2025-11-25 specification."""
33
+ PENDING = "pending" # Task created but not yet started
34
+ WORKING = "working" # Task is actively being processed
35
+ INPUT_REQUIRED = "input_required" # Task needs user input (elicitation)
36
+ COMPLETED = "completed" # Task finished successfully
37
+ FAILED = "failed" # Task failed with error
38
+ CANCELLED = "cancelled" # Task was cancelled
39
+
40
+
41
+ # Alias for backwards compatibility
42
+ TaskState = TaskStatus
43
+
44
+
45
+ @dataclass
46
+ class TaskProgress:
47
+ """Task progress information."""
48
+ current: float = 0.0
49
+ total: Optional[float] = None
50
+ message: Optional[str] = None
51
+
52
+ def to_dict(self) -> Dict[str, Any]:
53
+ result = {"current": self.current}
54
+ if self.total is not None:
55
+ result["total"] = self.total
56
+ if self.message:
57
+ result["message"] = self.message
58
+ return result
59
+
60
+
61
+ @dataclass
62
+ class Task:
63
+ """
64
+ MCP Task representation per 2025-11-25 specification.
65
+
66
+ Tasks are durable state machines that carry information about the underlying
67
+ execution state of requests, intended for requestor polling and deferred result retrieval.
68
+ """
69
+ id: str # Internal ID (maps to taskId in protocol)
70
+ method: str
71
+ params: Dict[str, Any] = field(default_factory=dict)
72
+ status: TaskStatus = TaskStatus.PENDING
73
+ status_message: Optional[str] = None
74
+ progress: Optional[TaskProgress] = None
75
+ result: Any = None
76
+ error: Optional[Dict[str, Any]] = None
77
+ created_at: str = field(default_factory=lambda: _iso_now())
78
+ last_updated_at: str = field(default_factory=lambda: _iso_now())
79
+ ttl: Optional[int] = None # TTL in milliseconds
80
+ poll_interval: int = 5000 # Recommended poll interval in milliseconds
81
+ session_id: Optional[str] = None
82
+ metadata: Dict[str, Any] = field(default_factory=dict)
83
+
84
+ # Backwards compatibility alias
85
+ @property
86
+ def state(self) -> TaskStatus:
87
+ return self.status
88
+
89
+ @state.setter
90
+ def state(self, value: TaskStatus) -> None:
91
+ self.status = value
92
+
93
+ @property
94
+ def updated_at(self) -> str:
95
+ return self.last_updated_at
96
+
97
+ def to_dict(self) -> Dict[str, Any]:
98
+ """Convert to MCP task response format per 2025-11-25 spec."""
99
+ result = {
100
+ "taskId": self.id,
101
+ "status": self.status.value,
102
+ "createdAt": self.created_at,
103
+ "lastUpdatedAt": self.last_updated_at,
104
+ }
105
+
106
+ if self.status_message:
107
+ result["statusMessage"] = self.status_message
108
+
109
+ if self.ttl is not None:
110
+ result["ttl"] = self.ttl
111
+
112
+ if self.poll_interval:
113
+ result["pollInterval"] = self.poll_interval
114
+
115
+ if self.progress:
116
+ result["progress"] = self.progress.to_dict()
117
+
118
+ if self.metadata:
119
+ result["_meta"] = self.metadata
120
+
121
+ return result
122
+
123
+ def to_create_result(self) -> Dict[str, Any]:
124
+ """Convert to CreateTaskResult format."""
125
+ return {"task": self.to_dict()}
126
+
127
+ def to_get_result(self) -> Dict[str, Any]:
128
+ """Convert to GetTaskResult format."""
129
+ return self.to_dict()
130
+
131
+
132
+ class TaskStore:
133
+ """
134
+ In-memory task storage.
135
+
136
+ Can be extended with DB adapters for persistence.
137
+ """
138
+
139
+ def __init__(self, max_tasks: int = 1000, ttl: int = 3600):
140
+ """
141
+ Initialize task store.
142
+
143
+ Args:
144
+ max_tasks: Maximum number of tasks to store
145
+ ttl: Task TTL in seconds (for cleanup)
146
+ """
147
+ self._tasks: Dict[str, Task] = {}
148
+ self._max_tasks = max_tasks
149
+ self._ttl = ttl
150
+
151
+ def create(
152
+ self,
153
+ method: str,
154
+ params: Dict[str, Any],
155
+ session_id: Optional[str] = None,
156
+ metadata: Optional[Dict[str, Any]] = None,
157
+ ) -> Task:
158
+ """Create a new task."""
159
+ # Cleanup old tasks if at capacity
160
+ if len(self._tasks) >= self._max_tasks:
161
+ self._cleanup_old_tasks()
162
+
163
+ task_id = f"task-{uuid.uuid4().hex[:16]}"
164
+ task = Task(
165
+ id=task_id,
166
+ method=method,
167
+ params=params,
168
+ session_id=session_id,
169
+ metadata=metadata or {},
170
+ )
171
+ self._tasks[task_id] = task
172
+ logger.debug(f"Created task: {task_id}")
173
+ return task
174
+
175
+ def get(self, task_id: str) -> Optional[Task]:
176
+ """Get a task by ID."""
177
+ return self._tasks.get(task_id)
178
+
179
+ def update(
180
+ self,
181
+ task_id: str,
182
+ status: Optional[TaskStatus] = None,
183
+ status_message: Optional[str] = None,
184
+ progress: Optional[TaskProgress] = None,
185
+ result: Any = None,
186
+ error: Optional[Dict[str, Any]] = None,
187
+ state: Optional[TaskStatus] = None, # Backwards compat alias
188
+ ) -> Optional[Task]:
189
+ """Update a task."""
190
+ task = self._tasks.get(task_id)
191
+ if not task:
192
+ return None
193
+
194
+ task.last_updated_at = _iso_now()
195
+
196
+ # Support both status and state (backwards compat)
197
+ new_status = status or state
198
+ if new_status:
199
+ task.status = new_status
200
+
201
+ if status_message:
202
+ task.status_message = status_message
203
+
204
+ if progress:
205
+ task.progress = progress
206
+
207
+ if result is not None:
208
+ task.result = result
209
+
210
+ if error:
211
+ task.error = error
212
+
213
+ logger.debug(f"Updated task {task_id}: status={task.status}")
214
+ return task
215
+
216
+ def cancel(self, task_id: str) -> Optional[Task]:
217
+ """Cancel a task."""
218
+ task = self._tasks.get(task_id)
219
+ if not task:
220
+ return None
221
+
222
+ if task.status in (TaskStatus.PENDING, TaskStatus.WORKING):
223
+ task.status = TaskStatus.CANCELLED
224
+ task.status_message = "The task was cancelled by request."
225
+ task.last_updated_at = _iso_now()
226
+ logger.debug(f"Cancelled task: {task_id}")
227
+
228
+ return task
229
+
230
+ def delete(self, task_id: str) -> bool:
231
+ """Delete a task."""
232
+ if task_id in self._tasks:
233
+ del self._tasks[task_id]
234
+ return True
235
+ return False
236
+
237
+ def list_tasks(
238
+ self,
239
+ session_id: Optional[str] = None,
240
+ status: Optional[TaskStatus] = None,
241
+ state: Optional[TaskStatus] = None, # Backwards compat alias
242
+ limit: int = 100,
243
+ ) -> List[Task]:
244
+ """List tasks with optional filtering."""
245
+ tasks = list(self._tasks.values())
246
+ filter_status = status or state
247
+
248
+ if session_id:
249
+ tasks = [t for t in tasks if t.session_id == session_id]
250
+
251
+ if filter_status:
252
+ tasks = [t for t in tasks if t.status == filter_status]
253
+
254
+ # Sort by created_at descending
255
+ tasks.sort(key=lambda t: t.created_at, reverse=True)
256
+
257
+ return tasks[:limit]
258
+
259
+ def _cleanup_old_tasks(self) -> None:
260
+ """Remove old completed/failed tasks."""
261
+ now = time.time()
262
+ to_remove = []
263
+
264
+ for task_id, task in self._tasks.items():
265
+ if task.status in (TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.CANCELLED):
266
+ # Parse ISO timestamp to compare
267
+ try:
268
+ from datetime import datetime
269
+ updated = datetime.fromisoformat(task.last_updated_at.replace("Z", "+00:00"))
270
+ age = now - updated.timestamp()
271
+ if age > self._ttl:
272
+ to_remove.append(task_id)
273
+ except (ValueError, AttributeError):
274
+ pass
275
+
276
+ for task_id in to_remove:
277
+ del self._tasks[task_id]
278
+
279
+ logger.debug(f"Cleaned up {len(to_remove)} old tasks")
280
+
281
+
282
+ class TaskManager:
283
+ """
284
+ MCP Task Manager.
285
+
286
+ Handles task lifecycle and execution.
287
+ """
288
+
289
+ def __init__(
290
+ self,
291
+ store: Optional[TaskStore] = None,
292
+ executor: Optional[Callable] = None,
293
+ ):
294
+ """
295
+ Initialize task manager.
296
+
297
+ Args:
298
+ store: Task storage (uses in-memory if None)
299
+ executor: Optional async executor for task execution
300
+ """
301
+ self._store = store or TaskStore()
302
+ self._executor = executor
303
+ self._running_tasks: Dict[str, asyncio.Task] = {}
304
+
305
+ async def create_task(
306
+ self,
307
+ method: str,
308
+ params: Dict[str, Any],
309
+ session_id: Optional[str] = None,
310
+ metadata: Optional[Dict[str, Any]] = None,
311
+ execute: bool = True,
312
+ ) -> Task:
313
+ """
314
+ Create and optionally start executing a task.
315
+
316
+ Args:
317
+ method: Method name for the task
318
+ params: Task parameters
319
+ session_id: Optional session ID
320
+ metadata: Optional metadata
321
+ execute: Whether to start execution immediately
322
+
323
+ Returns:
324
+ Created task
325
+ """
326
+ task = self._store.create(method, params, session_id, metadata)
327
+
328
+ if execute and self._executor:
329
+ # Start async execution
330
+ asyncio_task = asyncio.create_task(
331
+ self._execute_task(task.id)
332
+ )
333
+ self._running_tasks[task.id] = asyncio_task
334
+
335
+ return task
336
+
337
+ async def _execute_task(self, task_id: str) -> None:
338
+ """Execute a task asynchronously."""
339
+ task = self._store.get(task_id)
340
+ if not task:
341
+ return
342
+
343
+ try:
344
+ # Update to working
345
+ self._store.update(
346
+ task_id,
347
+ status=TaskStatus.WORKING,
348
+ status_message="The operation is now in progress.",
349
+ )
350
+
351
+ # Execute
352
+ if self._executor:
353
+ result = await self._executor(task.method, task.params)
354
+ self._store.update(
355
+ task_id,
356
+ status=TaskStatus.COMPLETED,
357
+ status_message="The operation completed successfully.",
358
+ result=result,
359
+ )
360
+ else:
361
+ self._store.update(
362
+ task_id,
363
+ status=TaskStatus.FAILED,
364
+ error={"code": -32603, "message": "No executor configured"},
365
+ )
366
+
367
+ except asyncio.CancelledError:
368
+ self._store.update(
369
+ task_id,
370
+ status=TaskStatus.CANCELLED,
371
+ status_message="The task was cancelled.",
372
+ )
373
+
374
+ except Exception as e:
375
+ logger.exception(f"Task execution failed: {task_id}")
376
+ self._store.update(
377
+ task_id,
378
+ status=TaskStatus.FAILED,
379
+ status_message=f"Task failed: {str(e)}",
380
+ error={"code": -32603, "message": str(e)},
381
+ )
382
+
383
+ finally:
384
+ if task_id in self._running_tasks:
385
+ del self._running_tasks[task_id]
386
+
387
+ def get_task(self, task_id: str) -> Optional[Task]:
388
+ """Get a task by ID."""
389
+ return self._store.get(task_id)
390
+
391
+ def update_progress(
392
+ self,
393
+ task_id: str,
394
+ current: float,
395
+ total: Optional[float] = None,
396
+ message: Optional[str] = None,
397
+ ) -> Optional[Task]:
398
+ """Update task progress."""
399
+ progress = TaskProgress(current=current, total=total, message=message)
400
+ return self._store.update(task_id, progress=progress)
401
+
402
+ async def cancel_task(self, task_id: str) -> Optional[Task]:
403
+ """Cancel a task."""
404
+ # Cancel running asyncio task if exists
405
+ if task_id in self._running_tasks:
406
+ self._running_tasks[task_id].cancel()
407
+ try:
408
+ await self._running_tasks[task_id]
409
+ except asyncio.CancelledError:
410
+ pass
411
+
412
+ return self._store.cancel(task_id)
413
+
414
+ def list_tasks(
415
+ self,
416
+ session_id: Optional[str] = None,
417
+ state: Optional[TaskState] = None,
418
+ limit: int = 100,
419
+ ) -> List[Task]:
420
+ """List tasks."""
421
+ return self._store.list_tasks(session_id, state, limit)
422
+
423
+ def delete_task(self, task_id: str) -> bool:
424
+ """Delete a task."""
425
+ return self._store.delete(task_id)
426
+
427
+
428
+ # Global task manager instance
429
+ _task_manager: Optional[TaskManager] = None
430
+
431
+
432
+ def get_task_manager() -> TaskManager:
433
+ """Get the global task manager."""
434
+ global _task_manager
435
+ if _task_manager is None:
436
+ _task_manager = TaskManager()
437
+ return _task_manager
438
+
439
+
440
+ def set_task_manager(manager: TaskManager) -> None:
441
+ """Set the global task manager."""
442
+ global _task_manager
443
+ _task_manager = manager
@@ -0,0 +1,18 @@
1
+ """
2
+ MCP Transport Implementations
3
+
4
+ Provides STDIO and HTTP Stream transports for the MCP server.
5
+ """
6
+
7
+ __all__ = ["StdioTransport", "HTTPStreamTransport"]
8
+
9
+
10
+ def __getattr__(name):
11
+ """Lazy load transports."""
12
+ if name == "StdioTransport":
13
+ from .stdio import StdioTransport
14
+ return StdioTransport
15
+ elif name == "HTTPStreamTransport":
16
+ from .http_stream import HTTPStreamTransport
17
+ return HTTPStreamTransport
18
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")