PraisonAI 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- praisonai/__init__.py +54 -0
- praisonai/__main__.py +15 -0
- praisonai/acp/__init__.py +54 -0
- praisonai/acp/config.py +159 -0
- praisonai/acp/server.py +587 -0
- praisonai/acp/session.py +219 -0
- praisonai/adapters/__init__.py +50 -0
- praisonai/adapters/readers.py +395 -0
- praisonai/adapters/rerankers.py +315 -0
- praisonai/adapters/retrievers.py +394 -0
- praisonai/adapters/vector_stores.py +409 -0
- praisonai/agent_scheduler.py +337 -0
- praisonai/agents_generator.py +903 -0
- praisonai/api/call.py +292 -0
- praisonai/auto.py +1197 -0
- praisonai/capabilities/__init__.py +275 -0
- praisonai/capabilities/a2a.py +140 -0
- praisonai/capabilities/assistants.py +283 -0
- praisonai/capabilities/audio.py +320 -0
- praisonai/capabilities/batches.py +469 -0
- praisonai/capabilities/completions.py +336 -0
- praisonai/capabilities/container_files.py +155 -0
- praisonai/capabilities/containers.py +93 -0
- praisonai/capabilities/embeddings.py +158 -0
- praisonai/capabilities/files.py +467 -0
- praisonai/capabilities/fine_tuning.py +293 -0
- praisonai/capabilities/guardrails.py +182 -0
- praisonai/capabilities/images.py +330 -0
- praisonai/capabilities/mcp.py +190 -0
- praisonai/capabilities/messages.py +270 -0
- praisonai/capabilities/moderations.py +154 -0
- praisonai/capabilities/ocr.py +217 -0
- praisonai/capabilities/passthrough.py +204 -0
- praisonai/capabilities/rag.py +207 -0
- praisonai/capabilities/realtime.py +160 -0
- praisonai/capabilities/rerank.py +165 -0
- praisonai/capabilities/responses.py +266 -0
- praisonai/capabilities/search.py +109 -0
- praisonai/capabilities/skills.py +133 -0
- praisonai/capabilities/vector_store_files.py +334 -0
- praisonai/capabilities/vector_stores.py +304 -0
- praisonai/capabilities/videos.py +141 -0
- praisonai/chainlit_ui.py +304 -0
- praisonai/chat/__init__.py +106 -0
- praisonai/chat/app.py +125 -0
- praisonai/cli/__init__.py +26 -0
- praisonai/cli/app.py +213 -0
- praisonai/cli/commands/__init__.py +75 -0
- praisonai/cli/commands/acp.py +70 -0
- praisonai/cli/commands/completion.py +333 -0
- praisonai/cli/commands/config.py +166 -0
- praisonai/cli/commands/debug.py +142 -0
- praisonai/cli/commands/diag.py +55 -0
- praisonai/cli/commands/doctor.py +166 -0
- praisonai/cli/commands/environment.py +179 -0
- praisonai/cli/commands/lsp.py +112 -0
- praisonai/cli/commands/mcp.py +210 -0
- praisonai/cli/commands/profile.py +457 -0
- praisonai/cli/commands/run.py +228 -0
- praisonai/cli/commands/schedule.py +150 -0
- praisonai/cli/commands/serve.py +97 -0
- praisonai/cli/commands/session.py +212 -0
- praisonai/cli/commands/traces.py +145 -0
- praisonai/cli/commands/version.py +101 -0
- praisonai/cli/configuration/__init__.py +18 -0
- praisonai/cli/configuration/loader.py +353 -0
- praisonai/cli/configuration/paths.py +114 -0
- praisonai/cli/configuration/schema.py +164 -0
- praisonai/cli/features/__init__.py +268 -0
- praisonai/cli/features/acp.py +236 -0
- praisonai/cli/features/action_orchestrator.py +546 -0
- praisonai/cli/features/agent_scheduler.py +773 -0
- praisonai/cli/features/agent_tools.py +474 -0
- praisonai/cli/features/agents.py +375 -0
- praisonai/cli/features/at_mentions.py +471 -0
- praisonai/cli/features/auto_memory.py +182 -0
- praisonai/cli/features/autonomy_mode.py +490 -0
- praisonai/cli/features/background.py +356 -0
- praisonai/cli/features/base.py +168 -0
- praisonai/cli/features/capabilities.py +1326 -0
- praisonai/cli/features/checkpoints.py +338 -0
- praisonai/cli/features/code_intelligence.py +652 -0
- praisonai/cli/features/compaction.py +294 -0
- praisonai/cli/features/compare.py +534 -0
- praisonai/cli/features/cost_tracker.py +514 -0
- praisonai/cli/features/debug.py +810 -0
- praisonai/cli/features/deploy.py +517 -0
- praisonai/cli/features/diag.py +289 -0
- praisonai/cli/features/doctor/__init__.py +63 -0
- praisonai/cli/features/doctor/checks/__init__.py +24 -0
- praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
- praisonai/cli/features/doctor/checks/config_checks.py +366 -0
- praisonai/cli/features/doctor/checks/db_checks.py +366 -0
- praisonai/cli/features/doctor/checks/env_checks.py +543 -0
- praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
- praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
- praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
- praisonai/cli/features/doctor/checks/network_checks.py +251 -0
- praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
- praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
- praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
- praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
- praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
- praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
- praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
- praisonai/cli/features/doctor/engine.py +266 -0
- praisonai/cli/features/doctor/formatters.py +310 -0
- praisonai/cli/features/doctor/handler.py +397 -0
- praisonai/cli/features/doctor/models.py +264 -0
- praisonai/cli/features/doctor/registry.py +239 -0
- praisonai/cli/features/endpoints.py +1019 -0
- praisonai/cli/features/eval.py +560 -0
- praisonai/cli/features/external_agents.py +231 -0
- praisonai/cli/features/fast_context.py +410 -0
- praisonai/cli/features/flow_display.py +566 -0
- praisonai/cli/features/git_integration.py +651 -0
- praisonai/cli/features/guardrail.py +171 -0
- praisonai/cli/features/handoff.py +185 -0
- praisonai/cli/features/hooks.py +583 -0
- praisonai/cli/features/image.py +384 -0
- praisonai/cli/features/interactive_runtime.py +585 -0
- praisonai/cli/features/interactive_tools.py +380 -0
- praisonai/cli/features/interactive_tui.py +603 -0
- praisonai/cli/features/jobs.py +632 -0
- praisonai/cli/features/knowledge.py +531 -0
- praisonai/cli/features/lite.py +244 -0
- praisonai/cli/features/lsp_cli.py +225 -0
- praisonai/cli/features/mcp.py +169 -0
- praisonai/cli/features/message_queue.py +587 -0
- praisonai/cli/features/metrics.py +211 -0
- praisonai/cli/features/n8n.py +673 -0
- praisonai/cli/features/observability.py +293 -0
- praisonai/cli/features/ollama.py +361 -0
- praisonai/cli/features/output_style.py +273 -0
- praisonai/cli/features/package.py +631 -0
- praisonai/cli/features/performance.py +308 -0
- praisonai/cli/features/persistence.py +636 -0
- praisonai/cli/features/profile.py +226 -0
- praisonai/cli/features/profiler/__init__.py +81 -0
- praisonai/cli/features/profiler/core.py +558 -0
- praisonai/cli/features/profiler/optimizations.py +652 -0
- praisonai/cli/features/profiler/suite.py +386 -0
- praisonai/cli/features/profiling.py +350 -0
- praisonai/cli/features/queue/__init__.py +73 -0
- praisonai/cli/features/queue/manager.py +395 -0
- praisonai/cli/features/queue/models.py +286 -0
- praisonai/cli/features/queue/persistence.py +564 -0
- praisonai/cli/features/queue/scheduler.py +484 -0
- praisonai/cli/features/queue/worker.py +372 -0
- praisonai/cli/features/recipe.py +1723 -0
- praisonai/cli/features/recipes.py +449 -0
- praisonai/cli/features/registry.py +229 -0
- praisonai/cli/features/repo_map.py +860 -0
- praisonai/cli/features/router.py +466 -0
- praisonai/cli/features/sandbox_executor.py +515 -0
- praisonai/cli/features/serve.py +829 -0
- praisonai/cli/features/session.py +222 -0
- praisonai/cli/features/skills.py +856 -0
- praisonai/cli/features/slash_commands.py +650 -0
- praisonai/cli/features/telemetry.py +179 -0
- praisonai/cli/features/templates.py +1384 -0
- praisonai/cli/features/thinking.py +305 -0
- praisonai/cli/features/todo.py +334 -0
- praisonai/cli/features/tools.py +680 -0
- praisonai/cli/features/tui/__init__.py +83 -0
- praisonai/cli/features/tui/app.py +580 -0
- praisonai/cli/features/tui/cli.py +566 -0
- praisonai/cli/features/tui/debug.py +511 -0
- praisonai/cli/features/tui/events.py +99 -0
- praisonai/cli/features/tui/mock_provider.py +328 -0
- praisonai/cli/features/tui/orchestrator.py +652 -0
- praisonai/cli/features/tui/screens/__init__.py +50 -0
- praisonai/cli/features/tui/screens/main.py +245 -0
- praisonai/cli/features/tui/screens/queue.py +174 -0
- praisonai/cli/features/tui/screens/session.py +124 -0
- praisonai/cli/features/tui/screens/settings.py +148 -0
- praisonai/cli/features/tui/widgets/__init__.py +56 -0
- praisonai/cli/features/tui/widgets/chat.py +261 -0
- praisonai/cli/features/tui/widgets/composer.py +224 -0
- praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
- praisonai/cli/features/tui/widgets/status.py +167 -0
- praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
- praisonai/cli/features/workflow.py +720 -0
- praisonai/cli/legacy.py +236 -0
- praisonai/cli/main.py +5559 -0
- praisonai/cli/schedule_cli.py +54 -0
- praisonai/cli/state/__init__.py +31 -0
- praisonai/cli/state/identifiers.py +161 -0
- praisonai/cli/state/sessions.py +313 -0
- praisonai/code/__init__.py +93 -0
- praisonai/code/agent_tools.py +344 -0
- praisonai/code/diff/__init__.py +21 -0
- praisonai/code/diff/diff_strategy.py +432 -0
- praisonai/code/tools/__init__.py +27 -0
- praisonai/code/tools/apply_diff.py +221 -0
- praisonai/code/tools/execute_command.py +275 -0
- praisonai/code/tools/list_files.py +274 -0
- praisonai/code/tools/read_file.py +206 -0
- praisonai/code/tools/search_replace.py +248 -0
- praisonai/code/tools/write_file.py +217 -0
- praisonai/code/utils/__init__.py +46 -0
- praisonai/code/utils/file_utils.py +307 -0
- praisonai/code/utils/ignore_utils.py +308 -0
- praisonai/code/utils/text_utils.py +276 -0
- praisonai/db/__init__.py +64 -0
- praisonai/db/adapter.py +531 -0
- praisonai/deploy/__init__.py +62 -0
- praisonai/deploy/api.py +231 -0
- praisonai/deploy/docker.py +454 -0
- praisonai/deploy/doctor.py +367 -0
- praisonai/deploy/main.py +327 -0
- praisonai/deploy/models.py +179 -0
- praisonai/deploy/providers/__init__.py +33 -0
- praisonai/deploy/providers/aws.py +331 -0
- praisonai/deploy/providers/azure.py +358 -0
- praisonai/deploy/providers/base.py +101 -0
- praisonai/deploy/providers/gcp.py +314 -0
- praisonai/deploy/schema.py +208 -0
- praisonai/deploy.py +185 -0
- praisonai/endpoints/__init__.py +53 -0
- praisonai/endpoints/a2u_server.py +410 -0
- praisonai/endpoints/discovery.py +165 -0
- praisonai/endpoints/providers/__init__.py +28 -0
- praisonai/endpoints/providers/a2a.py +253 -0
- praisonai/endpoints/providers/a2u.py +208 -0
- praisonai/endpoints/providers/agents_api.py +171 -0
- praisonai/endpoints/providers/base.py +231 -0
- praisonai/endpoints/providers/mcp.py +263 -0
- praisonai/endpoints/providers/recipe.py +206 -0
- praisonai/endpoints/providers/tools_mcp.py +150 -0
- praisonai/endpoints/registry.py +131 -0
- praisonai/endpoints/server.py +161 -0
- praisonai/inbuilt_tools/__init__.py +24 -0
- praisonai/inbuilt_tools/autogen_tools.py +117 -0
- praisonai/inc/__init__.py +2 -0
- praisonai/inc/config.py +96 -0
- praisonai/inc/models.py +155 -0
- praisonai/integrations/__init__.py +56 -0
- praisonai/integrations/base.py +303 -0
- praisonai/integrations/claude_code.py +270 -0
- praisonai/integrations/codex_cli.py +255 -0
- praisonai/integrations/cursor_cli.py +195 -0
- praisonai/integrations/gemini_cli.py +222 -0
- praisonai/jobs/__init__.py +67 -0
- praisonai/jobs/executor.py +425 -0
- praisonai/jobs/models.py +230 -0
- praisonai/jobs/router.py +314 -0
- praisonai/jobs/server.py +186 -0
- praisonai/jobs/store.py +203 -0
- praisonai/llm/__init__.py +66 -0
- praisonai/llm/registry.py +382 -0
- praisonai/mcp_server/__init__.py +152 -0
- praisonai/mcp_server/adapters/__init__.py +74 -0
- praisonai/mcp_server/adapters/agents.py +128 -0
- praisonai/mcp_server/adapters/capabilities.py +168 -0
- praisonai/mcp_server/adapters/cli_tools.py +568 -0
- praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
- praisonai/mcp_server/adapters/knowledge.py +93 -0
- praisonai/mcp_server/adapters/memory.py +104 -0
- praisonai/mcp_server/adapters/prompts.py +306 -0
- praisonai/mcp_server/adapters/resources.py +124 -0
- praisonai/mcp_server/adapters/tools_bridge.py +280 -0
- praisonai/mcp_server/auth/__init__.py +48 -0
- praisonai/mcp_server/auth/api_key.py +291 -0
- praisonai/mcp_server/auth/oauth.py +460 -0
- praisonai/mcp_server/auth/oidc.py +289 -0
- praisonai/mcp_server/auth/scopes.py +260 -0
- praisonai/mcp_server/cli.py +852 -0
- praisonai/mcp_server/elicitation.py +445 -0
- praisonai/mcp_server/icons.py +302 -0
- praisonai/mcp_server/recipe_adapter.py +573 -0
- praisonai/mcp_server/recipe_cli.py +824 -0
- praisonai/mcp_server/registry.py +703 -0
- praisonai/mcp_server/sampling.py +422 -0
- praisonai/mcp_server/server.py +490 -0
- praisonai/mcp_server/tasks.py +443 -0
- praisonai/mcp_server/transports/__init__.py +18 -0
- praisonai/mcp_server/transports/http_stream.py +376 -0
- praisonai/mcp_server/transports/stdio.py +132 -0
- praisonai/persistence/__init__.py +84 -0
- praisonai/persistence/config.py +238 -0
- praisonai/persistence/conversation/__init__.py +25 -0
- praisonai/persistence/conversation/async_mysql.py +427 -0
- praisonai/persistence/conversation/async_postgres.py +410 -0
- praisonai/persistence/conversation/async_sqlite.py +371 -0
- praisonai/persistence/conversation/base.py +151 -0
- praisonai/persistence/conversation/json_store.py +250 -0
- praisonai/persistence/conversation/mysql.py +387 -0
- praisonai/persistence/conversation/postgres.py +401 -0
- praisonai/persistence/conversation/singlestore.py +240 -0
- praisonai/persistence/conversation/sqlite.py +341 -0
- praisonai/persistence/conversation/supabase.py +203 -0
- praisonai/persistence/conversation/surrealdb.py +287 -0
- praisonai/persistence/factory.py +301 -0
- praisonai/persistence/hooks/__init__.py +18 -0
- praisonai/persistence/hooks/agent_hooks.py +297 -0
- praisonai/persistence/knowledge/__init__.py +26 -0
- praisonai/persistence/knowledge/base.py +144 -0
- praisonai/persistence/knowledge/cassandra.py +232 -0
- praisonai/persistence/knowledge/chroma.py +295 -0
- praisonai/persistence/knowledge/clickhouse.py +242 -0
- praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
- praisonai/persistence/knowledge/couchbase.py +286 -0
- praisonai/persistence/knowledge/lancedb.py +216 -0
- praisonai/persistence/knowledge/langchain_adapter.py +291 -0
- praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
- praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
- praisonai/persistence/knowledge/milvus.py +277 -0
- praisonai/persistence/knowledge/mongodb_vector.py +306 -0
- praisonai/persistence/knowledge/pgvector.py +335 -0
- praisonai/persistence/knowledge/pinecone.py +253 -0
- praisonai/persistence/knowledge/qdrant.py +301 -0
- praisonai/persistence/knowledge/redis_vector.py +291 -0
- praisonai/persistence/knowledge/singlestore_vector.py +299 -0
- praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
- praisonai/persistence/knowledge/upstash_vector.py +266 -0
- praisonai/persistence/knowledge/weaviate.py +223 -0
- praisonai/persistence/migrations/__init__.py +10 -0
- praisonai/persistence/migrations/manager.py +251 -0
- praisonai/persistence/orchestrator.py +406 -0
- praisonai/persistence/state/__init__.py +21 -0
- praisonai/persistence/state/async_mongodb.py +200 -0
- praisonai/persistence/state/base.py +107 -0
- praisonai/persistence/state/dynamodb.py +226 -0
- praisonai/persistence/state/firestore.py +175 -0
- praisonai/persistence/state/gcs.py +155 -0
- praisonai/persistence/state/memory.py +245 -0
- praisonai/persistence/state/mongodb.py +158 -0
- praisonai/persistence/state/redis.py +190 -0
- praisonai/persistence/state/upstash.py +144 -0
- praisonai/persistence/tests/__init__.py +3 -0
- praisonai/persistence/tests/test_all_backends.py +633 -0
- praisonai/profiler.py +1214 -0
- praisonai/recipe/__init__.py +134 -0
- praisonai/recipe/bridge.py +278 -0
- praisonai/recipe/core.py +893 -0
- praisonai/recipe/exceptions.py +54 -0
- praisonai/recipe/history.py +402 -0
- praisonai/recipe/models.py +266 -0
- praisonai/recipe/operations.py +440 -0
- praisonai/recipe/policy.py +422 -0
- praisonai/recipe/registry.py +849 -0
- praisonai/recipe/runtime.py +214 -0
- praisonai/recipe/security.py +711 -0
- praisonai/recipe/serve.py +859 -0
- praisonai/recipe/server.py +613 -0
- praisonai/scheduler/__init__.py +45 -0
- praisonai/scheduler/agent_scheduler.py +552 -0
- praisonai/scheduler/base.py +124 -0
- praisonai/scheduler/daemon_manager.py +225 -0
- praisonai/scheduler/state_manager.py +155 -0
- praisonai/scheduler/yaml_loader.py +193 -0
- praisonai/scheduler.py +194 -0
- praisonai/setup/__init__.py +1 -0
- praisonai/setup/build.py +21 -0
- praisonai/setup/post_install.py +23 -0
- praisonai/setup/setup_conda_env.py +25 -0
- praisonai/setup.py +16 -0
- praisonai/templates/__init__.py +116 -0
- praisonai/templates/cache.py +364 -0
- praisonai/templates/dependency_checker.py +358 -0
- praisonai/templates/discovery.py +391 -0
- praisonai/templates/loader.py +564 -0
- praisonai/templates/registry.py +511 -0
- praisonai/templates/resolver.py +206 -0
- praisonai/templates/security.py +327 -0
- praisonai/templates/tool_override.py +498 -0
- praisonai/templates/tools_doctor.py +256 -0
- praisonai/test.py +105 -0
- praisonai/train.py +562 -0
- praisonai/train_vision.py +306 -0
- praisonai/ui/agents.py +824 -0
- praisonai/ui/callbacks.py +57 -0
- praisonai/ui/chainlit_compat.py +246 -0
- praisonai/ui/chat.py +532 -0
- praisonai/ui/code.py +717 -0
- praisonai/ui/colab.py +474 -0
- praisonai/ui/colab_chainlit.py +81 -0
- praisonai/ui/components/aicoder.py +284 -0
- praisonai/ui/context.py +283 -0
- praisonai/ui/database_config.py +56 -0
- praisonai/ui/db.py +294 -0
- praisonai/ui/realtime.py +488 -0
- praisonai/ui/realtimeclient/__init__.py +756 -0
- praisonai/ui/realtimeclient/tools.py +242 -0
- praisonai/ui/sql_alchemy.py +710 -0
- praisonai/upload_vision.py +140 -0
- praisonai/version.py +1 -0
- praisonai-3.0.0.dist-info/METADATA +3493 -0
- praisonai-3.0.0.dist-info/RECORD +393 -0
- praisonai-3.0.0.dist-info/WHEEL +5 -0
- praisonai-3.0.0.dist-info/entry_points.txt +4 -0
- praisonai-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,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
|
+
)
|