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,466 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Router Handler for CLI.
|
|
3
|
+
|
|
4
|
+
Provides smart model selection based on task complexity.
|
|
5
|
+
Usage: praisonai "Complex task" --router
|
|
6
|
+
|
|
7
|
+
Supports custom model configuration from agents.yaml/workflow.yaml:
|
|
8
|
+
|
|
9
|
+
models:
|
|
10
|
+
gpt-4o-mini:
|
|
11
|
+
provider: openai
|
|
12
|
+
complexity: [simple, moderate]
|
|
13
|
+
cost_per_1k: 0.00075
|
|
14
|
+
capabilities: [text, function-calling]
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from enum import IntEnum
|
|
20
|
+
from .base import FlagHandler
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TaskComplexity(IntEnum):
|
|
24
|
+
"""Enum for task complexity levels."""
|
|
25
|
+
SIMPLE = 1
|
|
26
|
+
MODERATE = 2
|
|
27
|
+
COMPLEX = 3
|
|
28
|
+
VERY_COMPLEX = 4
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class ModelProfile:
|
|
33
|
+
"""Profile for an LLM model with its characteristics."""
|
|
34
|
+
name: str
|
|
35
|
+
provider: str
|
|
36
|
+
complexity_range: Tuple[TaskComplexity, TaskComplexity]
|
|
37
|
+
cost_per_1k_tokens: float
|
|
38
|
+
capabilities: List[str]
|
|
39
|
+
context_window: int = 128000
|
|
40
|
+
supports_tools: bool = True
|
|
41
|
+
supports_streaming: bool = True
|
|
42
|
+
strengths: Optional[List[str]] = None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class RouterHandler(FlagHandler):
|
|
46
|
+
"""
|
|
47
|
+
Handler for --router flag.
|
|
48
|
+
|
|
49
|
+
Automatically selects the best model based on task complexity.
|
|
50
|
+
|
|
51
|
+
Example:
|
|
52
|
+
praisonai "Simple question" --router
|
|
53
|
+
praisonai "Complex analysis" --router
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
# Default model tiers for routing (used when no custom models configured)
|
|
57
|
+
# Note: Use full model names for API compatibility
|
|
58
|
+
DEFAULT_MODEL_TIERS = {
|
|
59
|
+
'simple': ['gpt-4o-mini', 'anthropic/claude-3-haiku-20240307', 'gemini/gemini-1.5-flash'],
|
|
60
|
+
'medium': ['gpt-4o', 'anthropic/claude-3-5-sonnet-20241022', 'gemini/gemini-1.5-pro'],
|
|
61
|
+
'complex': ['gpt-4-turbo', 'anthropic/claude-3-opus-20240229', 'o1-preview'],
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Default model profiles
|
|
65
|
+
DEFAULT_MODELS: List[ModelProfile] = [
|
|
66
|
+
ModelProfile(
|
|
67
|
+
name="gpt-4o-mini",
|
|
68
|
+
provider="openai",
|
|
69
|
+
complexity_range=(TaskComplexity.SIMPLE, TaskComplexity.MODERATE),
|
|
70
|
+
cost_per_1k_tokens=0.00075,
|
|
71
|
+
capabilities=["text", "function-calling"],
|
|
72
|
+
context_window=128000
|
|
73
|
+
),
|
|
74
|
+
ModelProfile(
|
|
75
|
+
name="gpt-4o",
|
|
76
|
+
provider="openai",
|
|
77
|
+
complexity_range=(TaskComplexity.MODERATE, TaskComplexity.COMPLEX),
|
|
78
|
+
cost_per_1k_tokens=0.0075,
|
|
79
|
+
capabilities=["text", "vision", "function-calling"],
|
|
80
|
+
context_window=128000
|
|
81
|
+
),
|
|
82
|
+
ModelProfile(
|
|
83
|
+
name="anthropic/claude-3-haiku-20240307",
|
|
84
|
+
provider="anthropic",
|
|
85
|
+
complexity_range=(TaskComplexity.SIMPLE, TaskComplexity.MODERATE),
|
|
86
|
+
cost_per_1k_tokens=0.0008,
|
|
87
|
+
capabilities=["text", "function-calling"],
|
|
88
|
+
context_window=200000
|
|
89
|
+
),
|
|
90
|
+
ModelProfile(
|
|
91
|
+
name="anthropic/claude-3-5-sonnet-20241022",
|
|
92
|
+
provider="anthropic",
|
|
93
|
+
complexity_range=(TaskComplexity.MODERATE, TaskComplexity.VERY_COMPLEX),
|
|
94
|
+
cost_per_1k_tokens=0.009,
|
|
95
|
+
capabilities=["text", "vision", "function-calling"],
|
|
96
|
+
context_window=200000,
|
|
97
|
+
strengths=["reasoning", "code-generation", "analysis"]
|
|
98
|
+
),
|
|
99
|
+
ModelProfile(
|
|
100
|
+
name="gemini/gemini-1.5-flash",
|
|
101
|
+
provider="google",
|
|
102
|
+
complexity_range=(TaskComplexity.SIMPLE, TaskComplexity.MODERATE),
|
|
103
|
+
cost_per_1k_tokens=0.000125,
|
|
104
|
+
capabilities=["text", "vision", "function-calling"],
|
|
105
|
+
context_window=1048576
|
|
106
|
+
),
|
|
107
|
+
ModelProfile(
|
|
108
|
+
name="gemini/gemini-1.5-pro",
|
|
109
|
+
provider="google",
|
|
110
|
+
complexity_range=(TaskComplexity.COMPLEX, TaskComplexity.VERY_COMPLEX),
|
|
111
|
+
cost_per_1k_tokens=0.00625,
|
|
112
|
+
capabilities=["text", "vision", "function-calling"],
|
|
113
|
+
context_window=2097152
|
|
114
|
+
),
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
def __init__(self, verbose: bool = False):
|
|
118
|
+
"""Initialize RouterHandler with model routing support."""
|
|
119
|
+
super().__init__(verbose=verbose)
|
|
120
|
+
self._model_router: Optional[List[ModelProfile]] = None
|
|
121
|
+
self._custom_models: Dict[str, ModelProfile] = {}
|
|
122
|
+
self._cost_threshold: Optional[float] = None
|
|
123
|
+
self._model_tiers = self.DEFAULT_MODEL_TIERS.copy()
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def model_router(self) -> List[ModelProfile]:
|
|
127
|
+
"""Get the list of available model profiles."""
|
|
128
|
+
if self._model_router is None:
|
|
129
|
+
return self.DEFAULT_MODELS.copy()
|
|
130
|
+
return self._model_router
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def feature_name(self) -> str:
|
|
134
|
+
return "router"
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def flag_name(self) -> str:
|
|
138
|
+
return "router"
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def flag_help(self) -> str:
|
|
142
|
+
return "Auto-select best model based on task complexity"
|
|
143
|
+
|
|
144
|
+
def check_dependencies(self) -> Tuple[bool, str]:
|
|
145
|
+
"""Router is built-in, always available."""
|
|
146
|
+
return True, ""
|
|
147
|
+
|
|
148
|
+
def analyze_complexity(self, prompt: str) -> str:
|
|
149
|
+
"""
|
|
150
|
+
Analyze prompt complexity.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
prompt: The task prompt
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Complexity level: 'simple', 'medium', or 'complex'
|
|
157
|
+
"""
|
|
158
|
+
# Simple heuristics for complexity
|
|
159
|
+
prompt_lower = prompt.lower()
|
|
160
|
+
word_count = len(prompt.split())
|
|
161
|
+
|
|
162
|
+
# Complex indicators
|
|
163
|
+
complex_keywords = [
|
|
164
|
+
'analyze', 'research', 'comprehensive', 'detailed',
|
|
165
|
+
'compare', 'evaluate', 'synthesize', 'multi-step',
|
|
166
|
+
'code review', 'architecture', 'design pattern',
|
|
167
|
+
'optimize', 'debug', 'refactor'
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
# Simple indicators
|
|
171
|
+
simple_keywords = [
|
|
172
|
+
'what is', 'define', 'list', 'name', 'when',
|
|
173
|
+
'where', 'who', 'simple', 'quick', 'brief'
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
complex_count = sum(1 for kw in complex_keywords if kw in prompt_lower)
|
|
177
|
+
simple_count = sum(1 for kw in simple_keywords if kw in prompt_lower)
|
|
178
|
+
|
|
179
|
+
# Determine complexity
|
|
180
|
+
if complex_count >= 2 or word_count > 100:
|
|
181
|
+
return 'complex'
|
|
182
|
+
elif simple_count >= 2 or word_count < 20:
|
|
183
|
+
return 'simple'
|
|
184
|
+
else:
|
|
185
|
+
return 'medium'
|
|
186
|
+
|
|
187
|
+
def select_model(self, prompt: str, preferred_provider: str = None) -> str:
|
|
188
|
+
"""
|
|
189
|
+
Select the best model for the prompt.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
prompt: The task prompt
|
|
193
|
+
preferred_provider: Optional preferred provider (openai, anthropic, google)
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
Selected model name
|
|
197
|
+
"""
|
|
198
|
+
complexity = self.analyze_complexity(prompt)
|
|
199
|
+
|
|
200
|
+
# If custom models are loaded, use ModelProfile-based selection
|
|
201
|
+
if self._custom_models:
|
|
202
|
+
return self._select_from_profiles(prompt, complexity, preferred_provider)
|
|
203
|
+
|
|
204
|
+
# Otherwise use tier-based selection
|
|
205
|
+
models = self._model_tiers.get(complexity, self._model_tiers['medium'])
|
|
206
|
+
|
|
207
|
+
# Filter by provider if specified
|
|
208
|
+
if preferred_provider:
|
|
209
|
+
provider_prefixes = {
|
|
210
|
+
'openai': ['gpt-', 'o1-'],
|
|
211
|
+
'anthropic': ['anthropic/', 'claude-'],
|
|
212
|
+
'google': ['gemini/', 'gemini-']
|
|
213
|
+
}
|
|
214
|
+
prefixes = provider_prefixes.get(preferred_provider.lower(), [])
|
|
215
|
+
filtered = [m for m in models if any(p in m for p in prefixes)]
|
|
216
|
+
if filtered:
|
|
217
|
+
models = filtered
|
|
218
|
+
|
|
219
|
+
# Apply cost threshold if set
|
|
220
|
+
if self._cost_threshold:
|
|
221
|
+
filtered = [m for m in models if self.get_model_cost(m) <= self._cost_threshold]
|
|
222
|
+
if filtered:
|
|
223
|
+
models = filtered
|
|
224
|
+
|
|
225
|
+
selected = models[0] if models else 'gpt-4o-mini'
|
|
226
|
+
|
|
227
|
+
self.print_status(f"🎯 Task complexity: {complexity}", "info")
|
|
228
|
+
self.print_status(f"🤖 Selected model: {selected}", "success")
|
|
229
|
+
|
|
230
|
+
return selected
|
|
231
|
+
|
|
232
|
+
def _select_from_profiles(
|
|
233
|
+
self,
|
|
234
|
+
prompt: str,
|
|
235
|
+
complexity: str,
|
|
236
|
+
preferred_provider: str = None
|
|
237
|
+
) -> str:
|
|
238
|
+
"""Select model from custom ModelProfile objects."""
|
|
239
|
+
# Map string complexity to TaskComplexity enum
|
|
240
|
+
complexity_map = {
|
|
241
|
+
'simple': TaskComplexity.SIMPLE,
|
|
242
|
+
'medium': TaskComplexity.MODERATE,
|
|
243
|
+
'complex': TaskComplexity.COMPLEX,
|
|
244
|
+
}
|
|
245
|
+
task_complexity = complexity_map.get(complexity, TaskComplexity.MODERATE)
|
|
246
|
+
|
|
247
|
+
# Get all models that support this complexity level
|
|
248
|
+
candidates = []
|
|
249
|
+
for name, profile in self._custom_models.items():
|
|
250
|
+
min_c, max_c = profile.complexity_range
|
|
251
|
+
if min_c.value <= task_complexity.value <= max_c.value:
|
|
252
|
+
candidates.append(profile)
|
|
253
|
+
|
|
254
|
+
if not candidates:
|
|
255
|
+
return 'gpt-4o-mini'
|
|
256
|
+
|
|
257
|
+
# Filter by provider if specified
|
|
258
|
+
if preferred_provider:
|
|
259
|
+
filtered = [m for m in candidates if m.provider == preferred_provider]
|
|
260
|
+
if filtered:
|
|
261
|
+
candidates = filtered
|
|
262
|
+
|
|
263
|
+
# Filter by cost threshold if set
|
|
264
|
+
if self._cost_threshold:
|
|
265
|
+
filtered = [m for m in candidates if m.cost_per_1k_tokens <= self._cost_threshold]
|
|
266
|
+
if filtered:
|
|
267
|
+
candidates = filtered
|
|
268
|
+
|
|
269
|
+
# Sort by cost (cheapest first)
|
|
270
|
+
candidates.sort(key=lambda m: m.cost_per_1k_tokens)
|
|
271
|
+
|
|
272
|
+
return candidates[0].name if candidates else 'gpt-4o-mini'
|
|
273
|
+
|
|
274
|
+
def apply_to_agent_config(self, config: Dict[str, Any], flag_value: Any) -> Dict[str, Any]:
|
|
275
|
+
"""
|
|
276
|
+
Apply router configuration.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
config: Agent configuration dictionary
|
|
280
|
+
flag_value: Boolean or dict with provider preference
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
Modified configuration with selected model
|
|
284
|
+
"""
|
|
285
|
+
if not flag_value:
|
|
286
|
+
return config
|
|
287
|
+
|
|
288
|
+
# Get prompt from config if available
|
|
289
|
+
prompt = config.get('prompt', config.get('goal', ''))
|
|
290
|
+
|
|
291
|
+
preferred_provider = None
|
|
292
|
+
if isinstance(flag_value, dict):
|
|
293
|
+
preferred_provider = flag_value.get('provider')
|
|
294
|
+
|
|
295
|
+
if prompt:
|
|
296
|
+
selected_model = self.select_model(prompt, preferred_provider)
|
|
297
|
+
config['llm'] = selected_model
|
|
298
|
+
|
|
299
|
+
config['use_router'] = True
|
|
300
|
+
return config
|
|
301
|
+
|
|
302
|
+
def execute(self, prompt: str = None, provider: str = None, **kwargs) -> str:
|
|
303
|
+
"""
|
|
304
|
+
Execute model selection.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
prompt: Task prompt
|
|
308
|
+
provider: Preferred provider
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
Selected model name
|
|
312
|
+
"""
|
|
313
|
+
if not prompt:
|
|
314
|
+
return 'gpt-4o-mini' # Default
|
|
315
|
+
|
|
316
|
+
return self.select_model(prompt, provider)
|
|
317
|
+
|
|
318
|
+
# =========================================================================
|
|
319
|
+
# Custom Model Configuration Methods
|
|
320
|
+
# =========================================================================
|
|
321
|
+
|
|
322
|
+
def yaml_to_model_profile(self, name: str, config: Dict[str, Any]) -> ModelProfile:
|
|
323
|
+
"""
|
|
324
|
+
Convert YAML model configuration to ModelProfile object.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
name: Model name
|
|
328
|
+
config: Model configuration from YAML
|
|
329
|
+
|
|
330
|
+
Returns:
|
|
331
|
+
ModelProfile object
|
|
332
|
+
"""
|
|
333
|
+
# Parse complexity strings to TaskComplexity enum
|
|
334
|
+
complexity_list = config.get('complexity', ['moderate'])
|
|
335
|
+
complexity_map = {
|
|
336
|
+
'simple': TaskComplexity.SIMPLE,
|
|
337
|
+
'moderate': TaskComplexity.MODERATE,
|
|
338
|
+
'complex': TaskComplexity.COMPLEX,
|
|
339
|
+
'very_complex': TaskComplexity.VERY_COMPLEX,
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
complexities = [complexity_map.get(c.lower(), TaskComplexity.MODERATE) for c in complexity_list]
|
|
343
|
+
min_complexity = min(complexities, key=lambda x: x.value)
|
|
344
|
+
max_complexity = max(complexities, key=lambda x: x.value)
|
|
345
|
+
|
|
346
|
+
return ModelProfile(
|
|
347
|
+
name=name,
|
|
348
|
+
provider=config.get('provider', 'unknown'),
|
|
349
|
+
complexity_range=(min_complexity, max_complexity),
|
|
350
|
+
cost_per_1k_tokens=config.get('cost_per_1k', 0.001),
|
|
351
|
+
capabilities=config.get('capabilities', ['text']),
|
|
352
|
+
context_window=config.get('context_window', 128000),
|
|
353
|
+
supports_tools=config.get('supports_tools', True),
|
|
354
|
+
supports_streaming=config.get('supports_streaming', True),
|
|
355
|
+
strengths=config.get('strengths', None)
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
def load_models_from_config(
|
|
359
|
+
self,
|
|
360
|
+
models_config: Dict[str, Dict[str, Any]],
|
|
361
|
+
merge_with_defaults: bool = False
|
|
362
|
+
) -> None:
|
|
363
|
+
"""
|
|
364
|
+
Load custom models from YAML configuration.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
models_config: Dictionary of model configurations from YAML
|
|
368
|
+
merge_with_defaults: If True, merge with default models
|
|
369
|
+
"""
|
|
370
|
+
# Start with defaults if merging
|
|
371
|
+
if merge_with_defaults:
|
|
372
|
+
for profile in self.DEFAULT_MODELS:
|
|
373
|
+
self._custom_models[profile.name] = profile
|
|
374
|
+
|
|
375
|
+
# Add custom models
|
|
376
|
+
for name, config in models_config.items():
|
|
377
|
+
profile = self.yaml_to_model_profile(name, config)
|
|
378
|
+
self._custom_models[name] = profile
|
|
379
|
+
|
|
380
|
+
# Rebuild model tiers from profiles
|
|
381
|
+
self._rebuild_model_tiers()
|
|
382
|
+
|
|
383
|
+
def _rebuild_model_tiers(self) -> None:
|
|
384
|
+
"""Rebuild MODEL_TIERS from custom model profiles."""
|
|
385
|
+
self._model_tiers = {
|
|
386
|
+
'simple': [],
|
|
387
|
+
'medium': [],
|
|
388
|
+
'complex': [],
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
for name, profile in self._custom_models.items():
|
|
392
|
+
min_c, max_c = profile.complexity_range
|
|
393
|
+
|
|
394
|
+
if min_c.value <= TaskComplexity.SIMPLE.value <= max_c.value:
|
|
395
|
+
self._model_tiers['simple'].append(name)
|
|
396
|
+
if min_c.value <= TaskComplexity.MODERATE.value <= max_c.value:
|
|
397
|
+
self._model_tiers['medium'].append(name)
|
|
398
|
+
if min_c.value <= TaskComplexity.COMPLEX.value <= max_c.value:
|
|
399
|
+
self._model_tiers['complex'].append(name)
|
|
400
|
+
|
|
401
|
+
# Sort by cost (cheapest first)
|
|
402
|
+
for tier in self._model_tiers:
|
|
403
|
+
self._model_tiers[tier].sort(
|
|
404
|
+
key=lambda n: self._custom_models[n].cost_per_1k_tokens
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
def get_available_models(self) -> List[str]:
|
|
408
|
+
"""
|
|
409
|
+
Get list of available model names.
|
|
410
|
+
|
|
411
|
+
Returns:
|
|
412
|
+
List of model names
|
|
413
|
+
"""
|
|
414
|
+
if self._custom_models:
|
|
415
|
+
return list(self._custom_models.keys())
|
|
416
|
+
return [p.name for p in self.DEFAULT_MODELS]
|
|
417
|
+
|
|
418
|
+
def get_model_cost(self, model_name: str) -> float:
|
|
419
|
+
"""
|
|
420
|
+
Get cost per 1k tokens for a model.
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
model_name: Name of the model
|
|
424
|
+
|
|
425
|
+
Returns:
|
|
426
|
+
Cost per 1k tokens
|
|
427
|
+
"""
|
|
428
|
+
# Check custom models first
|
|
429
|
+
if model_name in self._custom_models:
|
|
430
|
+
return self._custom_models[model_name].cost_per_1k_tokens
|
|
431
|
+
|
|
432
|
+
# Check default models
|
|
433
|
+
for profile in self.DEFAULT_MODELS:
|
|
434
|
+
if profile.name == model_name:
|
|
435
|
+
return profile.cost_per_1k_tokens
|
|
436
|
+
|
|
437
|
+
# Default cost for unknown models
|
|
438
|
+
return 0.01
|
|
439
|
+
|
|
440
|
+
def set_cost_threshold(self, threshold: float) -> None:
|
|
441
|
+
"""
|
|
442
|
+
Set maximum cost per 1k tokens for model selection.
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
threshold: Maximum cost per 1k tokens
|
|
446
|
+
"""
|
|
447
|
+
self._cost_threshold = threshold
|
|
448
|
+
|
|
449
|
+
def get_model_profile(self, model_name: str) -> Optional[ModelProfile]:
|
|
450
|
+
"""
|
|
451
|
+
Get ModelProfile for a model.
|
|
452
|
+
|
|
453
|
+
Args:
|
|
454
|
+
model_name: Name of the model
|
|
455
|
+
|
|
456
|
+
Returns:
|
|
457
|
+
ModelProfile or None if not found
|
|
458
|
+
"""
|
|
459
|
+
if model_name in self._custom_models:
|
|
460
|
+
return self._custom_models[model_name]
|
|
461
|
+
|
|
462
|
+
for profile in self.DEFAULT_MODELS:
|
|
463
|
+
if profile.name == model_name:
|
|
464
|
+
return profile
|
|
465
|
+
|
|
466
|
+
return None
|