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,720 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Workflow Handler for CLI.
|
|
3
|
+
|
|
4
|
+
Provides YAML workflow management commands.
|
|
5
|
+
Usage: praisonai workflow run research.yaml
|
|
6
|
+
praisonai workflow validate research.yaml
|
|
7
|
+
praisonai workflow list
|
|
8
|
+
praisonai workflow create --template routing
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any, Dict, List, Optional
|
|
14
|
+
from .base import CommandHandler
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class WorkflowHandler(CommandHandler):
|
|
18
|
+
"""
|
|
19
|
+
Handler for workflow command.
|
|
20
|
+
|
|
21
|
+
Manages YAML workflow files - run, validate, list, and create from templates.
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
praisonai workflow run research.yaml --var topic="AI"
|
|
25
|
+
praisonai workflow validate research.yaml
|
|
26
|
+
praisonai workflow list
|
|
27
|
+
praisonai workflow create --template routing --output my_workflow.yaml
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
# Workflow templates
|
|
31
|
+
TEMPLATES = {
|
|
32
|
+
"simple": """# Simple Sequential Workflow
|
|
33
|
+
name: Simple Workflow
|
|
34
|
+
description: A simple sequential workflow
|
|
35
|
+
|
|
36
|
+
workflow:
|
|
37
|
+
verbose: true
|
|
38
|
+
|
|
39
|
+
agents:
|
|
40
|
+
researcher:
|
|
41
|
+
name: Researcher
|
|
42
|
+
role: Research Analyst
|
|
43
|
+
goal: Research topics
|
|
44
|
+
instructions: "Provide concise, factual information."
|
|
45
|
+
|
|
46
|
+
writer:
|
|
47
|
+
name: Writer
|
|
48
|
+
role: Content Writer
|
|
49
|
+
goal: Write content
|
|
50
|
+
instructions: "Write clear, engaging content."
|
|
51
|
+
|
|
52
|
+
steps:
|
|
53
|
+
- agent: researcher
|
|
54
|
+
action: "Research: {{input}}"
|
|
55
|
+
|
|
56
|
+
- agent: writer
|
|
57
|
+
action: "Write summary based on: {{previous_output}}"
|
|
58
|
+
""",
|
|
59
|
+
"routing": """# Routing Workflow
|
|
60
|
+
name: Routing Workflow
|
|
61
|
+
description: Classifier routes to specialized agents
|
|
62
|
+
|
|
63
|
+
workflow:
|
|
64
|
+
verbose: true
|
|
65
|
+
|
|
66
|
+
agents:
|
|
67
|
+
classifier:
|
|
68
|
+
name: Classifier
|
|
69
|
+
role: Request Classifier
|
|
70
|
+
goal: Classify requests
|
|
71
|
+
instructions: "Respond with ONLY 'technical', 'creative', or 'general'."
|
|
72
|
+
|
|
73
|
+
tech_agent:
|
|
74
|
+
name: TechExpert
|
|
75
|
+
role: Technical Expert
|
|
76
|
+
goal: Handle technical questions
|
|
77
|
+
instructions: "Provide technical answers."
|
|
78
|
+
|
|
79
|
+
creative_agent:
|
|
80
|
+
name: Creative
|
|
81
|
+
role: Creative Writer
|
|
82
|
+
goal: Handle creative requests
|
|
83
|
+
instructions: "Write creative content."
|
|
84
|
+
|
|
85
|
+
general_agent:
|
|
86
|
+
name: General
|
|
87
|
+
role: General Assistant
|
|
88
|
+
goal: Handle general requests
|
|
89
|
+
instructions: "Provide helpful responses."
|
|
90
|
+
|
|
91
|
+
steps:
|
|
92
|
+
- agent: classifier
|
|
93
|
+
action: "Classify: {{input}}"
|
|
94
|
+
|
|
95
|
+
- name: routing
|
|
96
|
+
route:
|
|
97
|
+
technical: [tech_agent]
|
|
98
|
+
creative: [creative_agent]
|
|
99
|
+
default: [general_agent]
|
|
100
|
+
""",
|
|
101
|
+
"parallel": """# Parallel Workflow
|
|
102
|
+
name: Parallel Research Workflow
|
|
103
|
+
description: Multiple agents work concurrently
|
|
104
|
+
|
|
105
|
+
workflow:
|
|
106
|
+
verbose: true
|
|
107
|
+
|
|
108
|
+
agents:
|
|
109
|
+
researcher1:
|
|
110
|
+
name: MarketResearcher
|
|
111
|
+
role: Market Analyst
|
|
112
|
+
goal: Research market trends
|
|
113
|
+
instructions: "Provide market insights."
|
|
114
|
+
|
|
115
|
+
researcher2:
|
|
116
|
+
name: CompetitorResearcher
|
|
117
|
+
role: Competitor Analyst
|
|
118
|
+
goal: Research competitors
|
|
119
|
+
instructions: "Provide competitor insights."
|
|
120
|
+
|
|
121
|
+
aggregator:
|
|
122
|
+
name: Aggregator
|
|
123
|
+
role: Synthesizer
|
|
124
|
+
goal: Combine findings
|
|
125
|
+
instructions: "Synthesize all research."
|
|
126
|
+
|
|
127
|
+
steps:
|
|
128
|
+
- name: parallel_research
|
|
129
|
+
parallel:
|
|
130
|
+
- agent: researcher1
|
|
131
|
+
action: "Research market for: {{input}}"
|
|
132
|
+
- agent: researcher2
|
|
133
|
+
action: "Research competitors for: {{input}}"
|
|
134
|
+
|
|
135
|
+
- agent: aggregator
|
|
136
|
+
action: "Combine all findings"
|
|
137
|
+
""",
|
|
138
|
+
"loop": """# Loop Workflow
|
|
139
|
+
name: Loop Processing Workflow
|
|
140
|
+
description: Process multiple items in a loop
|
|
141
|
+
|
|
142
|
+
workflow:
|
|
143
|
+
verbose: true
|
|
144
|
+
|
|
145
|
+
variables:
|
|
146
|
+
items:
|
|
147
|
+
- Item 1
|
|
148
|
+
- Item 2
|
|
149
|
+
- Item 3
|
|
150
|
+
|
|
151
|
+
agents:
|
|
152
|
+
processor:
|
|
153
|
+
name: Processor
|
|
154
|
+
role: Item Processor
|
|
155
|
+
goal: Process each item
|
|
156
|
+
instructions: "Process the given item thoroughly."
|
|
157
|
+
|
|
158
|
+
summarizer:
|
|
159
|
+
name: Summarizer
|
|
160
|
+
role: Summarizer
|
|
161
|
+
goal: Summarize results
|
|
162
|
+
instructions: "Summarize all processed items."
|
|
163
|
+
|
|
164
|
+
steps:
|
|
165
|
+
- agent: processor
|
|
166
|
+
action: "Process: {{item}}"
|
|
167
|
+
loop:
|
|
168
|
+
over: items
|
|
169
|
+
|
|
170
|
+
- agent: summarizer
|
|
171
|
+
action: "Summarize all processed items"
|
|
172
|
+
""",
|
|
173
|
+
"evaluator-optimizer": """# Evaluator-Optimizer Workflow
|
|
174
|
+
name: Evaluator Optimizer Workflow
|
|
175
|
+
description: Generate and improve until approved
|
|
176
|
+
|
|
177
|
+
workflow:
|
|
178
|
+
verbose: true
|
|
179
|
+
|
|
180
|
+
agents:
|
|
181
|
+
generator:
|
|
182
|
+
name: Generator
|
|
183
|
+
role: Content Generator
|
|
184
|
+
goal: Generate content
|
|
185
|
+
instructions: "Generate content. Improve based on feedback if provided."
|
|
186
|
+
|
|
187
|
+
evaluator:
|
|
188
|
+
name: Evaluator
|
|
189
|
+
role: Evaluator
|
|
190
|
+
goal: Evaluate content
|
|
191
|
+
instructions: "If good, respond 'APPROVED'. Otherwise provide feedback."
|
|
192
|
+
|
|
193
|
+
steps:
|
|
194
|
+
- agent: generator
|
|
195
|
+
action: "Generate content for: {{input}}"
|
|
196
|
+
|
|
197
|
+
- agent: evaluator
|
|
198
|
+
action: "Evaluate: {{previous_output}}"
|
|
199
|
+
repeat:
|
|
200
|
+
until: "approved"
|
|
201
|
+
max_iterations: 3
|
|
202
|
+
""",
|
|
203
|
+
"model-routing": """# Model Routing Workflow
|
|
204
|
+
name: Cost-Optimized Model Routing Workflow
|
|
205
|
+
description: Uses custom models with automatic routing based on task complexity
|
|
206
|
+
|
|
207
|
+
# Custom models configuration - define your own models with costs and capabilities
|
|
208
|
+
models:
|
|
209
|
+
cheap-fast:
|
|
210
|
+
provider: openai
|
|
211
|
+
complexity: [simple]
|
|
212
|
+
cost_per_1k: 0.0001
|
|
213
|
+
capabilities: [text]
|
|
214
|
+
context_window: 16000
|
|
215
|
+
|
|
216
|
+
balanced:
|
|
217
|
+
provider: openai
|
|
218
|
+
complexity: [moderate]
|
|
219
|
+
cost_per_1k: 0.001
|
|
220
|
+
capabilities: [text, function-calling]
|
|
221
|
+
context_window: 128000
|
|
222
|
+
|
|
223
|
+
premium:
|
|
224
|
+
provider: anthropic
|
|
225
|
+
complexity: [complex, very_complex]
|
|
226
|
+
cost_per_1k: 0.015
|
|
227
|
+
capabilities: [text, vision, function-calling]
|
|
228
|
+
context_window: 200000
|
|
229
|
+
strengths: [reasoning, analysis, code-generation]
|
|
230
|
+
|
|
231
|
+
workflow:
|
|
232
|
+
verbose: true
|
|
233
|
+
router: true # Enable model routing
|
|
234
|
+
routing_strategy: cost-optimized # Options: auto, cost-optimized, performance-optimized
|
|
235
|
+
|
|
236
|
+
agents:
|
|
237
|
+
classifier:
|
|
238
|
+
name: Classifier
|
|
239
|
+
role: Request Classifier
|
|
240
|
+
goal: Classify incoming requests by complexity
|
|
241
|
+
instructions: "Classify the request as 'simple', 'moderate', or 'complex'."
|
|
242
|
+
llm: cheap-fast # Always use cheap model for classification
|
|
243
|
+
|
|
244
|
+
researcher:
|
|
245
|
+
name: Researcher
|
|
246
|
+
role: Research Analyst
|
|
247
|
+
goal: Research topics thoroughly
|
|
248
|
+
instructions: "Research the topic and provide detailed findings."
|
|
249
|
+
llm_routing: auto # Auto-select based on task complexity
|
|
250
|
+
llm_models: [balanced, premium] # Models to choose from
|
|
251
|
+
|
|
252
|
+
writer:
|
|
253
|
+
name: Writer
|
|
254
|
+
role: Content Writer
|
|
255
|
+
goal: Write high-quality content
|
|
256
|
+
instructions: "Write clear, engaging content based on research."
|
|
257
|
+
llm: premium # Always use premium for quality writing
|
|
258
|
+
|
|
259
|
+
steps:
|
|
260
|
+
- agent: classifier
|
|
261
|
+
action: "Classify complexity of: {{input}}"
|
|
262
|
+
|
|
263
|
+
- name: routing
|
|
264
|
+
route:
|
|
265
|
+
simple: [researcher]
|
|
266
|
+
moderate: [researcher]
|
|
267
|
+
complex: [researcher, writer]
|
|
268
|
+
default: [researcher]
|
|
269
|
+
"""
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
def __init__(self, verbose: bool = False):
|
|
273
|
+
super().__init__(verbose)
|
|
274
|
+
self._manager = None
|
|
275
|
+
self._parser = None
|
|
276
|
+
|
|
277
|
+
@property
|
|
278
|
+
def feature_name(self) -> str:
|
|
279
|
+
return "workflow"
|
|
280
|
+
|
|
281
|
+
def get_actions(self) -> List[str]:
|
|
282
|
+
return ["run", "validate", "list", "create", "auto", "help"]
|
|
283
|
+
|
|
284
|
+
def get_help_text(self) -> str:
|
|
285
|
+
return """
|
|
286
|
+
Workflow Commands:
|
|
287
|
+
praisonai workflow run <file.yaml> - Run a YAML workflow
|
|
288
|
+
praisonai workflow run <file.yaml> --var key=value - Run with variables
|
|
289
|
+
praisonai workflow validate <file.yaml> - Validate a YAML workflow
|
|
290
|
+
praisonai workflow list - List workflows in .praison/workflows/
|
|
291
|
+
praisonai workflow create --template <name> - Create from template
|
|
292
|
+
praisonai workflow auto "topic" --pattern <pattern> - Auto-generate workflow
|
|
293
|
+
|
|
294
|
+
Templates: simple, routing, parallel, loop, evaluator-optimizer, model-routing
|
|
295
|
+
Patterns: sequential, routing, parallel
|
|
296
|
+
|
|
297
|
+
Example:
|
|
298
|
+
praisonai workflow run research.yaml --var topic="AI trends"
|
|
299
|
+
praisonai workflow create --template routing --output my_workflow.yaml
|
|
300
|
+
praisonai workflow auto "Research AI trends" --pattern parallel
|
|
301
|
+
"""
|
|
302
|
+
|
|
303
|
+
def _get_manager(self):
|
|
304
|
+
"""Get WorkflowManager lazily."""
|
|
305
|
+
if self._manager is None:
|
|
306
|
+
try:
|
|
307
|
+
from praisonaiagents.workflows import WorkflowManager
|
|
308
|
+
self._manager = WorkflowManager()
|
|
309
|
+
except ImportError:
|
|
310
|
+
self.print_status(
|
|
311
|
+
"Workflows require praisonaiagents. Install with: pip install praisonaiagents",
|
|
312
|
+
"error"
|
|
313
|
+
)
|
|
314
|
+
return None
|
|
315
|
+
return self._manager
|
|
316
|
+
|
|
317
|
+
def _get_parser(self):
|
|
318
|
+
"""Get YAMLWorkflowParser lazily."""
|
|
319
|
+
if self._parser is None:
|
|
320
|
+
try:
|
|
321
|
+
from praisonaiagents.workflows import YAMLWorkflowParser
|
|
322
|
+
self._parser = YAMLWorkflowParser()
|
|
323
|
+
except ImportError:
|
|
324
|
+
self.print_status(
|
|
325
|
+
"Workflows require praisonaiagents. Install with: pip install praisonaiagents",
|
|
326
|
+
"error"
|
|
327
|
+
)
|
|
328
|
+
return None
|
|
329
|
+
return self._parser
|
|
330
|
+
|
|
331
|
+
def _parse_variables(self, args: List[str]) -> Dict[str, Any]:
|
|
332
|
+
"""Parse --var key=value arguments."""
|
|
333
|
+
variables = {}
|
|
334
|
+
i = 0
|
|
335
|
+
while i < len(args):
|
|
336
|
+
if args[i] == "--var" and i + 1 < len(args):
|
|
337
|
+
var_str = args[i + 1]
|
|
338
|
+
if "=" in var_str:
|
|
339
|
+
key, value = var_str.split("=", 1)
|
|
340
|
+
variables[key.strip()] = value.strip()
|
|
341
|
+
i += 2
|
|
342
|
+
else:
|
|
343
|
+
i += 1
|
|
344
|
+
return variables
|
|
345
|
+
|
|
346
|
+
def _get_file_from_args(self, args: List[str]) -> Optional[str]:
|
|
347
|
+
"""Get the file path from arguments."""
|
|
348
|
+
for arg in args:
|
|
349
|
+
if arg.endswith(('.yaml', '.yml')) and not arg.startswith('--'):
|
|
350
|
+
return arg
|
|
351
|
+
return None
|
|
352
|
+
|
|
353
|
+
def action_run(self, args: List[str], **kwargs) -> Any:
|
|
354
|
+
"""
|
|
355
|
+
Run a YAML workflow file.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
args: [file.yaml, --var, key=value, ...]
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
Workflow execution result
|
|
362
|
+
"""
|
|
363
|
+
file_path = self._get_file_from_args(args)
|
|
364
|
+
if not file_path:
|
|
365
|
+
self.print_status("Usage: praisonai workflow run <file.yaml>", "error")
|
|
366
|
+
return None
|
|
367
|
+
|
|
368
|
+
if not os.path.exists(file_path):
|
|
369
|
+
self.print_status(f"File not found: {file_path}", "error")
|
|
370
|
+
return None
|
|
371
|
+
|
|
372
|
+
manager = self._get_manager()
|
|
373
|
+
if not manager:
|
|
374
|
+
return None
|
|
375
|
+
|
|
376
|
+
# Parse variables
|
|
377
|
+
variables = self._parse_variables(args)
|
|
378
|
+
|
|
379
|
+
# Get input if provided
|
|
380
|
+
input_data = kwargs.get('input', '')
|
|
381
|
+
|
|
382
|
+
# Check for --verbose flag
|
|
383
|
+
verbose = '--verbose' in args or '-v' in args
|
|
384
|
+
|
|
385
|
+
self.print_status(f"Running workflow: {file_path}", "info")
|
|
386
|
+
if variables:
|
|
387
|
+
self.print_status(f"Variables: {variables}", "info")
|
|
388
|
+
|
|
389
|
+
try:
|
|
390
|
+
result = manager.execute_yaml(
|
|
391
|
+
file_path,
|
|
392
|
+
input_data=input_data,
|
|
393
|
+
variables=variables,
|
|
394
|
+
verbose=verbose
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
self.print_status("Workflow completed!", "success")
|
|
398
|
+
|
|
399
|
+
# Print output
|
|
400
|
+
if result.get('output'):
|
|
401
|
+
from rich import print as rprint
|
|
402
|
+
rprint("\n[bold]Output:[/bold]")
|
|
403
|
+
rprint(result['output'])
|
|
404
|
+
|
|
405
|
+
return result
|
|
406
|
+
|
|
407
|
+
except Exception as e:
|
|
408
|
+
self.print_status(f"Workflow failed: {e}", "error")
|
|
409
|
+
return None
|
|
410
|
+
|
|
411
|
+
def action_validate(self, args: List[str], **kwargs) -> bool:
|
|
412
|
+
"""
|
|
413
|
+
Validate a YAML workflow file.
|
|
414
|
+
|
|
415
|
+
Args:
|
|
416
|
+
args: [file.yaml]
|
|
417
|
+
|
|
418
|
+
Returns:
|
|
419
|
+
True if valid, False otherwise
|
|
420
|
+
"""
|
|
421
|
+
file_path = self._get_file_from_args(args)
|
|
422
|
+
if not file_path:
|
|
423
|
+
self.print_status("Usage: praisonai workflow validate <file.yaml>", "error")
|
|
424
|
+
return False
|
|
425
|
+
|
|
426
|
+
if not os.path.exists(file_path):
|
|
427
|
+
self.print_status(f"File not found: {file_path}", "error")
|
|
428
|
+
return False
|
|
429
|
+
|
|
430
|
+
parser = self._get_parser()
|
|
431
|
+
if not parser:
|
|
432
|
+
return False
|
|
433
|
+
|
|
434
|
+
self.print_status(f"Validating: {file_path}", "info")
|
|
435
|
+
|
|
436
|
+
try:
|
|
437
|
+
# Load raw YAML to check for non-canonical names
|
|
438
|
+
import yaml
|
|
439
|
+
with open(file_path, 'r') as f:
|
|
440
|
+
raw_data = yaml.safe_load(f)
|
|
441
|
+
|
|
442
|
+
# Check for non-canonical names and suggest canonical ones
|
|
443
|
+
suggestions = self._get_canonical_suggestions(raw_data)
|
|
444
|
+
|
|
445
|
+
workflow = parser.parse_file(file_path)
|
|
446
|
+
|
|
447
|
+
# Print validation results
|
|
448
|
+
from rich import print as rprint
|
|
449
|
+
from rich.table import Table
|
|
450
|
+
|
|
451
|
+
table = Table(title="Workflow Validation")
|
|
452
|
+
table.add_column("Property", style="cyan")
|
|
453
|
+
table.add_column("Value", style="green")
|
|
454
|
+
|
|
455
|
+
table.add_row("Name", workflow.name)
|
|
456
|
+
table.add_row("Description", getattr(workflow, 'description', 'N/A'))
|
|
457
|
+
table.add_row("Steps", str(len(workflow.steps)))
|
|
458
|
+
table.add_row("Variables", str(len(workflow.variables)))
|
|
459
|
+
table.add_row("Planning", str(workflow.planning))
|
|
460
|
+
table.add_row("Reasoning", str(workflow.reasoning))
|
|
461
|
+
|
|
462
|
+
rprint(table)
|
|
463
|
+
self.print_status("✓ Workflow is valid!", "success")
|
|
464
|
+
|
|
465
|
+
# Show suggestions for canonical names
|
|
466
|
+
if suggestions:
|
|
467
|
+
rprint()
|
|
468
|
+
rprint("[yellow]💡 Suggestions for canonical field names:[/yellow]")
|
|
469
|
+
for suggestion in suggestions:
|
|
470
|
+
rprint(f" [dim]•[/dim] {suggestion}")
|
|
471
|
+
rprint()
|
|
472
|
+
rprint("[dim]Note: Both old and new names work, but canonical names are recommended.[/dim]")
|
|
473
|
+
|
|
474
|
+
return True
|
|
475
|
+
|
|
476
|
+
except Exception as e:
|
|
477
|
+
self.print_status(f"✗ Validation failed: {e}", "error")
|
|
478
|
+
return False
|
|
479
|
+
|
|
480
|
+
def _get_canonical_suggestions(self, data: Dict) -> List[str]:
|
|
481
|
+
"""
|
|
482
|
+
Check for non-canonical field names and return suggestions.
|
|
483
|
+
|
|
484
|
+
Canonical names (A-I-G-S mnemonic):
|
|
485
|
+
- Agents (not roles)
|
|
486
|
+
- Instructions (not backstory)
|
|
487
|
+
- Goal (same)
|
|
488
|
+
- Steps (not tasks)
|
|
489
|
+
|
|
490
|
+
Also:
|
|
491
|
+
- name (not topic)
|
|
492
|
+
- action (not description)
|
|
493
|
+
|
|
494
|
+
Args:
|
|
495
|
+
data: Raw YAML data
|
|
496
|
+
|
|
497
|
+
Returns:
|
|
498
|
+
List of suggestion strings
|
|
499
|
+
"""
|
|
500
|
+
suggestions = []
|
|
501
|
+
|
|
502
|
+
if not data:
|
|
503
|
+
return suggestions
|
|
504
|
+
|
|
505
|
+
# Check top-level keys
|
|
506
|
+
if 'roles' in data:
|
|
507
|
+
suggestions.append("Use 'agents' instead of 'roles'")
|
|
508
|
+
|
|
509
|
+
if 'topic' in data and 'name' not in data:
|
|
510
|
+
suggestions.append("Use 'name' instead of 'topic'")
|
|
511
|
+
|
|
512
|
+
# Check agent fields
|
|
513
|
+
agents_data = data.get('agents', data.get('roles', {}))
|
|
514
|
+
for agent_id, agent_config in agents_data.items():
|
|
515
|
+
if isinstance(agent_config, dict):
|
|
516
|
+
if 'backstory' in agent_config:
|
|
517
|
+
suggestions.append(f"Agent '{agent_id}': Use 'instructions' instead of 'backstory'")
|
|
518
|
+
|
|
519
|
+
# Check nested tasks
|
|
520
|
+
if 'tasks' in agent_config:
|
|
521
|
+
suggestions.append(f"Agent '{agent_id}': Use 'steps' at top level instead of nested 'tasks'")
|
|
522
|
+
|
|
523
|
+
# Check step fields
|
|
524
|
+
steps_data = data.get('steps', [])
|
|
525
|
+
for i, step in enumerate(steps_data):
|
|
526
|
+
if isinstance(step, dict):
|
|
527
|
+
if 'description' in step and 'action' not in step:
|
|
528
|
+
step_name = step.get('name', f'step {i+1}')
|
|
529
|
+
suggestions.append(f"Step '{step_name}': Use 'action' instead of 'description'")
|
|
530
|
+
|
|
531
|
+
# Check parallel steps
|
|
532
|
+
if 'parallel' in step:
|
|
533
|
+
for j, parallel_step in enumerate(step['parallel']):
|
|
534
|
+
if isinstance(parallel_step, dict):
|
|
535
|
+
if 'description' in parallel_step and 'action' not in parallel_step:
|
|
536
|
+
suggestions.append(f"Parallel step {j+1}: Use 'action' instead of 'description'")
|
|
537
|
+
|
|
538
|
+
return suggestions
|
|
539
|
+
|
|
540
|
+
def action_list(self, args: List[str], **kwargs) -> List[str]:
|
|
541
|
+
"""
|
|
542
|
+
List available workflows in .praison/workflows/ directory.
|
|
543
|
+
|
|
544
|
+
Returns:
|
|
545
|
+
List of workflow file names
|
|
546
|
+
"""
|
|
547
|
+
workflows_dir = Path(".praison/workflows")
|
|
548
|
+
|
|
549
|
+
if not workflows_dir.exists():
|
|
550
|
+
self.print_status("No .praison/workflows/ directory found", "warning")
|
|
551
|
+
self.print_status("Create one with: mkdir -p .praison/workflows", "info")
|
|
552
|
+
return []
|
|
553
|
+
|
|
554
|
+
# Find all YAML files
|
|
555
|
+
yaml_files = list(workflows_dir.glob("*.yaml")) + list(workflows_dir.glob("*.yml"))
|
|
556
|
+
|
|
557
|
+
if not yaml_files:
|
|
558
|
+
self.print_status("No workflow files found in .praison/workflows/", "warning")
|
|
559
|
+
return []
|
|
560
|
+
|
|
561
|
+
from rich import print as rprint
|
|
562
|
+
from rich.table import Table
|
|
563
|
+
|
|
564
|
+
table = Table(title="Available Workflows")
|
|
565
|
+
table.add_column("File", style="cyan")
|
|
566
|
+
table.add_column("Name", style="green")
|
|
567
|
+
table.add_column("Steps", style="yellow")
|
|
568
|
+
|
|
569
|
+
parser = self._get_parser()
|
|
570
|
+
workflow_names = []
|
|
571
|
+
|
|
572
|
+
for yaml_file in yaml_files:
|
|
573
|
+
try:
|
|
574
|
+
if parser:
|
|
575
|
+
workflow = parser.parse_file(yaml_file)
|
|
576
|
+
table.add_row(
|
|
577
|
+
yaml_file.name,
|
|
578
|
+
workflow.name,
|
|
579
|
+
str(len(workflow.steps))
|
|
580
|
+
)
|
|
581
|
+
else:
|
|
582
|
+
table.add_row(yaml_file.name, "N/A", "N/A")
|
|
583
|
+
workflow_names.append(yaml_file.name)
|
|
584
|
+
except Exception as e:
|
|
585
|
+
table.add_row(yaml_file.name, f"Error: {e}", "N/A")
|
|
586
|
+
|
|
587
|
+
rprint(table)
|
|
588
|
+
return workflow_names
|
|
589
|
+
|
|
590
|
+
def action_create(self, args: List[str], **kwargs) -> Optional[str]:
|
|
591
|
+
"""
|
|
592
|
+
Create a workflow from a template.
|
|
593
|
+
|
|
594
|
+
Args:
|
|
595
|
+
args: [--template, <name>, --output, <file.yaml>]
|
|
596
|
+
|
|
597
|
+
Returns:
|
|
598
|
+
Path to created file
|
|
599
|
+
"""
|
|
600
|
+
# Parse arguments
|
|
601
|
+
template_name = None
|
|
602
|
+
output_file = None
|
|
603
|
+
|
|
604
|
+
i = 0
|
|
605
|
+
while i < len(args):
|
|
606
|
+
if args[i] == "--template" and i + 1 < len(args):
|
|
607
|
+
template_name = args[i + 1]
|
|
608
|
+
i += 2
|
|
609
|
+
elif args[i] == "--output" and i + 1 < len(args):
|
|
610
|
+
output_file = args[i + 1]
|
|
611
|
+
i += 2
|
|
612
|
+
else:
|
|
613
|
+
i += 1
|
|
614
|
+
|
|
615
|
+
if not template_name:
|
|
616
|
+
self.print_status("Usage: praisonai workflow create --template <name>", "error")
|
|
617
|
+
self.print_status(f"Available templates: {', '.join(self.TEMPLATES.keys())}", "info")
|
|
618
|
+
return None
|
|
619
|
+
|
|
620
|
+
if template_name not in self.TEMPLATES:
|
|
621
|
+
self.print_status(f"Unknown template: {template_name}", "error")
|
|
622
|
+
self.print_status(f"Available templates: {', '.join(self.TEMPLATES.keys())}", "info")
|
|
623
|
+
return None
|
|
624
|
+
|
|
625
|
+
# Default output file
|
|
626
|
+
if not output_file:
|
|
627
|
+
output_file = f"{template_name}_workflow.yaml"
|
|
628
|
+
|
|
629
|
+
# Check if file exists
|
|
630
|
+
if os.path.exists(output_file):
|
|
631
|
+
self.print_status(f"File already exists: {output_file}", "error")
|
|
632
|
+
return None
|
|
633
|
+
|
|
634
|
+
# Write template
|
|
635
|
+
template_content = self.TEMPLATES[template_name]
|
|
636
|
+
|
|
637
|
+
with open(output_file, 'w') as f:
|
|
638
|
+
f.write(template_content)
|
|
639
|
+
|
|
640
|
+
self.print_status(f"✓ Created workflow: {output_file}", "success")
|
|
641
|
+
self.print_status(f"Run with: praisonai workflow run {output_file}", "info")
|
|
642
|
+
|
|
643
|
+
return output_file
|
|
644
|
+
|
|
645
|
+
def action_auto(self, args: List[str], **kwargs) -> Optional[str]:
|
|
646
|
+
"""
|
|
647
|
+
Auto-generate a workflow from a topic description.
|
|
648
|
+
|
|
649
|
+
Args:
|
|
650
|
+
args: ["topic description", --pattern, <pattern>, --output, <file.yaml>]
|
|
651
|
+
|
|
652
|
+
Returns:
|
|
653
|
+
Path to created file
|
|
654
|
+
"""
|
|
655
|
+
# Parse arguments
|
|
656
|
+
topic = None
|
|
657
|
+
pattern = "sequential"
|
|
658
|
+
output_file = None
|
|
659
|
+
|
|
660
|
+
i = 0
|
|
661
|
+
while i < len(args):
|
|
662
|
+
if args[i] == "--pattern" and i + 1 < len(args):
|
|
663
|
+
pattern = args[i + 1]
|
|
664
|
+
i += 2
|
|
665
|
+
elif args[i] == "--output" and i + 1 < len(args):
|
|
666
|
+
output_file = args[i + 1]
|
|
667
|
+
i += 2
|
|
668
|
+
elif not args[i].startswith("--") and topic is None:
|
|
669
|
+
topic = args[i]
|
|
670
|
+
i += 1
|
|
671
|
+
else:
|
|
672
|
+
i += 1
|
|
673
|
+
|
|
674
|
+
if not topic:
|
|
675
|
+
self.print_status('Usage: praisonai workflow auto "topic" --pattern <pattern>', "error")
|
|
676
|
+
self.print_status("Patterns: sequential, routing, parallel", "info")
|
|
677
|
+
return None
|
|
678
|
+
|
|
679
|
+
# Validate pattern
|
|
680
|
+
valid_patterns = ["sequential", "routing", "parallel", "loop", "orchestrator-workers", "evaluator-optimizer"]
|
|
681
|
+
if pattern not in valid_patterns:
|
|
682
|
+
self.print_status(f"Unknown pattern: {pattern}", "error")
|
|
683
|
+
self.print_status(f"Valid patterns: {', '.join(valid_patterns)}", "info")
|
|
684
|
+
return None
|
|
685
|
+
|
|
686
|
+
# Default output file
|
|
687
|
+
if not output_file:
|
|
688
|
+
# Create safe filename from topic
|
|
689
|
+
safe_name = "".join(c if c.isalnum() else "_" for c in topic[:30]).lower()
|
|
690
|
+
output_file = f"{safe_name}_workflow.yaml"
|
|
691
|
+
|
|
692
|
+
# Check if file exists
|
|
693
|
+
if os.path.exists(output_file):
|
|
694
|
+
self.print_status(f"File already exists: {output_file}", "error")
|
|
695
|
+
return None
|
|
696
|
+
|
|
697
|
+
self.print_status(f"Generating {pattern} workflow for: {topic}", "info")
|
|
698
|
+
|
|
699
|
+
try:
|
|
700
|
+
# Lazy import to avoid performance impact
|
|
701
|
+
from praisonai.auto import WorkflowAutoGenerator
|
|
702
|
+
|
|
703
|
+
generator = WorkflowAutoGenerator(
|
|
704
|
+
topic=topic,
|
|
705
|
+
workflow_file=output_file
|
|
706
|
+
)
|
|
707
|
+
|
|
708
|
+
result_path = generator.generate(pattern=pattern)
|
|
709
|
+
|
|
710
|
+
self.print_status(f"✓ Created workflow: {result_path}", "success")
|
|
711
|
+
self.print_status(f"Run with: praisonai workflow run {output_file}", "info")
|
|
712
|
+
|
|
713
|
+
return result_path
|
|
714
|
+
|
|
715
|
+
except ImportError:
|
|
716
|
+
self.print_status("Auto-generation requires instructor: pip install instructor", "error")
|
|
717
|
+
return None
|
|
718
|
+
except Exception as e:
|
|
719
|
+
self.print_status(f"Generation failed: {e}", "error")
|
|
720
|
+
return None
|