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,171 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agents API Provider
|
|
3
|
+
|
|
4
|
+
Provider adapter for agents-as-API endpoints (single agent or multi-agent router).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Dict, List, Optional
|
|
8
|
+
|
|
9
|
+
from .base import BaseProvider, InvokeResult, HealthResult
|
|
10
|
+
from ..discovery import EndpointInfo, ProviderInfo
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AgentsAPIProvider(BaseProvider):
|
|
14
|
+
"""
|
|
15
|
+
Provider adapter for agents-as-API endpoints.
|
|
16
|
+
|
|
17
|
+
Connects to FastAPI-based agent servers launched via Agent.launch() or Agents.launch()
|
|
18
|
+
and provides unified discovery and invocation interface.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
provider_type = "agents-api"
|
|
22
|
+
|
|
23
|
+
def get_provider_info(self) -> ProviderInfo:
|
|
24
|
+
"""Get provider information."""
|
|
25
|
+
return ProviderInfo(
|
|
26
|
+
type=self.provider_type,
|
|
27
|
+
name="Agents API",
|
|
28
|
+
description="Agent HTTP API endpoints",
|
|
29
|
+
capabilities=["list", "describe", "invoke", "health"],
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def list_endpoints(self, tags: Optional[List[str]] = None) -> List[EndpointInfo]:
|
|
33
|
+
"""List available agent endpoints."""
|
|
34
|
+
# Try unified discovery first
|
|
35
|
+
result = self._make_request("GET", "/__praisonai__/discovery")
|
|
36
|
+
|
|
37
|
+
if not result.get("error") and result.get("data"):
|
|
38
|
+
data = result.get("data", {})
|
|
39
|
+
endpoints = []
|
|
40
|
+
for ep in data.get("endpoints", []):
|
|
41
|
+
if ep.get("provider_type") == self.provider_type:
|
|
42
|
+
endpoints.append(EndpointInfo(
|
|
43
|
+
name=ep.get("name", ""),
|
|
44
|
+
description=ep.get("description", ""),
|
|
45
|
+
provider_type=self.provider_type,
|
|
46
|
+
tags=ep.get("tags", []),
|
|
47
|
+
version=ep.get("version", "1.0.0"),
|
|
48
|
+
streaming=ep.get("streaming", ["none"]),
|
|
49
|
+
auth_modes=ep.get("auth_modes", ["none"]),
|
|
50
|
+
))
|
|
51
|
+
return endpoints
|
|
52
|
+
|
|
53
|
+
# Fallback: try root endpoint for endpoint list
|
|
54
|
+
result = self._make_request("GET", "/")
|
|
55
|
+
|
|
56
|
+
if result.get("error"):
|
|
57
|
+
return []
|
|
58
|
+
|
|
59
|
+
data = result.get("data", {})
|
|
60
|
+
endpoint_paths = data.get("endpoints", [])
|
|
61
|
+
|
|
62
|
+
endpoints = []
|
|
63
|
+
for path in endpoint_paths:
|
|
64
|
+
endpoints.append(EndpointInfo(
|
|
65
|
+
name=path.lstrip("/"),
|
|
66
|
+
description=f"Agent endpoint at {path}",
|
|
67
|
+
provider_type=self.provider_type,
|
|
68
|
+
streaming=["none"],
|
|
69
|
+
auth_modes=["none"],
|
|
70
|
+
))
|
|
71
|
+
|
|
72
|
+
return endpoints
|
|
73
|
+
|
|
74
|
+
def describe_endpoint(self, name: str) -> Optional[EndpointInfo]:
|
|
75
|
+
"""Get detailed information about an agent endpoint."""
|
|
76
|
+
# Try unified discovery first
|
|
77
|
+
result = self._make_request("GET", "/__praisonai__/discovery")
|
|
78
|
+
|
|
79
|
+
if not result.get("error") and result.get("data"):
|
|
80
|
+
data = result.get("data", {})
|
|
81
|
+
for ep in data.get("endpoints", []):
|
|
82
|
+
if ep.get("name") == name:
|
|
83
|
+
return EndpointInfo(
|
|
84
|
+
name=ep.get("name", name),
|
|
85
|
+
description=ep.get("description", ""),
|
|
86
|
+
provider_type=self.provider_type,
|
|
87
|
+
tags=ep.get("tags", []),
|
|
88
|
+
version=ep.get("version", "1.0.0"),
|
|
89
|
+
input_schema=ep.get("input_schema"),
|
|
90
|
+
output_schema=ep.get("output_schema"),
|
|
91
|
+
streaming=ep.get("streaming", ["none"]),
|
|
92
|
+
auth_modes=ep.get("auth_modes", ["none"]),
|
|
93
|
+
metadata=ep.get("metadata", {}),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Fallback: return basic info
|
|
97
|
+
return EndpointInfo(
|
|
98
|
+
name=name,
|
|
99
|
+
description=f"Agent endpoint: {name}",
|
|
100
|
+
provider_type=self.provider_type,
|
|
101
|
+
input_schema={"type": "object", "properties": {"query": {"type": "string"}}},
|
|
102
|
+
streaming=["none"],
|
|
103
|
+
auth_modes=["none"],
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def invoke(
|
|
107
|
+
self,
|
|
108
|
+
name: str,
|
|
109
|
+
input_data: Optional[Dict[str, Any]] = None,
|
|
110
|
+
config: Optional[Dict[str, Any]] = None,
|
|
111
|
+
stream: bool = False,
|
|
112
|
+
) -> InvokeResult:
|
|
113
|
+
"""Invoke an agent endpoint."""
|
|
114
|
+
# Normalize endpoint path
|
|
115
|
+
path = name if name.startswith("/") else f"/{name}"
|
|
116
|
+
|
|
117
|
+
# Build request body
|
|
118
|
+
body = input_data or {}
|
|
119
|
+
if "query" not in body and config and "query" in config:
|
|
120
|
+
body["query"] = config["query"]
|
|
121
|
+
|
|
122
|
+
result = self._make_request("POST", path, json_data=body)
|
|
123
|
+
|
|
124
|
+
if result.get("status") == 401:
|
|
125
|
+
return InvokeResult(
|
|
126
|
+
ok=False,
|
|
127
|
+
status="auth_error",
|
|
128
|
+
error="Authentication required",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if result.get("status") == 404:
|
|
132
|
+
return InvokeResult(
|
|
133
|
+
ok=False,
|
|
134
|
+
status="not_found",
|
|
135
|
+
error=f"Endpoint not found: {name}",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
if result.get("error"):
|
|
139
|
+
return InvokeResult(
|
|
140
|
+
ok=False,
|
|
141
|
+
status="error",
|
|
142
|
+
error=result["error"].get("message", str(result["error"])),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
data = result.get("data", {})
|
|
146
|
+
return InvokeResult(
|
|
147
|
+
ok=True,
|
|
148
|
+
status="success",
|
|
149
|
+
data=data.get("response", data),
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def health(self) -> HealthResult:
|
|
153
|
+
"""Check agent server health."""
|
|
154
|
+
result = self._make_request("GET", "/health")
|
|
155
|
+
|
|
156
|
+
if result.get("error"):
|
|
157
|
+
return HealthResult(
|
|
158
|
+
healthy=False,
|
|
159
|
+
status="unhealthy",
|
|
160
|
+
provider_type=self.provider_type,
|
|
161
|
+
metadata={"error": result["error"].get("message", str(result["error"]))},
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
data = result.get("data", {})
|
|
165
|
+
return HealthResult(
|
|
166
|
+
healthy=data.get("status") == "ok",
|
|
167
|
+
status=data.get("status", "unknown"),
|
|
168
|
+
server_name="PraisonAI Agents API",
|
|
169
|
+
provider_type=self.provider_type,
|
|
170
|
+
metadata={"endpoints": data.get("endpoints", [])},
|
|
171
|
+
)
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base Provider Interface
|
|
3
|
+
|
|
4
|
+
Abstract base class for all provider adapters.
|
|
5
|
+
Each provider implements discovery, invocation, and health check methods.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from abc import ABC, abstractmethod
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import Any, Dict, Iterator, List, Optional
|
|
11
|
+
|
|
12
|
+
from ..discovery import EndpointInfo, ProviderInfo
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class InvokeResult:
|
|
17
|
+
"""Result from invoking an endpoint."""
|
|
18
|
+
ok: bool
|
|
19
|
+
status: str = "success"
|
|
20
|
+
data: Optional[Any] = None
|
|
21
|
+
error: Optional[str] = None
|
|
22
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
23
|
+
|
|
24
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
25
|
+
"""Convert to dictionary."""
|
|
26
|
+
return {
|
|
27
|
+
"ok": self.ok,
|
|
28
|
+
"status": self.status,
|
|
29
|
+
"data": self.data,
|
|
30
|
+
"error": self.error,
|
|
31
|
+
"metadata": self.metadata,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class HealthResult:
|
|
37
|
+
"""Result from health check."""
|
|
38
|
+
healthy: bool
|
|
39
|
+
status: str = "healthy"
|
|
40
|
+
server_name: Optional[str] = None
|
|
41
|
+
server_version: Optional[str] = None
|
|
42
|
+
provider_type: Optional[str] = None
|
|
43
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
44
|
+
|
|
45
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
46
|
+
"""Convert to dictionary."""
|
|
47
|
+
return {
|
|
48
|
+
"healthy": self.healthy,
|
|
49
|
+
"status": self.status,
|
|
50
|
+
"server_name": self.server_name,
|
|
51
|
+
"server_version": self.server_version,
|
|
52
|
+
"provider_type": self.provider_type,
|
|
53
|
+
"metadata": self.metadata,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class BaseProvider(ABC):
|
|
58
|
+
"""
|
|
59
|
+
Abstract base class for provider adapters.
|
|
60
|
+
|
|
61
|
+
Each provider type (recipe, agents-api, mcp, etc.) implements this interface
|
|
62
|
+
to provide consistent discovery and invocation behavior.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
# Provider type identifier
|
|
66
|
+
provider_type: str = "base"
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
base_url: str = "http://localhost:8765",
|
|
71
|
+
api_key: Optional[str] = None,
|
|
72
|
+
timeout: float = 30.0,
|
|
73
|
+
):
|
|
74
|
+
"""
|
|
75
|
+
Initialize the provider.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
base_url: Base URL of the server
|
|
79
|
+
api_key: Optional API key for authentication
|
|
80
|
+
timeout: Request timeout in seconds
|
|
81
|
+
"""
|
|
82
|
+
self.base_url = base_url.rstrip("/")
|
|
83
|
+
self.api_key = api_key
|
|
84
|
+
self.timeout = timeout
|
|
85
|
+
|
|
86
|
+
@abstractmethod
|
|
87
|
+
def get_provider_info(self) -> ProviderInfo:
|
|
88
|
+
"""
|
|
89
|
+
Get provider information.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
ProviderInfo with provider details
|
|
93
|
+
"""
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
@abstractmethod
|
|
97
|
+
def list_endpoints(self, tags: Optional[List[str]] = None) -> List[EndpointInfo]:
|
|
98
|
+
"""
|
|
99
|
+
List available endpoints.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
tags: Optional list of tags to filter by
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
List of EndpointInfo objects
|
|
106
|
+
"""
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
@abstractmethod
|
|
110
|
+
def describe_endpoint(self, name: str) -> Optional[EndpointInfo]:
|
|
111
|
+
"""
|
|
112
|
+
Get detailed information about an endpoint.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
name: Endpoint name
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
EndpointInfo or None if not found
|
|
119
|
+
"""
|
|
120
|
+
pass
|
|
121
|
+
|
|
122
|
+
@abstractmethod
|
|
123
|
+
def invoke(
|
|
124
|
+
self,
|
|
125
|
+
name: str,
|
|
126
|
+
input_data: Optional[Dict[str, Any]] = None,
|
|
127
|
+
config: Optional[Dict[str, Any]] = None,
|
|
128
|
+
stream: bool = False,
|
|
129
|
+
) -> InvokeResult:
|
|
130
|
+
"""
|
|
131
|
+
Invoke an endpoint.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
name: Endpoint name
|
|
135
|
+
input_data: Input data for the endpoint
|
|
136
|
+
config: Optional configuration overrides
|
|
137
|
+
stream: Whether to stream the response
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
InvokeResult with response data
|
|
141
|
+
"""
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
def invoke_stream(
|
|
145
|
+
self,
|
|
146
|
+
name: str,
|
|
147
|
+
input_data: Optional[Dict[str, Any]] = None,
|
|
148
|
+
config: Optional[Dict[str, Any]] = None,
|
|
149
|
+
) -> Iterator[Dict[str, Any]]:
|
|
150
|
+
"""
|
|
151
|
+
Invoke an endpoint with streaming.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
name: Endpoint name
|
|
155
|
+
input_data: Input data for the endpoint
|
|
156
|
+
config: Optional configuration overrides
|
|
157
|
+
|
|
158
|
+
Yields:
|
|
159
|
+
Stream events as dictionaries
|
|
160
|
+
"""
|
|
161
|
+
# Default implementation - subclasses can override
|
|
162
|
+
result = self.invoke(name, input_data, config, stream=True)
|
|
163
|
+
if result.ok:
|
|
164
|
+
yield {"event": "complete", "data": result.data}
|
|
165
|
+
else:
|
|
166
|
+
yield {"event": "error", "data": {"error": result.error}}
|
|
167
|
+
|
|
168
|
+
@abstractmethod
|
|
169
|
+
def health(self) -> HealthResult:
|
|
170
|
+
"""
|
|
171
|
+
Check server health.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
HealthResult with health status
|
|
175
|
+
"""
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
def _make_request(
|
|
179
|
+
self,
|
|
180
|
+
method: str,
|
|
181
|
+
path: str,
|
|
182
|
+
json_data: Optional[Dict] = None,
|
|
183
|
+
) -> Dict[str, Any]:
|
|
184
|
+
"""
|
|
185
|
+
Make HTTP request to server.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
method: HTTP method
|
|
189
|
+
path: URL path
|
|
190
|
+
json_data: Optional JSON body
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
Response data dictionary
|
|
194
|
+
"""
|
|
195
|
+
import json
|
|
196
|
+
import urllib.request
|
|
197
|
+
import urllib.error
|
|
198
|
+
|
|
199
|
+
full_url = f"{self.base_url}{path}"
|
|
200
|
+
|
|
201
|
+
headers = {"Content-Type": "application/json"}
|
|
202
|
+
if self.api_key:
|
|
203
|
+
headers["X-API-Key"] = self.api_key
|
|
204
|
+
|
|
205
|
+
data = None
|
|
206
|
+
if json_data:
|
|
207
|
+
data = json.dumps(json_data).encode("utf-8")
|
|
208
|
+
|
|
209
|
+
try:
|
|
210
|
+
req = urllib.request.Request(
|
|
211
|
+
full_url,
|
|
212
|
+
data=data,
|
|
213
|
+
headers=headers,
|
|
214
|
+
method=method,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
with urllib.request.urlopen(req, timeout=self.timeout) as response:
|
|
218
|
+
body = response.read().decode("utf-8")
|
|
219
|
+
return {"status": response.status, "data": json.loads(body) if body else {}}
|
|
220
|
+
|
|
221
|
+
except urllib.error.HTTPError as e:
|
|
222
|
+
body = e.read().decode("utf-8") if e.fp else ""
|
|
223
|
+
try:
|
|
224
|
+
error_data = json.loads(body) if body else {}
|
|
225
|
+
except json.JSONDecodeError:
|
|
226
|
+
error_data = {"message": body}
|
|
227
|
+
return {"status": e.code, "error": error_data}
|
|
228
|
+
except urllib.error.URLError as e:
|
|
229
|
+
return {"status": 0, "error": {"message": f"Connection error: {e.reason}"}}
|
|
230
|
+
except Exception as e:
|
|
231
|
+
return {"status": 0, "error": {"message": str(e)}}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Provider
|
|
3
|
+
|
|
4
|
+
Provider adapter for MCP server endpoints (stdio, http, sse).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Dict, Iterator, List, Optional
|
|
8
|
+
|
|
9
|
+
from .base import BaseProvider, InvokeResult, HealthResult
|
|
10
|
+
from ..discovery import EndpointInfo, ProviderInfo
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MCPProvider(BaseProvider):
|
|
14
|
+
"""
|
|
15
|
+
Provider adapter for MCP server endpoints.
|
|
16
|
+
|
|
17
|
+
Supports multiple MCP transport types:
|
|
18
|
+
- stdio: Standard input/output (requires subprocess)
|
|
19
|
+
- http: HTTP-based MCP server
|
|
20
|
+
- sse: Server-Sent Events MCP gateway
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
provider_type = "mcp"
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
base_url: str = "http://localhost:8765",
|
|
28
|
+
api_key: Optional[str] = None,
|
|
29
|
+
timeout: float = 30.0,
|
|
30
|
+
transport: str = "http",
|
|
31
|
+
command: Optional[str] = None,
|
|
32
|
+
args: Optional[List[str]] = None,
|
|
33
|
+
env: Optional[Dict[str, str]] = None,
|
|
34
|
+
):
|
|
35
|
+
"""
|
|
36
|
+
Initialize MCP provider.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
base_url: Base URL for HTTP/SSE transport
|
|
40
|
+
api_key: Optional API key
|
|
41
|
+
timeout: Request timeout
|
|
42
|
+
transport: Transport type (stdio, http, sse)
|
|
43
|
+
command: Command for stdio transport
|
|
44
|
+
args: Command arguments for stdio transport
|
|
45
|
+
env: Environment variables for stdio transport
|
|
46
|
+
"""
|
|
47
|
+
super().__init__(base_url, api_key, timeout)
|
|
48
|
+
self.transport = transport
|
|
49
|
+
self.command = command
|
|
50
|
+
self.args = args or []
|
|
51
|
+
self.env = env or {}
|
|
52
|
+
|
|
53
|
+
def get_provider_info(self) -> ProviderInfo:
|
|
54
|
+
"""Get provider information."""
|
|
55
|
+
return ProviderInfo(
|
|
56
|
+
type=self.provider_type,
|
|
57
|
+
name="MCP Server",
|
|
58
|
+
description=f"MCP server ({self.transport} transport)",
|
|
59
|
+
capabilities=["list-tools", "call-tool", "list-resources"],
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def list_endpoints(self, tags: Optional[List[str]] = None) -> List[EndpointInfo]:
|
|
63
|
+
"""List available MCP tools as endpoints."""
|
|
64
|
+
if self.transport == "stdio":
|
|
65
|
+
return self._list_stdio_tools(tags)
|
|
66
|
+
else:
|
|
67
|
+
return self._list_http_tools(tags)
|
|
68
|
+
|
|
69
|
+
def _list_stdio_tools(self, tags: Optional[List[str]] = None) -> List[EndpointInfo]:
|
|
70
|
+
"""List tools from stdio MCP server."""
|
|
71
|
+
try:
|
|
72
|
+
from praisonaiagents.mcp import MCP
|
|
73
|
+
|
|
74
|
+
mcp = MCP(command=self.command, args=self.args, env=self.env)
|
|
75
|
+
tools = mcp.get_tools()
|
|
76
|
+
|
|
77
|
+
endpoints = []
|
|
78
|
+
for tool in tools:
|
|
79
|
+
tool_name = getattr(tool, 'name', str(tool))
|
|
80
|
+
tool_desc = getattr(tool, 'description', '')
|
|
81
|
+
|
|
82
|
+
endpoints.append(EndpointInfo(
|
|
83
|
+
name=tool_name,
|
|
84
|
+
description=tool_desc,
|
|
85
|
+
provider_type=self.provider_type,
|
|
86
|
+
streaming=["mcp-stream"],
|
|
87
|
+
auth_modes=["none"],
|
|
88
|
+
metadata={"transport": "stdio"},
|
|
89
|
+
))
|
|
90
|
+
|
|
91
|
+
return endpoints
|
|
92
|
+
except Exception:
|
|
93
|
+
return []
|
|
94
|
+
|
|
95
|
+
def _list_http_tools(self, tags: Optional[List[str]] = None) -> List[EndpointInfo]:
|
|
96
|
+
"""List tools from HTTP MCP server."""
|
|
97
|
+
# Try unified discovery first
|
|
98
|
+
result = self._make_request("GET", "/__praisonai__/discovery")
|
|
99
|
+
|
|
100
|
+
if not result.get("error") and result.get("data"):
|
|
101
|
+
data = result.get("data", {})
|
|
102
|
+
endpoints = []
|
|
103
|
+
for ep in data.get("endpoints", []):
|
|
104
|
+
if ep.get("provider_type") == self.provider_type:
|
|
105
|
+
endpoints.append(EndpointInfo(
|
|
106
|
+
name=ep.get("name", ""),
|
|
107
|
+
description=ep.get("description", ""),
|
|
108
|
+
provider_type=self.provider_type,
|
|
109
|
+
tags=ep.get("tags", []),
|
|
110
|
+
streaming=ep.get("streaming", ["mcp-stream"]),
|
|
111
|
+
auth_modes=ep.get("auth_modes", ["none"]),
|
|
112
|
+
))
|
|
113
|
+
return endpoints
|
|
114
|
+
|
|
115
|
+
# Fallback: try MCP tools endpoint
|
|
116
|
+
result = self._make_request("GET", "/mcp/tools")
|
|
117
|
+
|
|
118
|
+
if result.get("error"):
|
|
119
|
+
return []
|
|
120
|
+
|
|
121
|
+
tools = result.get("data", {}).get("tools", [])
|
|
122
|
+
endpoints = []
|
|
123
|
+
|
|
124
|
+
for tool in tools:
|
|
125
|
+
endpoints.append(EndpointInfo(
|
|
126
|
+
name=tool.get("name", ""),
|
|
127
|
+
description=tool.get("description", ""),
|
|
128
|
+
provider_type=self.provider_type,
|
|
129
|
+
input_schema=tool.get("inputSchema"),
|
|
130
|
+
streaming=["mcp-stream"],
|
|
131
|
+
auth_modes=["none"],
|
|
132
|
+
))
|
|
133
|
+
|
|
134
|
+
return endpoints
|
|
135
|
+
|
|
136
|
+
def describe_endpoint(self, name: str) -> Optional[EndpointInfo]:
|
|
137
|
+
"""Get detailed information about an MCP tool."""
|
|
138
|
+
endpoints = self.list_endpoints()
|
|
139
|
+
for ep in endpoints:
|
|
140
|
+
if ep.name == name:
|
|
141
|
+
return ep
|
|
142
|
+
return None
|
|
143
|
+
|
|
144
|
+
def invoke(
|
|
145
|
+
self,
|
|
146
|
+
name: str,
|
|
147
|
+
input_data: Optional[Dict[str, Any]] = None,
|
|
148
|
+
config: Optional[Dict[str, Any]] = None,
|
|
149
|
+
stream: bool = False,
|
|
150
|
+
) -> InvokeResult:
|
|
151
|
+
"""Invoke an MCP tool."""
|
|
152
|
+
if self.transport == "stdio":
|
|
153
|
+
return self._invoke_stdio(name, input_data)
|
|
154
|
+
else:
|
|
155
|
+
return self._invoke_http(name, input_data)
|
|
156
|
+
|
|
157
|
+
def _invoke_stdio(self, name: str, input_data: Optional[Dict[str, Any]] = None) -> InvokeResult:
|
|
158
|
+
"""Invoke tool via stdio MCP."""
|
|
159
|
+
try:
|
|
160
|
+
from praisonaiagents.mcp import MCP
|
|
161
|
+
|
|
162
|
+
mcp = MCP(command=self.command, args=self.args, env=self.env)
|
|
163
|
+
tools = mcp.get_tools()
|
|
164
|
+
|
|
165
|
+
for tool in tools:
|
|
166
|
+
tool_name = getattr(tool, 'name', str(tool))
|
|
167
|
+
if tool_name == name:
|
|
168
|
+
if callable(tool):
|
|
169
|
+
result = tool(**(input_data or {}))
|
|
170
|
+
return InvokeResult(
|
|
171
|
+
ok=True,
|
|
172
|
+
status="success",
|
|
173
|
+
data=result,
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
return InvokeResult(
|
|
177
|
+
ok=False,
|
|
178
|
+
status="not_found",
|
|
179
|
+
error=f"Tool not found: {name}",
|
|
180
|
+
)
|
|
181
|
+
except Exception as e:
|
|
182
|
+
return InvokeResult(
|
|
183
|
+
ok=False,
|
|
184
|
+
status="error",
|
|
185
|
+
error=str(e),
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
def _invoke_http(self, name: str, input_data: Optional[Dict[str, Any]] = None) -> InvokeResult:
|
|
189
|
+
"""Invoke tool via HTTP MCP."""
|
|
190
|
+
body = {
|
|
191
|
+
"tool": name,
|
|
192
|
+
"arguments": input_data or {},
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
result = self._make_request("POST", "/mcp/tools/call", json_data=body)
|
|
196
|
+
|
|
197
|
+
if result.get("error"):
|
|
198
|
+
return InvokeResult(
|
|
199
|
+
ok=False,
|
|
200
|
+
status="error",
|
|
201
|
+
error=result["error"].get("message", str(result["error"])),
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
data = result.get("data", {})
|
|
205
|
+
return InvokeResult(
|
|
206
|
+
ok=True,
|
|
207
|
+
status="success",
|
|
208
|
+
data=data.get("result", data),
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
def invoke_stream(
|
|
212
|
+
self,
|
|
213
|
+
name: str,
|
|
214
|
+
input_data: Optional[Dict[str, Any]] = None,
|
|
215
|
+
config: Optional[Dict[str, Any]] = None,
|
|
216
|
+
) -> Iterator[Dict[str, Any]]:
|
|
217
|
+
"""Invoke MCP tool with streaming."""
|
|
218
|
+
# MCP streaming is tool-specific; for now, wrap sync call
|
|
219
|
+
result = self.invoke(name, input_data, config)
|
|
220
|
+
if result.ok:
|
|
221
|
+
yield {"event": "result", "data": result.data}
|
|
222
|
+
else:
|
|
223
|
+
yield {"event": "error", "data": {"error": result.error}}
|
|
224
|
+
|
|
225
|
+
def health(self) -> HealthResult:
|
|
226
|
+
"""Check MCP server health."""
|
|
227
|
+
if self.transport == "stdio":
|
|
228
|
+
# For stdio, check if command exists
|
|
229
|
+
import shutil
|
|
230
|
+
if self.command and shutil.which(self.command):
|
|
231
|
+
return HealthResult(
|
|
232
|
+
healthy=True,
|
|
233
|
+
status="available",
|
|
234
|
+
server_name=self.command,
|
|
235
|
+
provider_type=self.provider_type,
|
|
236
|
+
metadata={"transport": "stdio"},
|
|
237
|
+
)
|
|
238
|
+
return HealthResult(
|
|
239
|
+
healthy=False,
|
|
240
|
+
status="unavailable",
|
|
241
|
+
provider_type=self.provider_type,
|
|
242
|
+
metadata={"error": f"Command not found: {self.command}"},
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
# HTTP health check
|
|
246
|
+
result = self._make_request("GET", "/health")
|
|
247
|
+
|
|
248
|
+
if result.get("error"):
|
|
249
|
+
return HealthResult(
|
|
250
|
+
healthy=False,
|
|
251
|
+
status="unhealthy",
|
|
252
|
+
provider_type=self.provider_type,
|
|
253
|
+
metadata={"error": result["error"].get("message", str(result["error"]))},
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
data = result.get("data", {})
|
|
257
|
+
return HealthResult(
|
|
258
|
+
healthy=True,
|
|
259
|
+
status="healthy",
|
|
260
|
+
server_name=data.get("server_name", "MCP Server"),
|
|
261
|
+
server_version=data.get("version"),
|
|
262
|
+
provider_type=self.provider_type,
|
|
263
|
+
)
|