praisonai-code 0.0.45__tar.gz → 0.0.46__tar.gz
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_code-0.0.45 → praisonai_code-0.0.46}/PKG-INFO +1 -1
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/__init__.py +1 -1
- praisonai_code-0.0.46/praisonai_code/_train_bridge.py +35 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/app.py +15 -2
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/auth.py +231 -31
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/setup/handler.py +116 -21
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/legacy/praison_ai.py +28 -17
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/llm/catalogue.py +43 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code.egg-info/PKG-INFO +1 -1
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code.egg-info/SOURCES.txt +1 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/pyproject.toml +1 -1
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/README.md +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/__main__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/_bot_bridge.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/_framework_availability.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/_logging.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/_registry.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/_safe_loader.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/_version.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/_wrapper_bridge.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/_forward_shim.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/_paths.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/_warnings.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/_wrapper_reexport.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/approval_backend.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/branding.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/acp.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/agent.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/agents.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/attach.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/benchmark.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/browser.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/call.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/chat.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/checkpoint.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/code.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/command.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/commit.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/completion.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/config.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/daemon.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/debug.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/deploy.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/diag.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/doctor.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/endpoints.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/environment.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/eval.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/github.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/hooks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/init.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/loop.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/lsp.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/memory.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/models.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/obs.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/package.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/paths.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/permissions.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/plugins.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/port.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/publish.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/registry.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/research.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/retrieval.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/rules.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/run.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/sandbox.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/serve.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/session.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/setup.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/skills.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/templates.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/test.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/todo.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/tools.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/traces.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/tracker.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/ui.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/uninstall.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/up.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/upgrade.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/version.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/commands/workflow.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/config_loader.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/config.schema.json +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/credentials.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/loader.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/model_resolver.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/oauth.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/paths.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/resolver.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/configuration/schema.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/execution/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/execution/core.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/execution/profiler.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/execution/request.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/execution/result.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/fallback_schema.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/_approval_bridge.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/_endpoint_registry.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/_search_registry.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/action_orchestrator.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/agents.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/at_mentions.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/audit_cli.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/auto_memory.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/auto_mode.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/autonomy_mode.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/base.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/benchmark.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/capabilities.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/checkpoints.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/cli_profiler.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/code_intelligence.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/compaction.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/compare.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/config_hierarchy.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/context_manager.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/cost_tracker.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/csv_test_runner.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/custom_definitions.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/debug.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/diag.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/display_jsonl.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/_wrapper_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/acp_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/bot_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/config_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/db_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/env_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/gateway_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/lsp_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/mcp_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/memory_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/network_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/obs_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/packaging_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/performance_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/permissions_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/runtime_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/runtime_migration_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/selftest_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/serve_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/skills_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/checks/tools_checks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/engine.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/formatters.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/handler.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/models.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/doctor/registry.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/endpoints.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/examples.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/external_agents.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/fast_context.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/file_history.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/flow_display.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/git_attribution.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/git_integration.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/guardrail.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/handoff.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/hooks.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/hybrid_workflow.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/image.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/interactive_core_headless.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/interactive_runtime.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/interactive_test_harness.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/interactive_tools.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/interactive_tui.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/job_workflow.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/jobs.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/knowledge.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/knowledge_cli.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/lite.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/logs.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/lsp_cli.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/lsp_diagnostics.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/mcp.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/message_queue.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/metrics.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/migrate.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/migration_flow.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/migration_spec.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/n8n.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/observability.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/output_modes.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/output_style.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/package.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/performance.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/profiler/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/profiler/core.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/profiler/optimizations.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/profiler/suite.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/manager.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/models.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/persistence.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/scheduler.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/queue/worker.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/recipe_creator.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/recipe_prompts.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/registry.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/repo_map.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/router.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/safe_shell.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/sandbox_executor.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/sdk_knowledge.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/self_manage.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/session.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/session_checkpoints.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/setup/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/setup/templates.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/skills.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/slash_commands.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/telemetry.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/thinking.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/todo.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tools.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/cli.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/config.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/debug.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/events.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/mock_provider.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/orchestrator.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/help.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/main.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/queue.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/session.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/screens/settings.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/session_store.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/chat.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/command_popup.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/composer.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/file_popup.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/queue_panel.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/status.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/tui/widgets/tool_panel.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/wizard.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/workflow.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/yaml_utils.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/help_categories.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/async_tui.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/command_registry.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/config.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/core.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/events.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/frontends/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/frontends/rich_frontend.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/frontends/textual_frontend.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/praison_io.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/repl.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/split_tui.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/interactive/tui_app.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/legacy/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/legacy/env_security.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/legacy/prompt_dispatch.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/main.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/output/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/output/console.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/output/event_bridge.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/schedule_cli.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/schema_provider.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/session/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/session/resume.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/session/unified.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/state/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/state/identifiers.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/state/project_sessions.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/state/sessions.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/ui/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/ui/config.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/ui/events.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/ui/mg_backend.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/ui/plain.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/ui/rich_backend.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/unified_schema.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/utils/env_utils.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/utils/project.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/utils/stdin.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli_backends/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli_backends/claude.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli_backends/registry.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/data/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/data/fixtures/interactive/multi_agent.csv +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/data/fixtures/interactive/refactor.csv +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/data/fixtures/interactive/smoke.csv +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/data/fixtures/interactive/tools.csv +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/llm/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/llm/config.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/llm/credentials.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/llm/env.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/runtime/__init__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/runtime/__main__.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/runtime/client.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/runtime/descriptor.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/runtime/server.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/tool_registry.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/tool_resolver.py +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code.egg-info/dependency_links.txt +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code.egg-info/entry_points.txt +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code.egg-info/requires.txt +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code.egg-info/top_level.txt +0 -0
- {praisonai_code-0.0.45 → praisonai_code-0.0.46}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: praisonai-code
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.46
|
|
4
4
|
Summary: Agentic terminal CLI for PraisonAI — the terminal-native agent (run, chat, code, runtime, cli backends) extracted from the praisonai wrapper.
|
|
5
5
|
Author: Mervin Praison
|
|
6
6
|
License: MIT
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Lazy access to ``praisonai-train`` from ``praisonai-code``."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib
|
|
6
|
+
from types import ModuleType
|
|
7
|
+
from typing import Any, TypeVar
|
|
8
|
+
|
|
9
|
+
T = TypeVar("T")
|
|
10
|
+
|
|
11
|
+
_INSTALL_HINT = "Install the training package: pip install praisonai-train"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def train_package_available() -> bool:
|
|
15
|
+
import importlib.util
|
|
16
|
+
|
|
17
|
+
return importlib.util.find_spec("praisonai_train") is not None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def import_train_module(name: str) -> ModuleType:
|
|
21
|
+
if not name.startswith("praisonai_train"):
|
|
22
|
+
raise ValueError(f"Expected praisonai_train module name, got {name!r}")
|
|
23
|
+
try:
|
|
24
|
+
return importlib.import_module(name)
|
|
25
|
+
except ImportError as exc:
|
|
26
|
+
raise ImportError(f"{name} requires praisonai-train. {_INSTALL_HINT}") from exc
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def optional_train_attr(module_name: str, attr: str, default: T | None = None) -> Any | T | None:
|
|
30
|
+
if not train_package_available():
|
|
31
|
+
return default
|
|
32
|
+
try:
|
|
33
|
+
return getattr(import_train_module(module_name), attr)
|
|
34
|
+
except (ImportError, AttributeError):
|
|
35
|
+
return default
|
|
@@ -264,8 +264,7 @@ _WRAPPER_RESIDENT_COMMANDS = frozenset({
|
|
|
264
264
|
"flow",
|
|
265
265
|
"n8n",
|
|
266
266
|
"replay",
|
|
267
|
-
# C8.2 Batch B —
|
|
268
|
-
"train",
|
|
267
|
+
# C8.2 Batch B — managed / examples (train extracted to praisonai-train in C10)
|
|
269
268
|
"managed",
|
|
270
269
|
"examples",
|
|
271
270
|
"standardise",
|
|
@@ -287,6 +286,13 @@ _WRAPPER_RESIDENT_COMMANDS = frozenset({
|
|
|
287
286
|
"validate",
|
|
288
287
|
})
|
|
289
288
|
|
|
289
|
+
# C10: Training commands implemented in ``praisonai_train.cli.commands.*``.
|
|
290
|
+
# ``get_command()`` loads them via ``praisonai_train.cli.commands.{name}`` when the
|
|
291
|
+
# train package is installed; standalone ``praisonai-code`` hides them from ``--help``.
|
|
292
|
+
_TRAIN_RESIDENT_COMMANDS = frozenset({
|
|
293
|
+
"train",
|
|
294
|
+
})
|
|
295
|
+
|
|
290
296
|
# Backward-compatible alias (C7.1 name).
|
|
291
297
|
_WRAPPER_COMMANDS = _WRAPPER_RESIDENT_COMMANDS
|
|
292
298
|
|
|
@@ -299,6 +305,7 @@ _SPECIAL_COMMANDS = {
|
|
|
299
305
|
|
|
300
306
|
from praisonai_code._wrapper_bridge import wrapper_available
|
|
301
307
|
from praisonai_code._bot_bridge import bot_package_available
|
|
308
|
+
from praisonai_code._train_bridge import train_package_available
|
|
302
309
|
|
|
303
310
|
|
|
304
311
|
class LazyCommandGroup(TyperGroup):
|
|
@@ -314,10 +321,12 @@ class LazyCommandGroup(TyperGroup):
|
|
|
314
321
|
# install does not surface commands it cannot resolve.
|
|
315
322
|
wrapper_ok = wrapper_available()
|
|
316
323
|
bot_ok = bot_package_available()
|
|
324
|
+
train_ok = train_package_available()
|
|
317
325
|
commands.update(
|
|
318
326
|
name for name in _LAZY_COMMANDS
|
|
319
327
|
if (wrapper_ok or name not in _WRAPPER_RESIDENT_COMMANDS)
|
|
320
328
|
and (bot_ok or name not in _BOT_RESIDENT_COMMANDS)
|
|
329
|
+
and (train_ok or name not in _TRAIN_RESIDENT_COMMANDS)
|
|
321
330
|
)
|
|
322
331
|
commands.update(_SPECIAL_COMMANDS.keys())
|
|
323
332
|
|
|
@@ -363,6 +372,10 @@ class LazyCommandGroup(TyperGroup):
|
|
|
363
372
|
if not bot_package_available():
|
|
364
373
|
return None
|
|
365
374
|
module = importlib.import_module(f"praisonai_bot.cli.commands.{name}")
|
|
375
|
+
elif name in _TRAIN_RESIDENT_COMMANDS:
|
|
376
|
+
if not train_package_available():
|
|
377
|
+
return None
|
|
378
|
+
module = importlib.import_module(f"praisonai_train.cli.commands.{name}")
|
|
366
379
|
elif name in _WRAPPER_RESIDENT_COMMANDS:
|
|
367
380
|
if not wrapper_available():
|
|
368
381
|
return None
|
|
@@ -21,6 +21,85 @@ from ..configuration.credentials import CredentialStore, redact_key, validate_ap
|
|
|
21
21
|
app = typer.Typer(help="Manage API credentials")
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
# Provider id -> environment variable holding its API key. Used to fold active
|
|
25
|
+
# env-sourced credentials into `auth list`/`status` so users can tell which
|
|
26
|
+
# credential is live (env vs stored).
|
|
27
|
+
_PROVIDER_ENV_KEYS = {
|
|
28
|
+
"openai": "OPENAI_API_KEY",
|
|
29
|
+
"anthropic": "ANTHROPIC_API_KEY",
|
|
30
|
+
"google": "GOOGLE_API_KEY",
|
|
31
|
+
"gemini": "GEMINI_API_KEY",
|
|
32
|
+
"groq": "GROQ_API_KEY",
|
|
33
|
+
"openrouter": "OPENROUTER_API_KEY",
|
|
34
|
+
"mistral": "MISTRAL_API_KEY",
|
|
35
|
+
"deepseek": "DEEPSEEK_API_KEY",
|
|
36
|
+
"xai": "XAI_API_KEY",
|
|
37
|
+
"cohere": "COHERE_API_KEY",
|
|
38
|
+
"together": "TOGETHER_API_KEY",
|
|
39
|
+
"perplexity": "PERPLEXITYAI_API_KEY",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _env_credentials() -> dict[str, tuple[str, str]]:
|
|
44
|
+
"""Return ``{provider: (env_var, api_key)}`` for env-sourced keys present."""
|
|
45
|
+
found = {}
|
|
46
|
+
for provider, env_var in _PROVIDER_ENV_KEYS.items():
|
|
47
|
+
value = os.environ.get(env_var)
|
|
48
|
+
if value:
|
|
49
|
+
found[provider] = (env_var, value)
|
|
50
|
+
return found
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _select_provider_interactively(output) -> Optional[str]:
|
|
54
|
+
"""Catalogue-driven provider picker for when no provider id is supplied.
|
|
55
|
+
|
|
56
|
+
Returns the chosen provider id, or ``None`` if selection is unavailable
|
|
57
|
+
(non-tty / rich missing) so the caller can prompt for a free-form id.
|
|
58
|
+
"""
|
|
59
|
+
try:
|
|
60
|
+
from praisonai_code.llm.catalogue import ModelCatalogue
|
|
61
|
+
|
|
62
|
+
providers = ModelCatalogue().list_providers()
|
|
63
|
+
except Exception:
|
|
64
|
+
providers = []
|
|
65
|
+
|
|
66
|
+
ordered = [p for p in ("openai", "anthropic", "google", "ollama") if p in providers]
|
|
67
|
+
for p in providers:
|
|
68
|
+
if p not in ordered:
|
|
69
|
+
ordered.append(p)
|
|
70
|
+
ordered.append("custom")
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
from rich.prompt import Prompt
|
|
74
|
+
except Exception:
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
output.console.print("[bold]Choose your LLM provider:[/bold]")
|
|
78
|
+
choices = {}
|
|
79
|
+
for idx, pid in enumerate(ordered, start=1):
|
|
80
|
+
choices[str(idx)] = pid
|
|
81
|
+
label = "Other/custom" if pid == "custom" else pid
|
|
82
|
+
output.console.print(f" {idx}) {label}")
|
|
83
|
+
|
|
84
|
+
selected = Prompt.ask("Select provider", choices=list(choices.keys()), default="1")
|
|
85
|
+
pid = choices[selected]
|
|
86
|
+
if pid == "custom":
|
|
87
|
+
return Prompt.ask("Enter provider id").strip() or None
|
|
88
|
+
return pid
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _print_key_url_hint(provider: str, output) -> None:
|
|
92
|
+
"""Print a one-line 'Get your key' hint for well-known providers."""
|
|
93
|
+
try:
|
|
94
|
+
from praisonai_code.llm.catalogue import key_url_for_provider
|
|
95
|
+
|
|
96
|
+
url = key_url_for_provider(provider)
|
|
97
|
+
except Exception:
|
|
98
|
+
url = None
|
|
99
|
+
if url:
|
|
100
|
+
output.print_info(f"Get your key: {url}")
|
|
101
|
+
|
|
102
|
+
|
|
24
103
|
def _format_expiry(cred) -> str:
|
|
25
104
|
"""Format an OAuth credential's expiry for display ('(n/a)' for keys)."""
|
|
26
105
|
if not getattr(cred, "auth_method", "apikey") == "oauth":
|
|
@@ -148,7 +227,7 @@ def _run_oauth_login(
|
|
|
148
227
|
|
|
149
228
|
@app.command("login")
|
|
150
229
|
def auth_login(
|
|
151
|
-
provider: str = typer.Argument(help="Provider name (e.g., openai, anthropic)"),
|
|
230
|
+
provider: Optional[str] = typer.Argument(None, help="Provider name (e.g., openai, anthropic); prompts a picker if omitted"),
|
|
152
231
|
method: str = typer.Option("auto", "--method", help="Auth method: auto, apikey, or oauth"),
|
|
153
232
|
key: Optional[str] = typer.Option(None, "--key", help="API key (will prompt if not provided)"),
|
|
154
233
|
key_stdin: bool = typer.Option(False, "--key-stdin", help="Read API key from stdin"),
|
|
@@ -173,6 +252,15 @@ def auth_login(
|
|
|
173
252
|
"""
|
|
174
253
|
output = get_output_controller()
|
|
175
254
|
|
|
255
|
+
# Provider is optional: when omitted, present a catalogue-driven picker so
|
|
256
|
+
# users don't need to know the exact provider id up front. The positional
|
|
257
|
+
# argument still works for scripts.
|
|
258
|
+
if not provider:
|
|
259
|
+
provider = _select_provider_interactively(output)
|
|
260
|
+
if not provider:
|
|
261
|
+
output.print_error("A provider is required")
|
|
262
|
+
raise typer.Exit(1)
|
|
263
|
+
|
|
176
264
|
# Assemble any OAuth endpoint overrides supplied on the command line. These
|
|
177
265
|
# let users sign in to a built-in provider that needs an app client id, or
|
|
178
266
|
# to a provider not in the registry (e.g. a self-hosted gateway).
|
|
@@ -232,6 +320,7 @@ def auth_login(
|
|
|
232
320
|
api_key = key
|
|
233
321
|
else:
|
|
234
322
|
# Prompt for key
|
|
323
|
+
_print_key_url_hint(provider, output)
|
|
235
324
|
try:
|
|
236
325
|
api_key = typer.prompt(
|
|
237
326
|
f"Enter API key for {provider}",
|
|
@@ -357,46 +446,74 @@ def auth_list():
|
|
|
357
446
|
try:
|
|
358
447
|
store = CredentialStore()
|
|
359
448
|
providers = store.list_providers()
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
output.print_info("No stored credentials")
|
|
363
|
-
if output.is_json_mode:
|
|
364
|
-
output.print_json({"providers": []})
|
|
365
|
-
return
|
|
366
|
-
|
|
367
|
-
# Get detailed info for each provider
|
|
449
|
+
|
|
450
|
+
# Get detailed info for each stored provider.
|
|
368
451
|
provider_info = []
|
|
452
|
+
stored_names = set()
|
|
369
453
|
for provider_name in providers:
|
|
370
454
|
cred = store.get_credential(provider_name)
|
|
371
455
|
if cred:
|
|
372
|
-
|
|
456
|
+
stored_names.add(provider_name.lower())
|
|
457
|
+
provider_info.append({
|
|
373
458
|
"provider": provider_name,
|
|
374
459
|
"auth_method": cred.auth_method,
|
|
460
|
+
"source": "stored",
|
|
461
|
+
"env_var": None,
|
|
375
462
|
"key_redacted": redact_key(cred.api_key),
|
|
376
463
|
"base_url": cred.base_url,
|
|
377
464
|
"model": cred.model,
|
|
378
465
|
"expires_at": cred.expires_at,
|
|
379
466
|
"expires": _format_expiry(cred),
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
# Fold in active environment-variable keys (redacted) so the live
|
|
470
|
+
# credential is unambiguous. An env key is ALWAYS surfaced when present
|
|
471
|
+
# — even if the provider also has a stored key — because the env value
|
|
472
|
+
# overrides the stored one at runtime, so hiding it would point users at
|
|
473
|
+
# the wrong secret when they inspect or rotate credentials.
|
|
474
|
+
for provider_name, (env_var, value) in _env_credentials().items():
|
|
475
|
+
provider_info.append({
|
|
476
|
+
"provider": provider_name,
|
|
477
|
+
"auth_method": "apikey",
|
|
478
|
+
"source": "env",
|
|
479
|
+
"env_var": env_var,
|
|
480
|
+
"key_redacted": redact_key(value),
|
|
481
|
+
"base_url": None,
|
|
482
|
+
"model": None,
|
|
483
|
+
"expires_at": None,
|
|
484
|
+
"expires": "(n/a)",
|
|
485
|
+
"overrides_stored": provider_name in stored_names,
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
if not provider_info:
|
|
489
|
+
output.print_info("No stored credentials")
|
|
490
|
+
if output.is_json_mode:
|
|
491
|
+
output.print_json({"providers": []})
|
|
492
|
+
return
|
|
493
|
+
|
|
383
494
|
if output.is_json_mode:
|
|
384
495
|
output.print_json({"providers": provider_info})
|
|
385
496
|
else:
|
|
386
497
|
# Create table
|
|
387
|
-
headers = ["Provider", "Method", "Secret", "Expires", "Base URL", "Model"]
|
|
498
|
+
headers = ["Provider", "Method", "Source", "Secret", "Expires", "Base URL", "Model"]
|
|
388
499
|
rows = []
|
|
389
500
|
for info in provider_info:
|
|
501
|
+
source = info["source"]
|
|
502
|
+
if source == "env" and info.get("env_var"):
|
|
503
|
+
source = f"env ({info['env_var']})"
|
|
504
|
+
if info.get("overrides_stored"):
|
|
505
|
+
source += " [live, overrides stored]"
|
|
390
506
|
rows.append([
|
|
391
507
|
info["provider"],
|
|
392
508
|
info["auth_method"],
|
|
509
|
+
source,
|
|
393
510
|
info["key_redacted"],
|
|
394
511
|
info["expires"],
|
|
395
512
|
info["base_url"] or "(default)",
|
|
396
513
|
info["model"] or "(none)"
|
|
397
514
|
])
|
|
398
515
|
|
|
399
|
-
output.print_table(headers, rows, title="
|
|
516
|
+
output.print_table(headers, rows, title="Credentials")
|
|
400
517
|
|
|
401
518
|
except Exception as e:
|
|
402
519
|
output.print_error(f"Failed to list credentials: {e}")
|
|
@@ -425,6 +542,40 @@ def auth_status(
|
|
|
425
542
|
# Check specific provider
|
|
426
543
|
cred = store.get_credential(provider)
|
|
427
544
|
if not cred:
|
|
545
|
+
# Fall back to an active environment-variable key so the user
|
|
546
|
+
# can tell the credential is live from the env, not just missing
|
|
547
|
+
# from the store.
|
|
548
|
+
env_var = _PROVIDER_ENV_KEYS.get(provider.lower())
|
|
549
|
+
env_value = os.environ.get(env_var) if env_var else None
|
|
550
|
+
if env_value:
|
|
551
|
+
format_valid, format_msg = validate_api_key(provider, env_value)
|
|
552
|
+
status_info = {
|
|
553
|
+
"provider": provider,
|
|
554
|
+
"status": "found",
|
|
555
|
+
"auth_method": "apikey",
|
|
556
|
+
"source": "env",
|
|
557
|
+
"env_var": env_var,
|
|
558
|
+
"key_redacted": redact_key(env_value),
|
|
559
|
+
"format_valid": format_valid,
|
|
560
|
+
"format_message": format_msg,
|
|
561
|
+
"base_url": None,
|
|
562
|
+
"model": None,
|
|
563
|
+
"expires_at": None,
|
|
564
|
+
"expires": "(n/a)",
|
|
565
|
+
}
|
|
566
|
+
if output.is_json_mode:
|
|
567
|
+
output.print_json(status_info)
|
|
568
|
+
else:
|
|
569
|
+
output.print_panel(
|
|
570
|
+
f"Provider: {provider}\n"
|
|
571
|
+
f"Method: apikey\n"
|
|
572
|
+
f"Source: env ({env_var})\n"
|
|
573
|
+
f"Secret: {redact_key(env_value)}\n"
|
|
574
|
+
f"Format: {'✅' if format_valid else '❌'} {format_msg}",
|
|
575
|
+
title=f"Credentials Status: {provider}"
|
|
576
|
+
)
|
|
577
|
+
return
|
|
578
|
+
|
|
428
579
|
output.print_warning(f"No credentials found for {provider}")
|
|
429
580
|
if output.is_json_mode:
|
|
430
581
|
output.print_json({
|
|
@@ -433,17 +584,34 @@ def auth_status(
|
|
|
433
584
|
})
|
|
434
585
|
raise typer.Exit(1)
|
|
435
586
|
|
|
436
|
-
#
|
|
587
|
+
# A live env var overrides the stored credential at runtime. When
|
|
588
|
+
# both exist, validate/report the env key (the credential actually
|
|
589
|
+
# in effect) so status never claims the wrong secret is active.
|
|
590
|
+
env_var = _PROVIDER_ENV_KEYS.get(provider.lower())
|
|
591
|
+
env_value = os.environ.get(env_var) if env_var else None
|
|
592
|
+
active_from_env = bool(env_value) and not cred.is_oauth()
|
|
593
|
+
|
|
437
594
|
if cred.is_oauth():
|
|
438
595
|
format_valid, format_msg = True, "OAuth token"
|
|
596
|
+
secret = cred.api_key
|
|
597
|
+
source = "stored"
|
|
598
|
+
elif active_from_env:
|
|
599
|
+
format_valid, format_msg = validate_api_key(provider, env_value)
|
|
600
|
+
secret = env_value
|
|
601
|
+
source = f"env ({env_var})"
|
|
439
602
|
else:
|
|
440
603
|
format_valid, format_msg = validate_api_key(provider, cred.api_key)
|
|
441
|
-
|
|
604
|
+
secret = cred.api_key
|
|
605
|
+
source = "stored"
|
|
606
|
+
|
|
442
607
|
status_info = {
|
|
443
608
|
"provider": provider,
|
|
444
609
|
"status": "found",
|
|
445
610
|
"auth_method": cred.auth_method,
|
|
446
|
-
"
|
|
611
|
+
"source": source,
|
|
612
|
+
"env_var": env_var if active_from_env else None,
|
|
613
|
+
"overrides_stored": active_from_env,
|
|
614
|
+
"key_redacted": redact_key(secret),
|
|
447
615
|
"format_valid": format_valid,
|
|
448
616
|
"format_message": format_msg,
|
|
449
617
|
"base_url": cred.base_url,
|
|
@@ -454,9 +622,11 @@ def auth_status(
|
|
|
454
622
|
|
|
455
623
|
# Live validation if requested
|
|
456
624
|
if validate:
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
625
|
+
if cred.is_oauth():
|
|
626
|
+
# Freshly-refreshed token so we don't validate a stale mirror.
|
|
627
|
+
live_secret = store.get_valid_token(provider)
|
|
628
|
+
else:
|
|
629
|
+
live_secret = secret
|
|
460
630
|
live_valid, live_msg = _validate_with_live_call(provider, live_secret, cred.base_url)
|
|
461
631
|
status_info["live_valid"] = live_valid
|
|
462
632
|
status_info["live_message"] = live_msg
|
|
@@ -467,7 +637,9 @@ def auth_status(
|
|
|
467
637
|
output.print_panel(
|
|
468
638
|
f"Provider: {provider}\n"
|
|
469
639
|
f"Method: {cred.auth_method}\n"
|
|
470
|
-
f"
|
|
640
|
+
f"Source: {source}\n"
|
|
641
|
+
+ ("Note: env var overrides stored key at runtime\n" if active_from_env else "") +
|
|
642
|
+
f"Secret: {redact_key(secret)}\n"
|
|
471
643
|
+ (f"Expires: {_format_expiry(cred)}\n" if cred.is_oauth() else "") +
|
|
472
644
|
f"Format: {'✅' if format_valid else '❌'} {format_msg}\n"
|
|
473
645
|
+ (f"Live Test: {'✅' if status_info.get('live_valid') else '❌'} {status_info.get('live_message', 'Not tested')}\n" if validate else "") +
|
|
@@ -479,17 +651,13 @@ def auth_status(
|
|
|
479
651
|
else:
|
|
480
652
|
# Check all providers
|
|
481
653
|
providers = store.list_providers()
|
|
482
|
-
|
|
483
|
-
if not providers:
|
|
484
|
-
output.print_info("No stored credentials")
|
|
485
|
-
if output.is_json_mode:
|
|
486
|
-
output.print_json({"providers": []})
|
|
487
|
-
return
|
|
488
|
-
|
|
654
|
+
|
|
489
655
|
all_status = []
|
|
656
|
+
stored_names = set()
|
|
490
657
|
for provider_name in providers:
|
|
491
658
|
cred = store.get_credential(provider_name)
|
|
492
659
|
if cred:
|
|
660
|
+
stored_names.add(provider_name.lower())
|
|
493
661
|
if cred.is_oauth():
|
|
494
662
|
format_valid, format_msg = True, "OAuth token"
|
|
495
663
|
else:
|
|
@@ -498,6 +666,7 @@ def auth_status(
|
|
|
498
666
|
status = {
|
|
499
667
|
"provider": provider_name,
|
|
500
668
|
"auth_method": cred.auth_method,
|
|
669
|
+
"source": "stored",
|
|
501
670
|
"key_redacted": redact_key(cred.api_key),
|
|
502
671
|
"format_valid": format_valid,
|
|
503
672
|
"format_message": format_msg,
|
|
@@ -516,12 +685,42 @@ def auth_status(
|
|
|
516
685
|
status["live_message"] = live_msg
|
|
517
686
|
|
|
518
687
|
all_status.append(status)
|
|
519
|
-
|
|
688
|
+
|
|
689
|
+
# Fold in active env-var keys (redacted), marked env-sourced. Always
|
|
690
|
+
# surfaced even when the provider also has a stored key, since the
|
|
691
|
+
# env value is the credential in effect at runtime.
|
|
692
|
+
for provider_name, (env_var, value) in _env_credentials().items():
|
|
693
|
+
format_valid, format_msg = validate_api_key(provider_name, value)
|
|
694
|
+
source = f"env ({env_var})"
|
|
695
|
+
if provider_name in stored_names:
|
|
696
|
+
source += " [live, overrides stored]"
|
|
697
|
+
status = {
|
|
698
|
+
"provider": provider_name,
|
|
699
|
+
"auth_method": "apikey",
|
|
700
|
+
"source": source,
|
|
701
|
+
"key_redacted": redact_key(value),
|
|
702
|
+
"format_valid": format_valid,
|
|
703
|
+
"format_message": format_msg,
|
|
704
|
+
"expires_at": None,
|
|
705
|
+
"expires": "(n/a)",
|
|
706
|
+
}
|
|
707
|
+
if validate:
|
|
708
|
+
live_valid, live_msg = _validate_with_live_call(provider_name, value, None)
|
|
709
|
+
status["live_valid"] = live_valid
|
|
710
|
+
status["live_message"] = live_msg
|
|
711
|
+
all_status.append(status)
|
|
712
|
+
|
|
713
|
+
if not all_status:
|
|
714
|
+
output.print_info("No stored credentials")
|
|
715
|
+
if output.is_json_mode:
|
|
716
|
+
output.print_json({"providers": []})
|
|
717
|
+
return
|
|
718
|
+
|
|
520
719
|
if output.is_json_mode:
|
|
521
720
|
output.print_json({"providers": all_status})
|
|
522
721
|
else:
|
|
523
722
|
# Create table
|
|
524
|
-
headers = ["Provider", "Method", "Secret", "Expires", "Format"]
|
|
723
|
+
headers = ["Provider", "Method", "Source", "Secret", "Expires", "Format"]
|
|
525
724
|
if validate:
|
|
526
725
|
headers.append("Live Test")
|
|
527
726
|
|
|
@@ -530,6 +729,7 @@ def auth_status(
|
|
|
530
729
|
row = [
|
|
531
730
|
status["provider"],
|
|
532
731
|
status["auth_method"],
|
|
732
|
+
status.get("source", "stored"),
|
|
533
733
|
status["key_redacted"],
|
|
534
734
|
status["expires"],
|
|
535
735
|
"✅" if status["format_valid"] else "❌"
|
{praisonai_code-0.0.45 → praisonai_code-0.0.46}/praisonai_code/cli/features/setup/handler.py
RENAMED
|
@@ -87,16 +87,18 @@ class SetupHandler(CommandHandler):
|
|
|
87
87
|
return 1
|
|
88
88
|
|
|
89
89
|
providers = self._provider_defaults()
|
|
90
|
-
|
|
91
|
-
if provider
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
|
|
91
|
+
if provider in providers:
|
|
92
|
+
provider_info = providers[provider]
|
|
93
|
+
provider_name = provider_info[0]
|
|
94
|
+
env_key = provider_info[1]
|
|
95
|
+
default_model = provider_info[2]
|
|
96
|
+
else:
|
|
97
|
+
# Accept any catalogue-known provider (Groq, OpenRouter, Mistral, …)
|
|
98
|
+
# by deriving its env-var/default rather than rejecting it.
|
|
99
|
+
env_key, default_model, provider_name = self._provider_setup_info(
|
|
100
|
+
provider, providers
|
|
101
|
+
)
|
|
100
102
|
|
|
101
103
|
# Validate API key requirement
|
|
102
104
|
if env_key:
|
|
@@ -173,26 +175,24 @@ class SetupHandler(CommandHandler):
|
|
|
173
175
|
|
|
174
176
|
# 2. Provider selection (only if nothing detected / accepted)
|
|
175
177
|
if provider_id is None:
|
|
178
|
+
menu = self._catalogue_provider_choices()
|
|
176
179
|
output.console.print("[bold]1. Choose your LLM provider:[/bold]")
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
output.console.print(" 5) Custom provider")
|
|
182
|
-
|
|
180
|
+
for choice, (pid, _env_key, _model, name) in menu.items():
|
|
181
|
+
label = "Custom provider" if pid == "custom" else name
|
|
182
|
+
output.console.print(f" {choice}) {label}")
|
|
183
|
+
|
|
183
184
|
provider_choice = Prompt.ask(
|
|
184
185
|
"\nSelect provider",
|
|
185
|
-
choices=
|
|
186
|
+
choices=list(menu.keys()),
|
|
186
187
|
default="1"
|
|
187
188
|
)
|
|
188
189
|
|
|
189
|
-
provider_id, env_key, default_model, provider_name =
|
|
190
|
-
self._provider_menu()[provider_choice]
|
|
191
|
-
)
|
|
190
|
+
provider_id, env_key, default_model, provider_name = menu[provider_choice]
|
|
192
191
|
|
|
193
192
|
# API key input with live validation + re-prompt loop
|
|
194
193
|
if env_key:
|
|
195
194
|
output.console.print(f"\n[bold]2. Enter your {provider_name} API key:[/bold]")
|
|
195
|
+
self._print_key_url_hint(provider_id, output)
|
|
196
196
|
|
|
197
197
|
existing_key = os.getenv(env_key)
|
|
198
198
|
if existing_key and Confirm.ask(
|
|
@@ -291,7 +291,12 @@ class SetupHandler(CommandHandler):
|
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
def _provider_menu(self) -> Dict[str, tuple]:
|
|
294
|
-
"""Numeric provider menu → (provider_id, env_key, default_model, name).
|
|
294
|
+
"""Numeric provider menu → (provider_id, env_key, default_model, name).
|
|
295
|
+
|
|
296
|
+
Retained for backward compatibility / non-interactive callers. The
|
|
297
|
+
interactive wizard now uses the catalogue-driven picker in
|
|
298
|
+
``_catalogue_provider_choices``.
|
|
299
|
+
"""
|
|
295
300
|
defaults = self._provider_defaults()
|
|
296
301
|
ordered = ["openai", "anthropic", "google", "ollama", "custom"]
|
|
297
302
|
menu = {}
|
|
@@ -300,6 +305,96 @@ class SetupHandler(CommandHandler):
|
|
|
300
305
|
menu[str(idx)] = (pid, env_key, model, name)
|
|
301
306
|
return menu
|
|
302
307
|
|
|
308
|
+
def _catalogue_provider_choices(self) -> Dict[str, tuple]:
|
|
309
|
+
"""Numeric picker keyed "1".. → (provider_id, env_key, default_model, name).
|
|
310
|
+
|
|
311
|
+
Catalogue-driven: unions the curated ``_provider_defaults`` entries with
|
|
312
|
+
every provider enumerated by ``ModelCatalogue`` so onboarding covers the
|
|
313
|
+
full set of supported providers (Groq, OpenRouter, Mistral, DeepSeek,
|
|
314
|
+
xAI, …) rather than a hardcoded five. Always ends with a "custom"
|
|
315
|
+
escape hatch.
|
|
316
|
+
"""
|
|
317
|
+
defaults = self._provider_defaults()
|
|
318
|
+
|
|
319
|
+
ordered = ["openai", "anthropic", "google", "ollama"]
|
|
320
|
+
|
|
321
|
+
catalogue_providers = []
|
|
322
|
+
try:
|
|
323
|
+
from praisonai_code.llm.catalogue import ModelCatalogue
|
|
324
|
+
|
|
325
|
+
catalogue_providers = ModelCatalogue().list_providers()
|
|
326
|
+
except Exception:
|
|
327
|
+
catalogue_providers = []
|
|
328
|
+
|
|
329
|
+
for pid in catalogue_providers:
|
|
330
|
+
if pid not in ordered and pid not in ("custom",):
|
|
331
|
+
ordered.append(pid)
|
|
332
|
+
|
|
333
|
+
menu: Dict[str, tuple] = {}
|
|
334
|
+
idx = 1
|
|
335
|
+
for pid in ordered:
|
|
336
|
+
env_key, default_model, name = self._provider_setup_info(pid, defaults)
|
|
337
|
+
menu[str(idx)] = (pid, env_key, default_model, name)
|
|
338
|
+
idx += 1
|
|
339
|
+
|
|
340
|
+
# Custom escape hatch is always last.
|
|
341
|
+
menu[str(idx)] = ("custom", None, None, "Custom")
|
|
342
|
+
return menu
|
|
343
|
+
|
|
344
|
+
# Providers whose canonical API-key env-var is NOT ``<PROVIDER>_API_KEY``.
|
|
345
|
+
# Kept in sync with auth's ``_PROVIDER_ENV_KEYS`` so setup writes the same
|
|
346
|
+
# env-var name that auth (and the runtime) reads back.
|
|
347
|
+
_PROVIDER_ENV_KEY_OVERRIDES = {
|
|
348
|
+
"google": "GEMINI_API_KEY",
|
|
349
|
+
"gemini": "GEMINI_API_KEY",
|
|
350
|
+
"perplexity": "PERPLEXITYAI_API_KEY",
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
def _provider_setup_info(self, provider_id: str, defaults: Dict[str, tuple]) -> tuple:
|
|
354
|
+
"""Resolve ``(env_key, default_model, name)`` for a provider id.
|
|
355
|
+
|
|
356
|
+
Prefers a curated ``_provider_defaults`` row; otherwise derives a
|
|
357
|
+
usable env-var, default model, and display name from the catalogue so
|
|
358
|
+
catalogue-only providers (Groq, OpenRouter, …) get a working
|
|
359
|
+
non-interactive path rather than falling through to the custom branch.
|
|
360
|
+
"""
|
|
361
|
+
if provider_id in defaults:
|
|
362
|
+
name, env_key, model = defaults[provider_id]
|
|
363
|
+
return env_key, model, name
|
|
364
|
+
env_key = self._PROVIDER_ENV_KEY_OVERRIDES.get(
|
|
365
|
+
provider_id, f"{provider_id.upper()}_API_KEY"
|
|
366
|
+
)
|
|
367
|
+
default_model = self._catalogue_default_model(provider_id)
|
|
368
|
+
return env_key, default_model, provider_id.capitalize()
|
|
369
|
+
|
|
370
|
+
def _catalogue_default_model(self, provider_id: str) -> Optional[str]:
|
|
371
|
+
"""Return a sensible default model for a catalogue provider, or ``None``.
|
|
372
|
+
|
|
373
|
+
Picks the first model the catalogue lists for the provider so
|
|
374
|
+
catalogue-known providers get a non-interactive default instead of
|
|
375
|
+
being rejected like a custom provider.
|
|
376
|
+
"""
|
|
377
|
+
try:
|
|
378
|
+
from praisonai_code.llm.catalogue import ModelCatalogue
|
|
379
|
+
|
|
380
|
+
models = ModelCatalogue().list_models(provider=provider_id)
|
|
381
|
+
except Exception:
|
|
382
|
+
return None
|
|
383
|
+
if not models:
|
|
384
|
+
return None
|
|
385
|
+
return models[0].get("id")
|
|
386
|
+
|
|
387
|
+
def _print_key_url_hint(self, provider_id: str, output) -> None:
|
|
388
|
+
"""Print a one-line 'Get your key' hint for well-known providers."""
|
|
389
|
+
try:
|
|
390
|
+
from praisonai_code.llm.catalogue import key_url_for_provider
|
|
391
|
+
|
|
392
|
+
url = key_url_for_provider(provider_id)
|
|
393
|
+
except Exception:
|
|
394
|
+
url = None
|
|
395
|
+
if url:
|
|
396
|
+
output.console.print(f"[dim]Get your key: {url}[/dim]")
|
|
397
|
+
|
|
303
398
|
def _detect_provider_from_env(self) -> Optional[tuple]:
|
|
304
399
|
"""Detect a provider whose ``*_API_KEY`` is already in the environment.
|
|
305
400
|
|