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,445 @@
1
+ """
2
+ MCP Elicitation Implementation
3
+
4
+ Implements the Elicitation API per MCP 2025-11-25 specification.
5
+ Elicitation allows servers to request additional information from users.
6
+
7
+ Features:
8
+ - Form mode: Structured data with JSON schema validation
9
+ - URL mode: External URLs for sensitive interactions
10
+ - CLI integration for interactive prompts
11
+ - Non-interactive CI mode support
12
+ """
13
+
14
+ import logging
15
+ from dataclasses import dataclass, field
16
+ from enum import Enum
17
+ from typing import Any, Callable, Dict, List, Optional
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class ElicitationMode(str, Enum):
23
+ """Elicitation modes per MCP 2025-11-25."""
24
+ FORM = "form"
25
+ URL = "url"
26
+
27
+
28
+ class ElicitationAction(str, Enum):
29
+ """Elicitation response actions per MCP 2025-11-25."""
30
+ ACCEPT = "accept" # User accepted and provided data
31
+ DECLINE = "decline" # User explicitly declined
32
+ CANCEL = "cancel" # User cancelled the request
33
+
34
+
35
+ # Backwards compatibility alias
36
+ class ElicitationStatus(str, Enum):
37
+ """Elicitation response status (deprecated, use ElicitationAction)."""
38
+ COMPLETED = "accept" # Maps to accept
39
+ CANCELLED = "cancel" # Maps to cancel
40
+ TIMEOUT = "cancel" # Maps to cancel
41
+ ERROR = "decline" # Maps to decline
42
+
43
+
44
+ @dataclass
45
+ class ElicitationSchema:
46
+ """
47
+ Schema for form-mode elicitation.
48
+
49
+ Supports JSON Schema for validation with extensions for:
50
+ - String, number, boolean, enum types
51
+ - Default values
52
+ - Required fields
53
+ """
54
+ type: str = "object"
55
+ properties: Dict[str, Any] = field(default_factory=dict)
56
+ required: List[str] = field(default_factory=list)
57
+ title: Optional[str] = None
58
+ description: Optional[str] = None
59
+
60
+ def to_dict(self) -> Dict[str, Any]:
61
+ result = {
62
+ "type": self.type,
63
+ "properties": self.properties,
64
+ }
65
+ if self.required:
66
+ result["required"] = self.required
67
+ if self.title:
68
+ result["title"] = self.title
69
+ if self.description:
70
+ result["description"] = self.description
71
+ return result
72
+
73
+
74
+ @dataclass
75
+ class ElicitationRequest:
76
+ """
77
+ MCP Elicitation request per 2025-11-25 specification.
78
+
79
+ Represents a request for user input during server operations.
80
+ Supports form mode (structured data) and URL mode (external URLs).
81
+ """
82
+ message: str
83
+ mode: ElicitationMode = ElicitationMode.FORM
84
+ requested_schema: Optional[ElicitationSchema] = None
85
+ url: Optional[str] = None
86
+ elicitation_id: Optional[str] = None # Required for URL mode
87
+ timeout: Optional[int] = None
88
+ metadata: Dict[str, Any] = field(default_factory=dict)
89
+
90
+ # Backwards compatibility alias
91
+ @property
92
+ def schema(self) -> Optional[ElicitationSchema]:
93
+ return self.requested_schema
94
+
95
+ @property
96
+ def id(self) -> str:
97
+ return self.elicitation_id or ""
98
+
99
+ def to_dict(self) -> Dict[str, Any]:
100
+ """Convert to MCP elicitation/create params format."""
101
+ result = {
102
+ "message": self.message,
103
+ }
104
+
105
+ # Mode is optional for form (defaults to form if omitted)
106
+ if self.mode == ElicitationMode.URL:
107
+ result["mode"] = self.mode.value
108
+
109
+ if self.mode == ElicitationMode.FORM and self.requested_schema:
110
+ result["requestedSchema"] = self.requested_schema.to_dict()
111
+
112
+ if self.mode == ElicitationMode.URL:
113
+ if self.url:
114
+ result["url"] = self.url
115
+ if self.elicitation_id:
116
+ result["elicitationId"] = self.elicitation_id
117
+
118
+ if self.metadata:
119
+ result["_meta"] = self.metadata
120
+
121
+ return result
122
+
123
+
124
+ @dataclass
125
+ class ElicitationResult:
126
+ """
127
+ MCP Elicitation result per 2025-11-25 specification.
128
+
129
+ Contains the user's response to an elicitation request.
130
+ Action can be: accept, decline, or cancel.
131
+ """
132
+ action: ElicitationAction
133
+ content: Optional[Dict[str, Any]] = None # Only when action=accept
134
+ validation_error: Optional[str] = None
135
+
136
+ # Backwards compatibility aliases
137
+ @property
138
+ def status(self) -> ElicitationStatus:
139
+ if self.action == ElicitationAction.ACCEPT:
140
+ return ElicitationStatus.COMPLETED
141
+ elif self.action == ElicitationAction.DECLINE:
142
+ return ElicitationStatus.ERROR
143
+ return ElicitationStatus.CANCELLED
144
+
145
+ @property
146
+ def data(self) -> Optional[Dict[str, Any]]:
147
+ return self.content
148
+
149
+ @property
150
+ def error(self) -> Optional[str]:
151
+ return self.validation_error
152
+
153
+ def to_dict(self) -> Dict[str, Any]:
154
+ """Convert to MCP ElicitResult format."""
155
+ result = {
156
+ "action": self.action.value,
157
+ }
158
+
159
+ if self.action == ElicitationAction.ACCEPT and self.content:
160
+ result["content"] = self.content
161
+
162
+ if self.validation_error:
163
+ result["validationError"] = self.validation_error
164
+
165
+ return result
166
+
167
+ @classmethod
168
+ def accept(cls, content: Dict[str, Any]) -> "ElicitationResult":
169
+ """Create an accept result."""
170
+ return cls(action=ElicitationAction.ACCEPT, content=content)
171
+
172
+ @classmethod
173
+ def decline(cls, error: Optional[str] = None) -> "ElicitationResult":
174
+ """Create a decline result."""
175
+ return cls(action=ElicitationAction.DECLINE, validation_error=error)
176
+
177
+ @classmethod
178
+ def cancel(cls) -> "ElicitationResult":
179
+ """Create a cancel result."""
180
+ return cls(action=ElicitationAction.CANCEL)
181
+
182
+
183
+ class ElicitationHandler:
184
+ """
185
+ Handles elicitation requests.
186
+
187
+ Provides different handlers for:
188
+ - Interactive CLI mode
189
+ - Non-interactive CI mode
190
+ - Custom handlers
191
+ """
192
+
193
+ def __init__(
194
+ self,
195
+ interactive: bool = True,
196
+ default_timeout: int = 300,
197
+ ci_mode: bool = False,
198
+ ci_defaults: Optional[Dict[str, Any]] = None,
199
+ ):
200
+ """
201
+ Initialize elicitation handler.
202
+
203
+ Args:
204
+ interactive: Whether to prompt for user input
205
+ default_timeout: Default timeout in seconds
206
+ ci_mode: CI mode (fail or use defaults)
207
+ ci_defaults: Default values for CI mode
208
+ """
209
+ self.interactive = interactive
210
+ self.default_timeout = default_timeout
211
+ self.ci_mode = ci_mode
212
+ self.ci_defaults = ci_defaults or {}
213
+
214
+ self._pending_requests: Dict[str, ElicitationRequest] = {}
215
+ self._custom_handler: Optional[Callable] = None
216
+
217
+ def set_custom_handler(self, handler: Callable) -> None:
218
+ """Set a custom elicitation handler."""
219
+ self._custom_handler = handler
220
+
221
+ async def elicit(self, request: ElicitationRequest) -> ElicitationResult:
222
+ """
223
+ Process an elicitation request.
224
+
225
+ Args:
226
+ request: Elicitation request
227
+
228
+ Returns:
229
+ Elicitation result
230
+ """
231
+ req_id = request.elicitation_id or request.id
232
+ self._pending_requests[req_id] = request
233
+
234
+ try:
235
+ if self._custom_handler:
236
+ return await self._custom_handler(request)
237
+
238
+ if self.ci_mode:
239
+ return await self._handle_ci_mode(request)
240
+
241
+ if self.interactive:
242
+ return await self._handle_interactive(request)
243
+
244
+ return ElicitationResult.decline("No elicitation handler available")
245
+
246
+ finally:
247
+ if req_id in self._pending_requests:
248
+ del self._pending_requests[req_id]
249
+
250
+ async def _handle_ci_mode(self, request: ElicitationRequest) -> ElicitationResult:
251
+ """Handle elicitation in CI mode."""
252
+ if request.mode == ElicitationMode.URL:
253
+ # URL mode cannot be handled in CI
254
+ return ElicitationResult.decline("URL elicitation not supported in CI mode")
255
+
256
+ # Try to use defaults
257
+ if request.requested_schema:
258
+ data = {}
259
+ for prop_name, prop_schema in request.requested_schema.properties.items():
260
+ if prop_name in self.ci_defaults:
261
+ data[prop_name] = self.ci_defaults[prop_name]
262
+ elif "default" in prop_schema:
263
+ data[prop_name] = prop_schema["default"]
264
+ elif prop_name in request.requested_schema.required:
265
+ return ElicitationResult.decline(
266
+ f"Required field '{prop_name}' has no default in CI mode"
267
+ )
268
+
269
+ return ElicitationResult.accept(data)
270
+
271
+ return ElicitationResult.accept({})
272
+
273
+ async def _handle_interactive(self, request: ElicitationRequest) -> ElicitationResult:
274
+ """Handle elicitation interactively."""
275
+ if request.mode == ElicitationMode.URL:
276
+ return await self._handle_url_elicitation(request)
277
+
278
+ return await self._handle_form_elicitation(request)
279
+
280
+ async def _handle_form_elicitation(self, request: ElicitationRequest) -> ElicitationResult:
281
+ """Handle form-mode elicitation."""
282
+ try:
283
+ print(f"\n[Elicitation] {request.message}")
284
+
285
+ if not request.requested_schema:
286
+ # Simple confirmation
287
+ response = input("Continue? [y/N]: ").strip().lower()
288
+ if response in ("y", "yes"):
289
+ return ElicitationResult.accept({"confirmed": True})
290
+ return ElicitationResult.cancel()
291
+
292
+ # Collect form data
293
+ data = {}
294
+ for prop_name, prop_schema in request.requested_schema.properties.items():
295
+ prop_type = prop_schema.get("type", "string")
296
+ prop_desc = prop_schema.get("description", prop_name)
297
+ default = prop_schema.get("default")
298
+ required = prop_name in request.requested_schema.required
299
+
300
+ prompt = f" {prop_desc}"
301
+ if default is not None:
302
+ prompt += f" [{default}]"
303
+ if required:
304
+ prompt += " (required)"
305
+ prompt += ": "
306
+
307
+ # Handle enum type
308
+ if "enum" in prop_schema:
309
+ options = prop_schema["enum"]
310
+ print(f" Options: {', '.join(str(o) for o in options)}")
311
+
312
+ value = input(prompt).strip()
313
+
314
+ if not value and default is not None:
315
+ value = default
316
+ elif not value and required:
317
+ return ElicitationResult.decline(
318
+ f"Required field '{prop_name}' not provided"
319
+ )
320
+
321
+ # Type conversion
322
+ if value:
323
+ if prop_type == "integer":
324
+ value = int(value)
325
+ elif prop_type == "number":
326
+ value = float(value)
327
+ elif prop_type == "boolean":
328
+ value = value.lower() in ("true", "yes", "1", "y")
329
+
330
+ if value is not None:
331
+ data[prop_name] = value
332
+
333
+ return ElicitationResult.accept(data)
334
+
335
+ except KeyboardInterrupt:
336
+ return ElicitationResult.cancel()
337
+ except Exception as e:
338
+ return ElicitationResult.decline(str(e))
339
+
340
+ async def _handle_url_elicitation(self, request: ElicitationRequest) -> ElicitationResult:
341
+ """Handle URL-mode elicitation."""
342
+ try:
343
+ print(f"\n[Elicitation] {request.message}")
344
+ print(f" Please visit: {request.url}")
345
+
346
+ # Wait for user confirmation
347
+ response = input("Press Enter when complete, or 'c' to cancel: ").strip().lower()
348
+
349
+ if response == "c":
350
+ return ElicitationResult.cancel()
351
+
352
+ return ElicitationResult.accept({"url_visited": True})
353
+
354
+ except KeyboardInterrupt:
355
+ return ElicitationResult.cancel()
356
+ except Exception as e:
357
+ return ElicitationResult.decline(str(e))
358
+
359
+ def cancel(self, request_id: str) -> bool:
360
+ """Cancel a pending elicitation request."""
361
+ if request_id in self._pending_requests:
362
+ del self._pending_requests[request_id]
363
+ return True
364
+ return False
365
+
366
+
367
+ # Global elicitation handler
368
+ _elicitation_handler: Optional[ElicitationHandler] = None
369
+
370
+
371
+ def get_elicitation_handler() -> ElicitationHandler:
372
+ """Get the global elicitation handler."""
373
+ global _elicitation_handler
374
+ if _elicitation_handler is None:
375
+ _elicitation_handler = ElicitationHandler()
376
+ return _elicitation_handler
377
+
378
+
379
+ def set_elicitation_handler(handler: ElicitationHandler) -> None:
380
+ """Set the global elicitation handler."""
381
+ global _elicitation_handler
382
+ _elicitation_handler = handler
383
+
384
+
385
+ def create_form_request(
386
+ message: str,
387
+ properties: Dict[str, Any],
388
+ required: Optional[List[str]] = None,
389
+ title: Optional[str] = None,
390
+ timeout: Optional[int] = None,
391
+ ) -> ElicitationRequest:
392
+ """
393
+ Create a form-mode elicitation request per MCP 2025-11-25.
394
+
395
+ Args:
396
+ message: Message to display to user
397
+ properties: JSON Schema properties (requestedSchema)
398
+ required: Required field names
399
+ title: Form title
400
+ timeout: Request timeout
401
+
402
+ Returns:
403
+ ElicitationRequest
404
+ """
405
+ schema = ElicitationSchema(
406
+ properties=properties,
407
+ required=required or [],
408
+ title=title,
409
+ )
410
+
411
+ return ElicitationRequest(
412
+ message=message,
413
+ mode=ElicitationMode.FORM,
414
+ requested_schema=schema,
415
+ timeout=timeout,
416
+ )
417
+
418
+
419
+ def create_url_request(
420
+ message: str,
421
+ url: str,
422
+ elicitation_id: Optional[str] = None,
423
+ timeout: Optional[int] = None,
424
+ ) -> ElicitationRequest:
425
+ """
426
+ Create a URL-mode elicitation request per MCP 2025-11-25.
427
+
428
+ Args:
429
+ message: Message to display to user
430
+ url: URL to visit
431
+ elicitation_id: Unique ID for the elicitation (auto-generated if not provided)
432
+ timeout: Request timeout
433
+
434
+ Returns:
435
+ ElicitationRequest
436
+ """
437
+ import uuid
438
+
439
+ return ElicitationRequest(
440
+ message=message,
441
+ mode=ElicitationMode.URL,
442
+ url=url,
443
+ elicitation_id=elicitation_id or f"elicit-{uuid.uuid4().hex[:12]}",
444
+ timeout=timeout,
445
+ )