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,680 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tools Handler for CLI.
|
|
3
|
+
|
|
4
|
+
Provides tool registry management.
|
|
5
|
+
Usage: praisonai tools list
|
|
6
|
+
praisonai tools info internet_search
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Any, Dict, List
|
|
10
|
+
from .base import CommandHandler
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ToolsHandler(CommandHandler):
|
|
14
|
+
"""
|
|
15
|
+
Handler for tools command.
|
|
16
|
+
|
|
17
|
+
Manages tool registry and provides tool information.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
praisonai tools list
|
|
21
|
+
praisonai tools info internet_search
|
|
22
|
+
praisonai tools search "web"
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, verbose: bool = False):
|
|
26
|
+
super().__init__(verbose)
|
|
27
|
+
self._registry = None
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def feature_name(self) -> str:
|
|
31
|
+
return "tools"
|
|
32
|
+
|
|
33
|
+
def get_actions(self) -> List[str]:
|
|
34
|
+
return ["list", "info", "search", "doctor", "resolve", "discover", "show-sources", "add", "add-sources", "remove-sources", "help"]
|
|
35
|
+
|
|
36
|
+
def get_help_text(self) -> str:
|
|
37
|
+
return """
|
|
38
|
+
Tools Commands:
|
|
39
|
+
praisonai tools list - List all available tools
|
|
40
|
+
praisonai tools info <name> - Show tool details
|
|
41
|
+
praisonai tools search <query> - Search tools by name/description
|
|
42
|
+
praisonai tools doctor - Diagnose tool availability and dependencies
|
|
43
|
+
praisonai tools doctor --json - Output diagnosis as JSON
|
|
44
|
+
praisonai tools resolve <name> - Resolve a tool name to its source
|
|
45
|
+
praisonai tools discover - Discover tools from installed packages
|
|
46
|
+
praisonai tools show-sources - Show all tool sources for a template
|
|
47
|
+
praisonai tools add <source> - Add tools from package, file, or GitHub
|
|
48
|
+
praisonai tools add-sources <source> - Add a tool source to persistent config
|
|
49
|
+
praisonai tools remove-sources <source> - Remove a tool source from config
|
|
50
|
+
|
|
51
|
+
Add Examples:
|
|
52
|
+
praisonai tools add pandas - Wrap pandas functions as tools
|
|
53
|
+
praisonai tools add ./my_tools.py - Add local tools file
|
|
54
|
+
praisonai tools add github:user/repo - Add tools from GitHub
|
|
55
|
+
|
|
56
|
+
Built-in tools include: internet_search, calculator, file operations, etc.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def _get_registry(self):
|
|
60
|
+
"""Get tool registry lazily."""
|
|
61
|
+
if self._registry is None:
|
|
62
|
+
try:
|
|
63
|
+
from praisonaiagents.tools import get_registry
|
|
64
|
+
self._registry = get_registry()
|
|
65
|
+
except ImportError:
|
|
66
|
+
self.print_status(
|
|
67
|
+
"Tools require praisonaiagents. Install with: pip install praisonaiagents",
|
|
68
|
+
"error"
|
|
69
|
+
)
|
|
70
|
+
return None
|
|
71
|
+
return self._registry
|
|
72
|
+
|
|
73
|
+
def _get_builtin_tools(self) -> Dict[str, Any]:
|
|
74
|
+
"""Get dictionary of built-in tools."""
|
|
75
|
+
tools = {}
|
|
76
|
+
try:
|
|
77
|
+
from praisonaiagents.tools import TOOL_MAPPINGS
|
|
78
|
+
tools.update(TOOL_MAPPINGS)
|
|
79
|
+
except ImportError:
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
# Add common tool descriptions
|
|
83
|
+
tool_descriptions = {
|
|
84
|
+
"internet_search": "Search the internet using DuckDuckGo",
|
|
85
|
+
"calculator": "Perform mathematical calculations",
|
|
86
|
+
"read_file": "Read contents of a file",
|
|
87
|
+
"write_file": "Write content to a file",
|
|
88
|
+
"list_files": "List files in a directory",
|
|
89
|
+
"execute_code": "Execute Python code",
|
|
90
|
+
"shell_command": "Execute shell commands",
|
|
91
|
+
"wikipedia_search": "Search Wikipedia",
|
|
92
|
+
"arxiv_search": "Search arXiv papers",
|
|
93
|
+
"tavily_search": "Search using Tavily API",
|
|
94
|
+
"csv_read": "Read CSV files",
|
|
95
|
+
"json_read": "Read JSON files",
|
|
96
|
+
"yaml_read": "Read YAML files",
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for name, desc in tool_descriptions.items():
|
|
100
|
+
if name not in tools:
|
|
101
|
+
tools[name] = {"description": desc, "available": name in tools}
|
|
102
|
+
|
|
103
|
+
return tools
|
|
104
|
+
|
|
105
|
+
def action_list(self, args: List[str], **kwargs) -> List[str]:
|
|
106
|
+
"""
|
|
107
|
+
List all available tools.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
List of tool names
|
|
111
|
+
"""
|
|
112
|
+
tools = self._get_builtin_tools()
|
|
113
|
+
|
|
114
|
+
self.print_status("\n🔧 Available Tools:", "info")
|
|
115
|
+
self.print_status("-" * 50, "info")
|
|
116
|
+
|
|
117
|
+
# Group by category
|
|
118
|
+
categories = {
|
|
119
|
+
"Search": ["internet_search", "wikipedia_search", "arxiv_search", "tavily_search"],
|
|
120
|
+
"File": ["read_file", "write_file", "list_files", "csv_read", "json_read", "yaml_read"],
|
|
121
|
+
"Code": ["execute_code", "shell_command", "calculator"],
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
for category, tool_names in categories.items():
|
|
125
|
+
self.print_status(f"\n {category}:", "info")
|
|
126
|
+
for name in tool_names:
|
|
127
|
+
if name in tools:
|
|
128
|
+
desc = tools[name].get("description", "No description") if isinstance(tools[name], dict) else "Available"
|
|
129
|
+
self.print_status(f" • {name}: {desc}", "info")
|
|
130
|
+
|
|
131
|
+
# List any uncategorized tools
|
|
132
|
+
categorized = set(t for tools_list in categories.values() for t in tools_list)
|
|
133
|
+
uncategorized = [t for t in tools.keys() if t not in categorized]
|
|
134
|
+
|
|
135
|
+
if uncategorized:
|
|
136
|
+
self.print_status("\n Other:", "info")
|
|
137
|
+
for name in uncategorized[:10]: # Limit to 10
|
|
138
|
+
self.print_status(f" • {name}", "info")
|
|
139
|
+
|
|
140
|
+
# Show added tool sources from config
|
|
141
|
+
config = self._load_config()
|
|
142
|
+
if config.get("sources"):
|
|
143
|
+
self.print_status("\n Added Sources (use with Agent):", "info")
|
|
144
|
+
for source in config["sources"]:
|
|
145
|
+
self.print_status(f" • {source}", "info")
|
|
146
|
+
|
|
147
|
+
return list(tools.keys())
|
|
148
|
+
|
|
149
|
+
def action_info(self, args: List[str], **kwargs) -> Dict[str, Any]:
|
|
150
|
+
"""
|
|
151
|
+
Show tool information.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
args: List containing tool name
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
Dictionary of tool info
|
|
158
|
+
"""
|
|
159
|
+
if not args:
|
|
160
|
+
self.print_status("Usage: praisonai tools info <tool_name>", "error")
|
|
161
|
+
return {}
|
|
162
|
+
|
|
163
|
+
tool_name = args[0]
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
import praisonaiagents.tools as tools_module
|
|
167
|
+
|
|
168
|
+
if hasattr(tools_module, tool_name):
|
|
169
|
+
tool = getattr(tools_module, tool_name)
|
|
170
|
+
|
|
171
|
+
info = {
|
|
172
|
+
"name": tool_name,
|
|
173
|
+
"type": type(tool).__name__,
|
|
174
|
+
"doc": tool.__doc__ or "No documentation",
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
# Get function signature if available
|
|
178
|
+
if callable(tool):
|
|
179
|
+
import inspect
|
|
180
|
+
try:
|
|
181
|
+
sig = inspect.signature(tool)
|
|
182
|
+
info["signature"] = str(sig)
|
|
183
|
+
info["parameters"] = list(sig.parameters.keys())
|
|
184
|
+
except (ValueError, TypeError):
|
|
185
|
+
pass
|
|
186
|
+
|
|
187
|
+
self.print_status(f"\n🔧 Tool: {tool_name}", "info")
|
|
188
|
+
self.print_status("-" * 40, "info")
|
|
189
|
+
for key, value in info.items():
|
|
190
|
+
if key == "doc":
|
|
191
|
+
self.print_status(f"\nDescription:\n{value}", "info")
|
|
192
|
+
else:
|
|
193
|
+
self.print_status(f" {key}: {value}", "info")
|
|
194
|
+
|
|
195
|
+
return info
|
|
196
|
+
else:
|
|
197
|
+
self.print_status(f"Tool '{tool_name}' not found", "error")
|
|
198
|
+
return {}
|
|
199
|
+
|
|
200
|
+
except ImportError:
|
|
201
|
+
self.print_status("Could not load tools module", "error")
|
|
202
|
+
return {}
|
|
203
|
+
|
|
204
|
+
def action_search(self, args: List[str], **kwargs) -> List[str]:
|
|
205
|
+
"""
|
|
206
|
+
Search tools by name or description.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
args: List containing search query
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
List of matching tool names
|
|
213
|
+
"""
|
|
214
|
+
if not args:
|
|
215
|
+
self.print_status("Usage: praisonai tools search <query>", "error")
|
|
216
|
+
return []
|
|
217
|
+
|
|
218
|
+
query = ' '.join(args).lower()
|
|
219
|
+
tools = self._get_builtin_tools()
|
|
220
|
+
|
|
221
|
+
matches = []
|
|
222
|
+
for name, info in tools.items():
|
|
223
|
+
desc = info.get("description", "") if isinstance(info, dict) else ""
|
|
224
|
+
if query in name.lower() or query in desc.lower():
|
|
225
|
+
matches.append(name)
|
|
226
|
+
|
|
227
|
+
if matches:
|
|
228
|
+
self.print_status(f"\n🔍 Tools matching '{query}':", "info")
|
|
229
|
+
for name in matches:
|
|
230
|
+
self.print_status(f" • {name}", "info")
|
|
231
|
+
else:
|
|
232
|
+
self.print_status(f"No tools found matching '{query}'", "warning")
|
|
233
|
+
|
|
234
|
+
return matches
|
|
235
|
+
|
|
236
|
+
def action_doctor(self, args: List[str], **kwargs) -> Dict[str, Any]:
|
|
237
|
+
"""
|
|
238
|
+
Diagnose tool availability and dependencies.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
args: List containing optional flags (--json)
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
Dict with diagnostic results
|
|
245
|
+
"""
|
|
246
|
+
json_output = "--json" in args
|
|
247
|
+
|
|
248
|
+
try:
|
|
249
|
+
from praisonai.templates.tools_doctor import ToolsDoctor
|
|
250
|
+
|
|
251
|
+
doctor = ToolsDoctor()
|
|
252
|
+
|
|
253
|
+
if json_output:
|
|
254
|
+
print(doctor.diagnose_json())
|
|
255
|
+
else:
|
|
256
|
+
print(doctor.diagnose_human())
|
|
257
|
+
|
|
258
|
+
return doctor.diagnose()
|
|
259
|
+
|
|
260
|
+
except Exception as e:
|
|
261
|
+
self.print_status(f"Error running diagnostics: {e}", "error")
|
|
262
|
+
return {}
|
|
263
|
+
|
|
264
|
+
def action_resolve(self, args: List[str], **kwargs) -> Dict[str, Any]:
|
|
265
|
+
"""
|
|
266
|
+
Resolve a tool name to its source.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
args: [tool_name, --template <template>, --tools <file>, --tools-dir <dir>]
|
|
270
|
+
"""
|
|
271
|
+
if not args:
|
|
272
|
+
self.print_status("Usage: praisonai tools resolve <tool_name> [--template <template>]", "error")
|
|
273
|
+
return {}
|
|
274
|
+
|
|
275
|
+
tool_name = args[0]
|
|
276
|
+
template_name = None
|
|
277
|
+
tools_files = []
|
|
278
|
+
tools_dirs = []
|
|
279
|
+
|
|
280
|
+
# Parse flags
|
|
281
|
+
i = 1
|
|
282
|
+
while i < len(args):
|
|
283
|
+
if args[i] == "--template" and i + 1 < len(args):
|
|
284
|
+
template_name = args[i + 1]
|
|
285
|
+
i += 2
|
|
286
|
+
elif args[i] == "--tools" and i + 1 < len(args):
|
|
287
|
+
tools_files.append(args[i + 1])
|
|
288
|
+
i += 2
|
|
289
|
+
elif args[i] == "--tools-dir" and i + 1 < len(args):
|
|
290
|
+
tools_dirs.append(args[i + 1])
|
|
291
|
+
i += 2
|
|
292
|
+
else:
|
|
293
|
+
i += 1
|
|
294
|
+
|
|
295
|
+
try:
|
|
296
|
+
from praisonai.templates.tool_override import create_tool_registry_with_overrides, resolve_tools
|
|
297
|
+
|
|
298
|
+
registry = create_tool_registry_with_overrides(
|
|
299
|
+
override_files=tools_files if tools_files else None,
|
|
300
|
+
override_dirs=tools_dirs if tools_dirs else None,
|
|
301
|
+
include_defaults=True,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
resolved = resolve_tools([tool_name], registry=registry)
|
|
305
|
+
|
|
306
|
+
if resolved:
|
|
307
|
+
tool = resolved[0]
|
|
308
|
+
info = {
|
|
309
|
+
"name": tool_name,
|
|
310
|
+
"resolved": True,
|
|
311
|
+
"type": type(tool).__name__,
|
|
312
|
+
"module": getattr(tool, "__module__", "unknown"),
|
|
313
|
+
}
|
|
314
|
+
self.print_status(f"\n✓ Tool '{tool_name}' resolved:", "success")
|
|
315
|
+
for k, v in info.items():
|
|
316
|
+
self.print_status(f" {k}: {v}", "info")
|
|
317
|
+
return info
|
|
318
|
+
else:
|
|
319
|
+
self.print_status(f"✗ Tool '{tool_name}' not found", "error")
|
|
320
|
+
return {"name": tool_name, "resolved": False}
|
|
321
|
+
|
|
322
|
+
except Exception as e:
|
|
323
|
+
self.print_status(f"Error resolving tool: {e}", "error")
|
|
324
|
+
return {}
|
|
325
|
+
|
|
326
|
+
def action_discover(self, args: List[str], **kwargs) -> Dict[str, Any]:
|
|
327
|
+
"""
|
|
328
|
+
Discover tools from installed packages.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
args: [--include <package>, --entrypoints]
|
|
332
|
+
"""
|
|
333
|
+
include_packages = []
|
|
334
|
+
use_entrypoints = "--entrypoints" in args
|
|
335
|
+
|
|
336
|
+
i = 0
|
|
337
|
+
while i < len(args):
|
|
338
|
+
if args[i] == "--include" and i + 1 < len(args):
|
|
339
|
+
include_packages.append(args[i + 1])
|
|
340
|
+
i += 2
|
|
341
|
+
else:
|
|
342
|
+
i += 1
|
|
343
|
+
|
|
344
|
+
discovered = {}
|
|
345
|
+
|
|
346
|
+
# Try praisonai_tools package
|
|
347
|
+
try:
|
|
348
|
+
import praisonai_tools
|
|
349
|
+
pkg_tools = []
|
|
350
|
+
|
|
351
|
+
# Check for video module
|
|
352
|
+
try:
|
|
353
|
+
from praisonai_tools import video
|
|
354
|
+
pkg_tools.append("praisonai_tools.video")
|
|
355
|
+
except ImportError:
|
|
356
|
+
pass
|
|
357
|
+
|
|
358
|
+
# Check for tools module
|
|
359
|
+
try:
|
|
360
|
+
import praisonai_tools.tools as ext_tools
|
|
361
|
+
for name in dir(ext_tools):
|
|
362
|
+
if not name.startswith('_'):
|
|
363
|
+
obj = getattr(ext_tools, name, None)
|
|
364
|
+
if callable(obj):
|
|
365
|
+
pkg_tools.append(name)
|
|
366
|
+
except ImportError:
|
|
367
|
+
pass
|
|
368
|
+
|
|
369
|
+
if pkg_tools:
|
|
370
|
+
discovered["praisonai_tools"] = pkg_tools
|
|
371
|
+
except ImportError:
|
|
372
|
+
pass
|
|
373
|
+
|
|
374
|
+
# Try praisonaiagents built-in tools
|
|
375
|
+
try:
|
|
376
|
+
from praisonaiagents.tools import TOOL_MAPPINGS
|
|
377
|
+
discovered["praisonaiagents.tools"] = list(TOOL_MAPPINGS.keys())[:20] # Limit
|
|
378
|
+
except ImportError:
|
|
379
|
+
pass
|
|
380
|
+
|
|
381
|
+
# Additional packages from --include
|
|
382
|
+
for pkg in include_packages:
|
|
383
|
+
try:
|
|
384
|
+
import importlib
|
|
385
|
+
mod = importlib.import_module(pkg)
|
|
386
|
+
tools = [n for n in dir(mod) if not n.startswith('_') and callable(getattr(mod, n, None))]
|
|
387
|
+
if tools:
|
|
388
|
+
discovered[pkg] = tools[:20]
|
|
389
|
+
except ImportError:
|
|
390
|
+
self.print_status(f"Package '{pkg}' not found", "warning")
|
|
391
|
+
|
|
392
|
+
self.print_status("\n🔍 Discovered Tools:", "info")
|
|
393
|
+
for pkg, tools in discovered.items():
|
|
394
|
+
self.print_status(f"\n {pkg}:", "info")
|
|
395
|
+
for t in tools[:10]:
|
|
396
|
+
self.print_status(f" • {t}", "info")
|
|
397
|
+
if len(tools) > 10:
|
|
398
|
+
self.print_status(f" ... and {len(tools) - 10} more", "info")
|
|
399
|
+
|
|
400
|
+
return discovered
|
|
401
|
+
|
|
402
|
+
def action_show_sources(self, args: List[str], **kwargs) -> Dict[str, Any]:
|
|
403
|
+
"""
|
|
404
|
+
Show all tool sources for a template.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
args: [--template <template>]
|
|
408
|
+
"""
|
|
409
|
+
template_name = None
|
|
410
|
+
|
|
411
|
+
i = 0
|
|
412
|
+
while i < len(args):
|
|
413
|
+
if args[i] == "--template" and i + 1 < len(args):
|
|
414
|
+
template_name = args[i + 1]
|
|
415
|
+
i += 2
|
|
416
|
+
else:
|
|
417
|
+
i += 1
|
|
418
|
+
|
|
419
|
+
from pathlib import Path
|
|
420
|
+
|
|
421
|
+
# Check if tools.py exists in current directory
|
|
422
|
+
cwd_tools_py = Path.cwd() / "tools.py"
|
|
423
|
+
|
|
424
|
+
sources = {
|
|
425
|
+
"built_in": "praisonaiagents.tools.TOOL_MAPPINGS",
|
|
426
|
+
"package_discovery": ["praisonai_tools"],
|
|
427
|
+
"default_dirs": [
|
|
428
|
+
"~/.praison/tools",
|
|
429
|
+
"~/.config/praison/tools",
|
|
430
|
+
],
|
|
431
|
+
"cwd_tools_py": str(cwd_tools_py) if cwd_tools_py.exists() else "(not found: ./tools.py)",
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if template_name:
|
|
435
|
+
try:
|
|
436
|
+
from praisonai.templates.loader import TemplateLoader
|
|
437
|
+
loader = TemplateLoader()
|
|
438
|
+
template = loader.load_template(template_name)
|
|
439
|
+
|
|
440
|
+
if template.requires and isinstance(template.requires, dict):
|
|
441
|
+
ts = template.requires.get("tools_sources", [])
|
|
442
|
+
if ts:
|
|
443
|
+
sources["template_tools_sources"] = ts
|
|
444
|
+
|
|
445
|
+
if template.path:
|
|
446
|
+
from pathlib import Path
|
|
447
|
+
tools_py = Path(template.path) / "tools.py"
|
|
448
|
+
if tools_py.exists():
|
|
449
|
+
sources["template_local_tools_py"] = str(tools_py)
|
|
450
|
+
|
|
451
|
+
except Exception as e:
|
|
452
|
+
self.print_status(f"Could not load template: {e}", "warning")
|
|
453
|
+
|
|
454
|
+
self.print_status("\n📦 Tool Sources:", "info")
|
|
455
|
+
for source_type, value in sources.items():
|
|
456
|
+
if isinstance(value, list):
|
|
457
|
+
self.print_status(f"\n {source_type}:", "info")
|
|
458
|
+
for v in value:
|
|
459
|
+
self.print_status(f" • {v}", "info")
|
|
460
|
+
else:
|
|
461
|
+
self.print_status(f"\n {source_type}: {value}", "info")
|
|
462
|
+
|
|
463
|
+
return sources
|
|
464
|
+
|
|
465
|
+
def _get_config_path(self):
|
|
466
|
+
"""Get the path to the tools config file."""
|
|
467
|
+
from pathlib import Path
|
|
468
|
+
config_dir = Path.home() / ".praison"
|
|
469
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
470
|
+
return config_dir / "tools_sources.yaml"
|
|
471
|
+
|
|
472
|
+
def _load_config(self) -> Dict[str, Any]:
|
|
473
|
+
"""Load tools config from file."""
|
|
474
|
+
config_path = self._get_config_path()
|
|
475
|
+
if config_path.exists():
|
|
476
|
+
import yaml
|
|
477
|
+
with open(config_path, 'r') as f:
|
|
478
|
+
return yaml.safe_load(f) or {}
|
|
479
|
+
return {"sources": []}
|
|
480
|
+
|
|
481
|
+
def _save_config(self, config: Dict[str, Any]):
|
|
482
|
+
"""Save tools config to file."""
|
|
483
|
+
import yaml
|
|
484
|
+
config_path = self._get_config_path()
|
|
485
|
+
with open(config_path, 'w') as f:
|
|
486
|
+
yaml.dump(config, f, default_flow_style=False)
|
|
487
|
+
|
|
488
|
+
def action_add(self, args: List[str], **kwargs) -> Dict[str, Any]:
|
|
489
|
+
"""
|
|
490
|
+
Add tools from package, file, or GitHub.
|
|
491
|
+
|
|
492
|
+
Args:
|
|
493
|
+
args: [source] - package name, file path, or github:user/repo
|
|
494
|
+
|
|
495
|
+
Examples:
|
|
496
|
+
praisonai tools add pandas
|
|
497
|
+
praisonai tools add ./my_tools.py
|
|
498
|
+
praisonai tools add github:user/repo/tools
|
|
499
|
+
"""
|
|
500
|
+
if not args:
|
|
501
|
+
self.print_status("Usage: praisonai tools add <source>", "error")
|
|
502
|
+
self.print_status(" source: package name, file path, or github:user/repo", "info")
|
|
503
|
+
return {"success": False, "error": "No source provided"}
|
|
504
|
+
|
|
505
|
+
source = args[0]
|
|
506
|
+
result = {"source": source, "success": False, "tools": []}
|
|
507
|
+
|
|
508
|
+
from pathlib import Path
|
|
509
|
+
|
|
510
|
+
# Check if it's a local file
|
|
511
|
+
if source.startswith("./") or source.startswith("/") or source.endswith(".py"):
|
|
512
|
+
path = Path(source).resolve()
|
|
513
|
+
if path.exists():
|
|
514
|
+
# Copy to ~/.praison/tools/
|
|
515
|
+
tools_dir = Path.home() / ".praison" / "tools"
|
|
516
|
+
tools_dir.mkdir(parents=True, exist_ok=True)
|
|
517
|
+
dest = tools_dir / path.name
|
|
518
|
+
|
|
519
|
+
import shutil
|
|
520
|
+
shutil.copy(path, dest)
|
|
521
|
+
|
|
522
|
+
self.print_status(f"\n✅ Added tools file: {path.name}", "success")
|
|
523
|
+
self.print_status(f" Copied to: {dest}", "info")
|
|
524
|
+
|
|
525
|
+
# Discover tools in the file
|
|
526
|
+
try:
|
|
527
|
+
import importlib.util
|
|
528
|
+
spec = importlib.util.spec_from_file_location("tools_module", dest)
|
|
529
|
+
module = importlib.util.module_from_spec(spec)
|
|
530
|
+
spec.loader.exec_module(module)
|
|
531
|
+
|
|
532
|
+
tools = [n for n in dir(module) if not n.startswith('_') and callable(getattr(module, n, None))]
|
|
533
|
+
result["tools"] = tools
|
|
534
|
+
self.print_status(f" Found {len(tools)} tools: {', '.join(tools[:5])}", "info")
|
|
535
|
+
except Exception as e:
|
|
536
|
+
self.print_status(f" Warning: Could not inspect tools: {e}", "warning")
|
|
537
|
+
|
|
538
|
+
result["success"] = True
|
|
539
|
+
return result
|
|
540
|
+
else:
|
|
541
|
+
self.print_status(f"File not found: {source}", "error")
|
|
542
|
+
return result
|
|
543
|
+
|
|
544
|
+
# Check if it's a GitHub reference
|
|
545
|
+
elif source.startswith("github:"):
|
|
546
|
+
github_path = source[7:] # Remove "github:"
|
|
547
|
+
parts = github_path.split("/")
|
|
548
|
+
if len(parts) < 2:
|
|
549
|
+
self.print_status("Invalid GitHub format. Use: github:user/repo/path", "error")
|
|
550
|
+
return result
|
|
551
|
+
|
|
552
|
+
user, repo = parts[0], parts[1]
|
|
553
|
+
path = "/".join(parts[2:]) if len(parts) > 2 else ""
|
|
554
|
+
|
|
555
|
+
# Download from GitHub
|
|
556
|
+
import urllib.request
|
|
557
|
+
|
|
558
|
+
if path:
|
|
559
|
+
raw_url = f"https://raw.githubusercontent.com/{user}/{repo}/main/{path}"
|
|
560
|
+
if not path.endswith(".py"):
|
|
561
|
+
raw_url += "/tools.py"
|
|
562
|
+
else:
|
|
563
|
+
raw_url = f"https://raw.githubusercontent.com/{user}/{repo}/main/tools.py"
|
|
564
|
+
|
|
565
|
+
try:
|
|
566
|
+
self.print_status(f"Downloading from: {raw_url}", "info")
|
|
567
|
+
|
|
568
|
+
tools_dir = Path.home() / ".praison" / "tools"
|
|
569
|
+
tools_dir.mkdir(parents=True, exist_ok=True)
|
|
570
|
+
|
|
571
|
+
filename = f"{user}_{repo}_{path.replace('/', '_')}.py" if path else f"{user}_{repo}_tools.py"
|
|
572
|
+
dest = tools_dir / filename
|
|
573
|
+
|
|
574
|
+
urllib.request.urlretrieve(raw_url, dest)
|
|
575
|
+
|
|
576
|
+
self.print_status(f"\n✅ Added tools from GitHub: {user}/{repo}", "success")
|
|
577
|
+
self.print_status(f" Saved to: {dest}", "info")
|
|
578
|
+
|
|
579
|
+
result["success"] = True
|
|
580
|
+
return result
|
|
581
|
+
except Exception as e:
|
|
582
|
+
self.print_status(f"Failed to download from GitHub: {e}", "error")
|
|
583
|
+
return result
|
|
584
|
+
|
|
585
|
+
# Assume it's a package name - but warn that packages need wrapper tools
|
|
586
|
+
else:
|
|
587
|
+
try:
|
|
588
|
+
import importlib
|
|
589
|
+
module = importlib.import_module(source)
|
|
590
|
+
|
|
591
|
+
# Get callable functions from the module
|
|
592
|
+
tools = [n for n in dir(module) if not n.startswith('_') and callable(getattr(module, n, None))]
|
|
593
|
+
|
|
594
|
+
self.print_status(f"\n⚠️ Package '{source}' is installed but NOT directly usable as tools", "warning")
|
|
595
|
+
self.print_status(f" Found {len(tools)} callable items in package", "info")
|
|
596
|
+
self.print_status("", "info")
|
|
597
|
+
self.print_status(" To use this package with agents, create wrapper tools:", "info")
|
|
598
|
+
self.print_status(" 1. Create a file: ~/.praison/tools/my_tools.py", "info")
|
|
599
|
+
self.print_status(" 2. Define wrapper functions with docstrings", "info")
|
|
600
|
+
self.print_status(" 3. Tools will be auto-discovered", "info")
|
|
601
|
+
self.print_status("", "info")
|
|
602
|
+
self.print_status(" Example wrapper:", "info")
|
|
603
|
+
self.print_status(f" def my_{source}_tool(data: str) -> str:", "info")
|
|
604
|
+
self.print_status(f' """Use {source} to process data."""', "info")
|
|
605
|
+
self.print_status(f" import {source}", "info")
|
|
606
|
+
self.print_status(" # Your logic here", "info")
|
|
607
|
+
self.print_status(" return result", "info")
|
|
608
|
+
|
|
609
|
+
result["success"] = True
|
|
610
|
+
result["tools"] = tools[:10]
|
|
611
|
+
result["note"] = "Package requires wrapper tools"
|
|
612
|
+
return result
|
|
613
|
+
except ImportError:
|
|
614
|
+
self.print_status(f"Package '{source}' not found. Install with: pip install {source}", "error")
|
|
615
|
+
return result
|
|
616
|
+
|
|
617
|
+
def action_add_sources(self, args: List[str], **kwargs) -> Dict[str, Any]:
|
|
618
|
+
"""
|
|
619
|
+
Add a tool source to persistent config.
|
|
620
|
+
|
|
621
|
+
Args:
|
|
622
|
+
args: [source] - package name, file path, or github:user/repo
|
|
623
|
+
"""
|
|
624
|
+
if not args:
|
|
625
|
+
self.print_status("Usage: praisonai tools add-sources <source>", "error")
|
|
626
|
+
return {"success": False, "error": "No source provided"}
|
|
627
|
+
|
|
628
|
+
source = args[0]
|
|
629
|
+
config = self._load_config()
|
|
630
|
+
|
|
631
|
+
if "sources" not in config:
|
|
632
|
+
config["sources"] = []
|
|
633
|
+
|
|
634
|
+
if source in config["sources"]:
|
|
635
|
+
self.print_status(f"Source '{source}' already in config", "warning")
|
|
636
|
+
return {"success": True, "already_exists": True}
|
|
637
|
+
|
|
638
|
+
config["sources"].append(source)
|
|
639
|
+
self._save_config(config)
|
|
640
|
+
|
|
641
|
+
self.print_status(f"\n✅ Added tool source: {source}", "success")
|
|
642
|
+
self.print_status(f" Config saved to: {self._get_config_path()}", "info")
|
|
643
|
+
|
|
644
|
+
return {"success": True, "source": source}
|
|
645
|
+
|
|
646
|
+
def action_remove_sources(self, args: List[str], **kwargs) -> Dict[str, Any]:
|
|
647
|
+
"""
|
|
648
|
+
Remove a tool source from persistent config.
|
|
649
|
+
|
|
650
|
+
Args:
|
|
651
|
+
args: [source] - source to remove
|
|
652
|
+
"""
|
|
653
|
+
if not args:
|
|
654
|
+
self.print_status("Usage: praisonai tools remove-sources <source>", "error")
|
|
655
|
+
return {"success": False, "error": "No source provided"}
|
|
656
|
+
|
|
657
|
+
source = args[0]
|
|
658
|
+
config = self._load_config()
|
|
659
|
+
|
|
660
|
+
if "sources" not in config or source not in config["sources"]:
|
|
661
|
+
self.print_status(f"Source '{source}' not found in config", "warning")
|
|
662
|
+
return {"success": False, "not_found": True}
|
|
663
|
+
|
|
664
|
+
config["sources"].remove(source)
|
|
665
|
+
self._save_config(config)
|
|
666
|
+
|
|
667
|
+
self.print_status(f"\n✅ Removed tool source: {source}", "success")
|
|
668
|
+
|
|
669
|
+
return {"success": True, "source": source}
|
|
670
|
+
|
|
671
|
+
def execute(self, action: str, action_args: List[str], **kwargs) -> Any:
|
|
672
|
+
"""Execute tools command action."""
|
|
673
|
+
# Handle hyphenated action names
|
|
674
|
+
if action == "show-sources":
|
|
675
|
+
return self.action_show_sources(action_args, **kwargs)
|
|
676
|
+
elif action == "add-sources":
|
|
677
|
+
return self.action_add_sources(action_args, **kwargs)
|
|
678
|
+
elif action == "remove-sources":
|
|
679
|
+
return self.action_remove_sources(action_args, **kwargs)
|
|
680
|
+
return super().execute(action, action_args, **kwargs)
|