teddy-cli 0.1.17.dev1396__tar.gz → 0.1.17.dev1397__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.
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/PKG-INFO +1 -1
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/pyproject.toml +1 -1
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/__main__.py +1 -37
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/session_cli_handlers.py +163 -32
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/litellm_adapter.py +75 -20
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/session.py +0 -1
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/planning_service.py +1 -10
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/session_service.py +1 -3
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/config/config.yaml +3 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/.gitignore +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/LICENSE +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/README.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/cli_formatter.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/cli_helpers.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/textual_plan_reviewer.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_app.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_editor.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_execution.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_helpers.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_logic.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_previews.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/inbound/textual_plan_reviewer_widgets.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/console_interactor.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/console_interactor_ask_loop.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/console_interactor_helpers.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/console_tooling.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/filesystem_helpers.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/local_file_system_adapter.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/local_repo_tree_generator.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/openrouter_hydrator.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/shell_adapter.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/shell_command_builder.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/suppressed_logging.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/system_environment_adapter.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/system_environment_inspector.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/system_time_adapter.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/terminal_quit_key_listener.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/web_scraper_adapter.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/web_searcher_adapter.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/outbound/yaml_config_adapter.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/container.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/action_ports.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/change_set.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/drift_report.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/exceptions.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/execution_report.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/orchestrator_ports.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/plan.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/planning_ports.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/project_context.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/report_assembly_data.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/shell_output.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/web_search_results.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/inbound/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/inbound/edit_simulator.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/inbound/get_context_use_case.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/inbound/init.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/inbound/plan_parser.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/inbound/plan_reviewer.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/inbound/plan_validator.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/inbound/planning_use_case.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/inbound/run_plan_use_case.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/config_service.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/environment_inspector.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/execution_report_assembler.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/file_system_manager.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/llm_client.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/markdown_report_formatter.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/prompt_manager.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/quit_key_listener.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/repo_tree_generator.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/session_loop_guard.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/session_manager.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/session_repository.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/shell_executor.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/system_environment.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/time_service.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/user_interactor.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/web_scraper.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/outbound/web_searcher.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/action_changeset_builder.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/action_diff_manager.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/action_dispatcher.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/action_executor.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/action_factory.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/action_parser_complex.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/action_parser_strategies.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/context_service.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/edit_simulator.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/execution_orchestrator.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/execution_report_assembler.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/init_service.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/markdown_plan_parser.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/markdown_report_formatter.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/parser_infrastructure.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/parser_metadata.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/parser_reporting.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/plan_validator.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/prompt_manager.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/session_lifecycle_manager.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/session_loop_guard.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/session_orchestrator.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/session_planner.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/session_pruning_service.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/session_replanner.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/session_repository.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/templates/execution_report.md.j2 +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/update_checker.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/validation_rules/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/validation_rules/edit.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/validation_rules/edit_matcher.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/validation_rules/edit_matcher_heuristics.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/validation_rules/execute.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/validation_rules/filesystem.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/validation_rules/helpers.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/validation_rules/message.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/diff.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/editor_names.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/interrupt_guard.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/io.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/markdown.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/paths.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/serialization.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/session_notices.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/stdin_ownership.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/string.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/terminal.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/prompts.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/registries/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/registries/infrastructure.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/registries/reviewer.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/registries/validators.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/MRP.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/config/__init__.py +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/config/init.context +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/config/prompts/architect.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/config/prompts/assistant.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/config/prompts/debugger.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/config/prompts/developer.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/config/prompts/pathfinder.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/config/prompts/prototyper.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/templates/ARCHITECTURE.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/templates/PROJECT.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/templates/case-file.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/templates/ci.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/templates/component-design.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/templates/makefile.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/templates/milestone.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/templates/pre-commit.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/templates/specification-document.md +0 -0
- {teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/templates/vertical-slice.md +0 -0
|
@@ -112,31 +112,6 @@ def _resolve_setup_api_key(
|
|
|
112
112
|
return system_env.isatty() and not pipeline
|
|
113
113
|
|
|
114
114
|
|
|
115
|
-
def _run_init_setup_gates(container) -> None:
|
|
116
|
-
"""Run the interactive setup gates after ``teddy init`` scaffolding.
|
|
117
|
-
|
|
118
|
-
Bare ``teddy init`` and ``teddy init config`` scaffold (or reset) the
|
|
119
|
-
``.teddy`` configuration, then run the SAME one-time setup as ``teddy
|
|
120
|
-
start``: the required LLM API-key prompt (when the key is missing and the
|
|
121
|
-
configured model requires one) and the optional editor selection (when no
|
|
122
|
-
editor is configured). Both gates reuse the existing preflight helpers, so
|
|
123
|
-
no prompt logic is duplicated. The gates are TTY-gated: a non-interactive
|
|
124
|
-
run (stdin is not a TTY) prompts for neither, keeping automated and CI
|
|
125
|
-
invocations clean.
|
|
126
|
-
"""
|
|
127
|
-
from teddy_executor.adapters.inbound.session_cli_handlers import (
|
|
128
|
-
_ensure_api_key_configured,
|
|
129
|
-
_validate_editor_config,
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
system_env = container.resolve(ISystemEnvironment)
|
|
133
|
-
if not system_env.isatty():
|
|
134
|
-
return
|
|
135
|
-
config_service = container.resolve(IConfigService)
|
|
136
|
-
_ensure_api_key_configured(config_service, setup_api_key=True)
|
|
137
|
-
_validate_editor_config(container)
|
|
138
|
-
|
|
139
|
-
|
|
140
115
|
def _display_init_drift(container) -> None:
|
|
141
116
|
"""Print the prompt/template drift advice after bare ``teddy init``.
|
|
142
117
|
|
|
@@ -144,8 +119,7 @@ def _display_init_drift(container) -> None:
|
|
|
144
119
|
"unchanged" summary cannot mislead: it flags drifted prompts and missing
|
|
145
120
|
templates and names the actionable ``teddy init prompts`` /
|
|
146
121
|
``teddy init templates`` commands. The two shared helpers are imported
|
|
147
|
-
lazily,
|
|
148
|
-
they never block the command.
|
|
122
|
+
lazily, and they are advisory only -- they never block the command.
|
|
149
123
|
"""
|
|
150
124
|
from teddy_executor.adapters.inbound.session_cli_handlers import (
|
|
151
125
|
_display_checks_footer,
|
|
@@ -262,9 +236,6 @@ def start( # noqa: PLR0913
|
|
|
262
236
|
),
|
|
263
237
|
),
|
|
264
238
|
model: Optional[str] = typer.Option(None, "--model", help="LLM model override."),
|
|
265
|
-
api_key: Optional[str] = typer.Option(
|
|
266
|
-
None, "--api-key", help="LLM API key override."
|
|
267
|
-
),
|
|
268
239
|
max_turns: Optional[int] = OPT_MAX_TURNS,
|
|
269
240
|
max_cost: Optional[float] = OPT_MAX_COST,
|
|
270
241
|
):
|
|
@@ -297,7 +268,6 @@ def start( # noqa: PLR0913
|
|
|
297
268
|
pipeline=pipeline,
|
|
298
269
|
additional_context=additional_context,
|
|
299
270
|
model=model,
|
|
300
|
-
api_key=api_key,
|
|
301
271
|
max_turns=max_turns,
|
|
302
272
|
max_cost=max_cost,
|
|
303
273
|
)
|
|
@@ -326,7 +296,6 @@ def init_callback(ctx: typer.Context):
|
|
|
326
296
|
summary = init_use_case.ensure_initialized()
|
|
327
297
|
typer.echo(f"TeDDy initialized in .teddy folder. {summary}")
|
|
328
298
|
_display_init_drift(container)
|
|
329
|
-
_run_init_setup_gates(container)
|
|
330
299
|
|
|
331
300
|
|
|
332
301
|
@init_app.command()
|
|
@@ -353,7 +322,6 @@ def config():
|
|
|
353
322
|
init_use_case = container.resolve(IInitUseCase)
|
|
354
323
|
status = init_use_case.ensure_config_initialized(overwrite=True)
|
|
355
324
|
typer.echo(status)
|
|
356
|
-
_run_init_setup_gates(container)
|
|
357
325
|
|
|
358
326
|
|
|
359
327
|
@init_app.command()
|
|
@@ -542,9 +510,6 @@ def resume( # noqa: PLR0913
|
|
|
542
510
|
),
|
|
543
511
|
no_copy: bool = OPT_NO_COPY,
|
|
544
512
|
model: Optional[str] = typer.Option(None, "--model", help="LLM model override."),
|
|
545
|
-
api_key: Optional[str] = typer.Option(
|
|
546
|
-
None, "--api-key", help="LLM API key override."
|
|
547
|
-
),
|
|
548
513
|
agent: Optional[str] = typer.Option(
|
|
549
514
|
None,
|
|
550
515
|
"--agent",
|
|
@@ -587,7 +552,6 @@ def resume( # noqa: PLR0913
|
|
|
587
552
|
setup_api_key=_resolve_setup_api_key(system_env, pipeline=pipeline),
|
|
588
553
|
no_copy=no_copy,
|
|
589
554
|
model=model,
|
|
590
|
-
api_key=api_key,
|
|
591
555
|
agent=agent,
|
|
592
556
|
message=message,
|
|
593
557
|
pipeline=pipeline,
|
|
@@ -666,7 +666,6 @@ def handle_new_session( # noqa: PLR0913
|
|
|
666
666
|
pipeline: bool = False,
|
|
667
667
|
additional_context: Optional[list[str]] = None,
|
|
668
668
|
model: Optional[str] = None,
|
|
669
|
-
api_key: Optional[str] = None,
|
|
670
669
|
setup_editor: Optional[bool] = None,
|
|
671
670
|
setup_api_key: Optional[bool] = None,
|
|
672
671
|
max_turns: Optional[int] = None,
|
|
@@ -712,7 +711,6 @@ def handle_new_session( # noqa: PLR0913
|
|
|
712
711
|
initial_request=message,
|
|
713
712
|
additional_context=additional_context or [],
|
|
714
713
|
model=model,
|
|
715
|
-
api_key=api_key,
|
|
716
714
|
)
|
|
717
715
|
session_dir = session_manager.create_session(options)
|
|
718
716
|
typer.echo(f"Session created at: {session_dir}")
|
|
@@ -790,8 +788,7 @@ def _run_cli_preflight_check(
|
|
|
790
788
|
|
|
791
789
|
# API-key setup runs BEFORE the LLM client is resolved so its transient
|
|
792
790
|
# config-service instance reads the freshly-persisted on-disk state. The
|
|
793
|
-
# gate itself is single-sourced in ``_ensure_api_key_configured
|
|
794
|
-
# ``init`` command shares identical gating.
|
|
791
|
+
# gate itself is single-sourced in ``_ensure_api_key_configured``.
|
|
795
792
|
config_service = container.resolve(IConfigService)
|
|
796
793
|
_ensure_api_key_configured(config_service, setup_api_key)
|
|
797
794
|
|
|
@@ -829,20 +826,24 @@ def _ensure_api_key_configured(
|
|
|
829
826
|
config_service: IConfigService,
|
|
830
827
|
setup_api_key: Optional[bool],
|
|
831
828
|
) -> None:
|
|
832
|
-
"""Runs the
|
|
833
|
-
|
|
834
|
-
The gate fires only when ``setup_api_key`` is truthy
|
|
835
|
-
``llm.api_key`` is absent or blank
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
829
|
+
"""Runs the API-key gate when the key is missing and a key may be required.
|
|
830
|
+
|
|
831
|
+
The gate fires only when ``setup_api_key`` is truthy and the resolved
|
|
832
|
+
``llm.api_key`` is absent or blank. A local endpoint short-circuits the
|
|
833
|
+
prompt with a persisted placeholder key, because a server on the developer
|
|
834
|
+
machine never needs a real credential. Otherwise the interactive prompt
|
|
835
|
+
fires when the configured model actually requires a provider key
|
|
836
|
+
(key-requiredness is delegated to litellm). It is ADDITIVE and inert by
|
|
837
|
+
default (``setup_api_key`` of ``None``/``False`` -> skip), so callers that
|
|
838
|
+
never opt in are unaffected. Single-sourced so both session entry points
|
|
839
|
+
share identical gating.
|
|
840
840
|
"""
|
|
841
|
-
if (
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
841
|
+
if not setup_api_key or not _is_llm_api_key_missing(config_service):
|
|
842
|
+
return
|
|
843
|
+
if _is_local_endpoint(config_service):
|
|
844
|
+
_persist_local_placeholder_key(config_service)
|
|
845
|
+
return
|
|
846
|
+
if _llm_model_requires_api_key(config_service):
|
|
846
847
|
_prompt_for_api_key(config_service)
|
|
847
848
|
|
|
848
849
|
|
|
@@ -895,29 +896,49 @@ def _prompt_for_api_key(config_service: IConfigService) -> None:
|
|
|
895
896
|
The key is written to ``.teddy/.env`` (never ``os.environ``) and the config
|
|
896
897
|
is migrated to the ``${TEDDY_LLM_API_KEY}`` interpolation form so the
|
|
897
898
|
transient ``IConfigService`` instance held by ``ILlmClient`` resolves it on
|
|
898
|
-
the same run.
|
|
899
|
-
|
|
899
|
+
the same run. The warning names the resolved provider and the stripped model
|
|
900
|
+
so the user knows which credential to paste. An empty line skips the prompt
|
|
901
|
+
with a notice, a whitespace-only entry persists nothing, and an aborted
|
|
900
902
|
prompt (Ctrl-C / Ctrl-D) returns WITHOUT raising so the downstream
|
|
901
903
|
validation error can surface the missing key with its own hint.
|
|
902
904
|
"""
|
|
905
|
+
provider, model = _resolve_model_identity(config_service)
|
|
906
|
+
api_base = config_service.get_setting("llm.api_base")
|
|
907
|
+
remote_api_base = (
|
|
908
|
+
api_base if isinstance(api_base, str) and api_base.strip() else None
|
|
909
|
+
)
|
|
910
|
+
|
|
903
911
|
typer.echo("", err=True)
|
|
904
912
|
typer.secho("LLM API Key", fg=typer.colors.CYAN, bold=True, err=True)
|
|
905
913
|
typer.echo("", err=True)
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
"
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
914
|
+
warning_lines = ["\u26a0 No LLM API key configured."]
|
|
915
|
+
if remote_api_base:
|
|
916
|
+
warning_lines.append(f" Endpoint: {remote_api_base}")
|
|
917
|
+
elif provider:
|
|
918
|
+
warning_lines.append(f" Provider: {provider}")
|
|
919
|
+
if model:
|
|
920
|
+
warning_lines.append(f" Model: {model}")
|
|
921
|
+
typer.secho("\n".join(warning_lines), fg=typer.colors.YELLOW, err=True)
|
|
922
|
+
typer.echo("", err=True)
|
|
923
|
+
|
|
924
|
+
instructions = ["Paste your key below, or press Enter on an empty line to skip."]
|
|
925
|
+
if not remote_api_base:
|
|
926
|
+
instructions.append(
|
|
927
|
+
"To use a different provider, change llm.model in .teddy/config.yaml."
|
|
928
|
+
)
|
|
929
|
+
typer.secho("\n".join(instructions), fg=typer.colors.YELLOW, err=True)
|
|
912
930
|
typer.echo("", err=True)
|
|
913
931
|
|
|
914
932
|
try:
|
|
915
|
-
value = typer.prompt(
|
|
933
|
+
value = typer.prompt(
|
|
934
|
+
"LLM API key", hide_input=True, default="", show_default=False
|
|
935
|
+
)
|
|
916
936
|
except (EOFError, typer.Abort):
|
|
917
937
|
return
|
|
918
938
|
|
|
919
939
|
value = value.strip()
|
|
920
940
|
if not value:
|
|
941
|
+
typer.secho("\u2139 No key saved.", fg=typer.colors.YELLOW, err=True)
|
|
921
942
|
return
|
|
922
943
|
|
|
923
944
|
config_service.set_env_variable("TEDDY_LLM_API_KEY", value)
|
|
@@ -930,6 +951,121 @@ def _prompt_for_api_key(config_service: IConfigService) -> None:
|
|
|
930
951
|
)
|
|
931
952
|
|
|
932
953
|
|
|
954
|
+
def _resolve_model_identity(
|
|
955
|
+
config_service: IConfigService,
|
|
956
|
+
) -> tuple[Optional[str], str]:
|
|
957
|
+
"""Resolves the provider name and the prefix-stripped model for the prompt.
|
|
958
|
+
|
|
959
|
+
litellm is the single source of truth for provider resolution. A failed
|
|
960
|
+
resolution prints the provider list to stdout, so the call runs inside a
|
|
961
|
+
stdout redirect. An unresolvable model falls back to the configured string
|
|
962
|
+
with no provider, so the prompt still shows which model the key belongs to.
|
|
963
|
+
"""
|
|
964
|
+
import contextlib
|
|
965
|
+
import io
|
|
966
|
+
import logging
|
|
967
|
+
|
|
968
|
+
model = config_service.get_setting("llm.model")
|
|
969
|
+
if not (isinstance(model, str) and model.strip()):
|
|
970
|
+
return None, ""
|
|
971
|
+
api_base = config_service.get_setting("llm.api_base")
|
|
972
|
+
resolved_api_base = (
|
|
973
|
+
api_base if isinstance(api_base, str) and api_base.strip() else None
|
|
974
|
+
)
|
|
975
|
+
try:
|
|
976
|
+
import litellm
|
|
977
|
+
|
|
978
|
+
with contextlib.redirect_stdout(io.StringIO()):
|
|
979
|
+
resolved_model, provider, _dynamic_key, _resolved_base = (
|
|
980
|
+
litellm.get_llm_provider(model, api_base=resolved_api_base)
|
|
981
|
+
)
|
|
982
|
+
return str(provider), str(resolved_model)
|
|
983
|
+
except Exception:
|
|
984
|
+
logging.getLogger(__name__).warning(
|
|
985
|
+
"Could not resolve a provider for model '%s'; showing the configured "
|
|
986
|
+
"name instead.",
|
|
987
|
+
model,
|
|
988
|
+
exc_info=True,
|
|
989
|
+
)
|
|
990
|
+
return None, model.strip()
|
|
991
|
+
|
|
992
|
+
|
|
993
|
+
_LOCAL_PLACEHOLDER_KEY = "dummy-key-custom-endpoints"
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
def _is_local_endpoint(config_service: IConfigService) -> bool:
|
|
997
|
+
"""True when ``llm.api_base`` points at the developer machine.
|
|
998
|
+
|
|
999
|
+
A local host means no real credential can be required, so the gate writes a
|
|
1000
|
+
placeholder instead of prompting. Host classification performs no DNS
|
|
1001
|
+
lookup, so an unresolvable name never blocks startup.
|
|
1002
|
+
"""
|
|
1003
|
+
api_base = config_service.get_setting("llm.api_base")
|
|
1004
|
+
if not (isinstance(api_base, str) and api_base.strip()):
|
|
1005
|
+
return False
|
|
1006
|
+
return _host_is_local(_api_base_host(api_base))
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
def _api_base_host(api_base: str) -> Optional[str]:
|
|
1010
|
+
"""Extracts the host from an ``api_base`` value, tolerating a missing scheme."""
|
|
1011
|
+
from urllib.parse import urlsplit
|
|
1012
|
+
|
|
1013
|
+
value = api_base.strip()
|
|
1014
|
+
candidate = value if "://" in value else f"//{value}"
|
|
1015
|
+
try:
|
|
1016
|
+
return urlsplit(candidate).hostname
|
|
1017
|
+
except ValueError:
|
|
1018
|
+
return None
|
|
1019
|
+
|
|
1020
|
+
|
|
1021
|
+
def _host_is_local(host: Optional[str]) -> bool:
|
|
1022
|
+
"""True when a host names the developer machine or a private network.
|
|
1023
|
+
|
|
1024
|
+
Loopback names, the ``host.docker.internal`` alias, and ``.local`` names all
|
|
1025
|
+
address the developer machine. Loopback, link-local, and private address
|
|
1026
|
+
ranges cannot be a public provider. No DNS lookup runs, so an unresolvable
|
|
1027
|
+
name never blocks startup.
|
|
1028
|
+
"""
|
|
1029
|
+
import ipaddress
|
|
1030
|
+
|
|
1031
|
+
if not host:
|
|
1032
|
+
return False
|
|
1033
|
+
normalized = host.strip("[]").casefold()
|
|
1034
|
+
if normalized == "localhost" or normalized.endswith(".localhost"):
|
|
1035
|
+
return True
|
|
1036
|
+
if normalized == "host.docker.internal" or normalized.endswith(".local"):
|
|
1037
|
+
return True
|
|
1038
|
+
try:
|
|
1039
|
+
address = ipaddress.ip_address(normalized)
|
|
1040
|
+
except ValueError:
|
|
1041
|
+
return False
|
|
1042
|
+
return address.is_loopback or address.is_link_local or address.is_private
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
def _persist_local_placeholder_key(config_service: IConfigService) -> None:
|
|
1046
|
+
"""Writes the placeholder key for a local endpoint and prints the notice (stderr).
|
|
1047
|
+
|
|
1048
|
+
The placeholder is written to ``.teddy/.env`` and the config migrates to the
|
|
1049
|
+
``${TEDDY_LLM_API_KEY}`` interpolation form, mirroring the interactive
|
|
1050
|
+
prompt path so a server that checks the Authorization header still starts.
|
|
1051
|
+
"""
|
|
1052
|
+
config_service.set_env_variable("TEDDY_LLM_API_KEY", _LOCAL_PLACEHOLDER_KEY)
|
|
1053
|
+
config_service.set_setting("llm.api_key", "${TEDDY_LLM_API_KEY}")
|
|
1054
|
+
api_base = config_service.get_setting("llm.api_base") or ""
|
|
1055
|
+
typer.echo("", err=True)
|
|
1056
|
+
typer.secho(
|
|
1057
|
+
f"\u2139 Local endpoint detected: {api_base}",
|
|
1058
|
+
fg=typer.colors.CYAN,
|
|
1059
|
+
err=True,
|
|
1060
|
+
)
|
|
1061
|
+
typer.secho(
|
|
1062
|
+
f' Saved placeholder API key "{_LOCAL_PLACEHOLDER_KEY}" to .teddy/.env.\n'
|
|
1063
|
+
" Replace TEDDY_LLM_API_KEY there if the server checks the Authorization header.",
|
|
1064
|
+
fg=typer.colors.YELLOW,
|
|
1065
|
+
err=True,
|
|
1066
|
+
)
|
|
1067
|
+
|
|
1068
|
+
|
|
933
1069
|
def _persist_editor_choice(config_service: IConfigService, value: str) -> None:
|
|
934
1070
|
"""Persists the editor choice and prints the green save confirmation (stderr)."""
|
|
935
1071
|
config_service.set_setting("editor", value)
|
|
@@ -1167,7 +1303,6 @@ def _sync_and_display_session_meta(
|
|
|
1167
1303
|
container: Container,
|
|
1168
1304
|
session_name: str,
|
|
1169
1305
|
model: Optional[str] = None,
|
|
1170
|
-
api_key: Optional[str] = None,
|
|
1171
1306
|
agent: Optional[str] = None,
|
|
1172
1307
|
) -> None:
|
|
1173
1308
|
"""Reads latest turn meta.yaml, syncs config overrides, and clears actual_model.
|
|
@@ -1201,9 +1336,6 @@ def _sync_and_display_session_meta(
|
|
|
1201
1336
|
elif config_model != "unknown" and meta.get("model") != config_model:
|
|
1202
1337
|
meta["model"] = config_model
|
|
1203
1338
|
changed = True
|
|
1204
|
-
if api_key:
|
|
1205
|
-
meta["api_key"] = api_key
|
|
1206
|
-
changed = True
|
|
1207
1339
|
if changed:
|
|
1208
1340
|
repository.save_meta(f"{latest_turn_path}/meta.yaml", meta)
|
|
1209
1341
|
|
|
@@ -1214,7 +1346,6 @@ def handle_resume_session( # noqa: PLR0913
|
|
|
1214
1346
|
interactive: bool = True,
|
|
1215
1347
|
no_copy: bool = False,
|
|
1216
1348
|
model: Optional[str] = None,
|
|
1217
|
-
api_key: Optional[str] = None,
|
|
1218
1349
|
agent: Optional[str] = None,
|
|
1219
1350
|
message: Optional[str] = None,
|
|
1220
1351
|
pipeline: bool = False,
|
|
@@ -1240,7 +1371,7 @@ def handle_resume_session( # noqa: PLR0913
|
|
|
1240
1371
|
|
|
1241
1372
|
# 3. Display actual_model and sync config overrides
|
|
1242
1373
|
_sync_and_display_session_meta(
|
|
1243
|
-
container, session_name, model=model,
|
|
1374
|
+
container, session_name, model=model, agent=agent
|
|
1244
1375
|
)
|
|
1245
1376
|
|
|
1246
1377
|
# 4. Display session path (below the Agent/Model identity block).
|
|
@@ -108,7 +108,9 @@ class LiteLLMAdapter(ILlmClient):
|
|
|
108
108
|
resolved = "gpt-4o"
|
|
109
109
|
return str(resolved)
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
# Request, retry, and hydration form one linear flow whose branching is
|
|
112
|
+
# inherent to the provider protocol. Extracting it is outside this change.
|
|
113
|
+
def get_completion( # noqa: C901
|
|
112
114
|
self, messages: List[Dict[str, str]], model: Optional[str] = None, **kwargs: Any
|
|
113
115
|
) -> Any:
|
|
114
116
|
"""
|
|
@@ -414,29 +416,82 @@ class LiteLLMAdapter(ILlmClient):
|
|
|
414
416
|
"(or your shell environment)."
|
|
415
417
|
)
|
|
416
418
|
|
|
417
|
-
#
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
"The API key appears to be invalid, expired, or deactivated."
|
|
430
|
-
)
|
|
431
|
-
except TimeoutError:
|
|
432
|
-
errors.append(
|
|
433
|
-
"The remote connectivity check timed out after 10 seconds."
|
|
419
|
+
# 2. Provider resolution: a bare model name cannot be routed, so the
|
|
420
|
+
# failure surfaces at preflight with a paste-ready fix instead of at the
|
|
421
|
+
# first completion. Skipped when an earlier error already explains the
|
|
422
|
+
# configuration problem.
|
|
423
|
+
if not errors:
|
|
424
|
+
errors.extend(self._provider_resolution_errors(model))
|
|
425
|
+
|
|
426
|
+
# 3. Optional remote check: verify key validity and expiration.
|
|
427
|
+
if not errors:
|
|
428
|
+
errors.extend(
|
|
429
|
+
self._remote_check_errors(
|
|
430
|
+
model, api_key, include_remote, is_api_key_provided
|
|
434
431
|
)
|
|
435
|
-
|
|
436
|
-
errors.append(f"Remote connectivity check failed: {str(e)}")
|
|
432
|
+
)
|
|
437
433
|
|
|
438
434
|
return errors
|
|
439
435
|
|
|
436
|
+
def _provider_resolution_errors(self, model: str) -> List[str]:
|
|
437
|
+
"""Returns the paste-ready error when litellm cannot infer a provider.
|
|
438
|
+
|
|
439
|
+
A custom ``api_base`` is left to the user's endpoint, so no resolution
|
|
440
|
+
runs there. The library prints its provider list to stdout on failure,
|
|
441
|
+
so that output is captured and never reaches the CLI. The list shape lets
|
|
442
|
+
the caller extend unconditionally and keeps its branching flat.
|
|
443
|
+
"""
|
|
444
|
+
import contextlib
|
|
445
|
+
import io
|
|
446
|
+
|
|
447
|
+
if self._config_service.get_setting("llm.api_base"):
|
|
448
|
+
return []
|
|
449
|
+
|
|
450
|
+
litellm = self._get_litellm()
|
|
451
|
+
try:
|
|
452
|
+
with contextlib.redirect_stdout(io.StringIO()):
|
|
453
|
+
litellm.get_llm_provider(model=model)
|
|
454
|
+
except Exception:
|
|
455
|
+
# A resolution failure is the signal; the library raises several
|
|
456
|
+
# exception types depending on the model string and provider table.
|
|
457
|
+
return [
|
|
458
|
+
f"Cannot infer a provider for model '{model}'. "
|
|
459
|
+
"Change llm.model in .teddy/config.yaml to prefix it with the "
|
|
460
|
+
f"provider, e.g. 'openai/{model}'."
|
|
461
|
+
]
|
|
462
|
+
return []
|
|
463
|
+
|
|
464
|
+
def _remote_check_errors(
|
|
465
|
+
self,
|
|
466
|
+
model: str,
|
|
467
|
+
api_key: Any,
|
|
468
|
+
include_remote: bool,
|
|
469
|
+
is_api_key_provided: bool,
|
|
470
|
+
) -> List[str]:
|
|
471
|
+
"""Validates the key against the provider when a remote check is due.
|
|
472
|
+
|
|
473
|
+
Returns zero or one error. A missing request, an absent key, or a valid
|
|
474
|
+
key all yield an empty list, so the caller can extend unconditionally and
|
|
475
|
+
the request path stays flat.
|
|
476
|
+
"""
|
|
477
|
+
if not (include_remote and is_api_key_provided):
|
|
478
|
+
return []
|
|
479
|
+
|
|
480
|
+
from concurrent.futures import TimeoutError
|
|
481
|
+
|
|
482
|
+
litellm = self._get_litellm()
|
|
483
|
+
executor = self._get_executor()
|
|
484
|
+
future = executor.submit(litellm.check_valid_key, model=model, api_key=api_key)
|
|
485
|
+
try:
|
|
486
|
+
is_valid = future.result(timeout=10.0)
|
|
487
|
+
if not is_valid:
|
|
488
|
+
return ["The API key appears to be invalid, expired, or deactivated."]
|
|
489
|
+
except TimeoutError:
|
|
490
|
+
return ["The remote connectivity check timed out after 10 seconds."]
|
|
491
|
+
except Exception as e:
|
|
492
|
+
return [f"Remote connectivity check failed: {str(e)}"]
|
|
493
|
+
return []
|
|
494
|
+
|
|
440
495
|
def get_context_window(self, model: Optional[str] = None) -> int:
|
|
441
496
|
"""
|
|
442
497
|
Returns the maximum context window size (tokens) for the specified model.
|
|
@@ -111,7 +111,6 @@ class PlanningService(IPlanningUseCase):
|
|
|
111
111
|
response, plan_content, turn_cost = self._perform_generation_with_retry(
|
|
112
112
|
messages,
|
|
113
113
|
model=model,
|
|
114
|
-
api_key=meta.get("api_key"),
|
|
115
114
|
)
|
|
116
115
|
|
|
117
116
|
cost_val = self._prompt_manager.log_telemetry(token_count, turn_cost)
|
|
@@ -132,7 +131,6 @@ class PlanningService(IPlanningUseCase):
|
|
|
132
131
|
self,
|
|
133
132
|
messages: list[Dict[str, str]],
|
|
134
133
|
model: str,
|
|
135
|
-
api_key: Optional[str] = None,
|
|
136
134
|
) -> tuple[Any, str, float]:
|
|
137
135
|
"""Implements retry loop for empty LLM content."""
|
|
138
136
|
max_retries_val = self._config_service.get_setting("llm.max_retries")
|
|
@@ -141,15 +139,8 @@ class PlanningService(IPlanningUseCase):
|
|
|
141
139
|
plan_content = ""
|
|
142
140
|
turn_cost = 0.0
|
|
143
141
|
|
|
144
|
-
# Construct overrides dict for kwargs
|
|
145
|
-
overrides = {}
|
|
146
|
-
if api_key:
|
|
147
|
-
overrides["api_key"] = api_key
|
|
148
|
-
|
|
149
142
|
for attempt in range(max_retries):
|
|
150
|
-
response = self._llm_client.get_completion(
|
|
151
|
-
messages=messages, model=model, **overrides
|
|
152
|
-
)
|
|
143
|
+
response = self._llm_client.get_completion(messages=messages, model=model)
|
|
153
144
|
plan_content = self._extract_plan_content(response)
|
|
154
145
|
attempt_cost = self._llm_client.get_completion_cost(
|
|
155
146
|
response, model_override=model
|
|
@@ -137,8 +137,6 @@ class SessionService(ISessionManager):
|
|
|
137
137
|
}
|
|
138
138
|
if options.model:
|
|
139
139
|
meta_data["model"] = options.model
|
|
140
|
-
if options.api_key:
|
|
141
|
-
meta_data["api_key"] = options.api_key
|
|
142
140
|
return meta_data
|
|
143
141
|
|
|
144
142
|
def _resolve_agent_prompt(self, agent_name: str) -> tuple[str, str]:
|
|
@@ -486,7 +484,7 @@ class SessionService(ISessionManager):
|
|
|
486
484
|
}
|
|
487
485
|
|
|
488
486
|
# Carry over LLM overrides and actual_model for display continuity
|
|
489
|
-
for key in ["model", "actual_model", "provider"
|
|
487
|
+
for key in ["model", "actual_model", "provider"]:
|
|
490
488
|
if key in current_meta:
|
|
491
489
|
meta[key] = current_meta[key]
|
|
492
490
|
|
|
@@ -46,6 +46,9 @@ llm:
|
|
|
46
46
|
X-OpenRouter-Title: "TeDDy"
|
|
47
47
|
X-OpenRouter-Categories: "cli-agent"
|
|
48
48
|
|
|
49
|
+
# llm.model must start with the provider prefix, e.g. "openai/qwen3-coder-30b".
|
|
50
|
+
# A bare model name fails preflight, because litellm cannot infer the provider.
|
|
51
|
+
|
|
49
52
|
# Local models (Ollama, LM Studio):
|
|
50
53
|
# model: "ollama/qwen3-coder:30b"
|
|
51
54
|
# model: "lm_studio/qwen3-coder-30b"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/adapters/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/domain/models/plan.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/ports/inbound/init.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/services/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/editor_names.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/markdown.py
RENAMED
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/paths.py
RENAMED
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/serialization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/string.py
RENAMED
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/core/utils/terminal.py
RENAMED
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/registries/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/registries/reviewer.py
RENAMED
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/registries/validators.py
RENAMED
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{teddy_cli-0.1.17.dev1396 → teddy_cli-0.1.17.dev1397}/src/teddy_executor/resources/templates/ci.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|