shotgun-sh 0.10.2.dev2__tar.gz → 0.10.3.dev2__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.
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/PKG-INFO +2 -2
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/pyproject.toml +2 -2
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/agent_manager.py +44 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/config/provider.py +84 -102
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/context_analyzer/analyzer.py +2 -6
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/compaction.py +15 -2
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/constants.py +3 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/history_processors.py +2 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/token_estimation.py +68 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/models.py +38 -3
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/web_search/openai.py +38 -37
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/web_search/openai_compatible.py +36 -37
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/context.py +2 -2
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/manager.py +118 -15
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/llm_proxy/client.py +16 -6
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/main.py +13 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/posthog_telemetry.py +14 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/app.py +14 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/components/spinner.py +6 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/components/vertical_tail.py +8 -1
- shotgun_sh-0.10.3.dev2/src/shotgun/tui/markdown.py +51 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat/chat_screen.py +47 -87
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat/codebase_index_prompt_screen.py +2 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/hint_message.py +2 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/history/agent_response.py +2 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/history/user_question.py +1 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/welcome_message.py +2 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/github_issue.py +3 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/pipx_migration.py +2 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/provider_config.py +49 -11
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/shotgun_auth.py +2 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/tier1_warning_modal.py +3 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/welcome.py +2 -1
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/.gitignore +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/LICENSE +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/README.md +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/hatch_build.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/autopilot_orchestrator.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/claude_cli_subprocess.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/claude_subprocess.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/dependency_graph.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/lightweight_parser.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/llm_parser.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/prompts/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/prompts/context_preamble.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/prompts/create_pr.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/prompts/execute_parallel_stages.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/prompts/execute_stage.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/prompts/qa_testing.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/prompts/review_code.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/stage_monitor.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/autopilot/tasks_parser.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/cancellation.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/common.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/config/README.md +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/config/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/config/constants.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/config/manager.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/config/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/config/streaming_test.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/config/tier_detection.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/constants/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/constants/file_types.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/context_analyzer/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/context_analyzer/constants.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/context_analyzer/formatter.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/context_analyzer/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/filters.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/chunking.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/context_extraction.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/file_content_deduplication.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/history_building.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/message_utils.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/token_counting/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/token_counting/anthropic.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/token_counting/base.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/token_counting/openai.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/token_counting/sentencepiece_counter.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/token_counting/tokenizer_cache.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/history/token_counting/utils.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/conversation/manager.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/error/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/error/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/export.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/file_read.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/gemini3_patch.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/llm.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/messages.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/plan.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/research.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/router/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/router/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/router/router.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/router/tools/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/router/tools/delegation_tools.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/router/tools/plan_tools.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/runner.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/specify.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tasks.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/codebase/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/codebase/codebase_shell.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/codebase/directory_lister.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/codebase/file_read.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/codebase/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/codebase/query_graph.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/codebase/retrieve_code.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/context7.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/file_management.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/file_read_tools/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/file_read_tools/multimodal_file_read.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/markdown_tools/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/markdown_tools/insert_section.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/markdown_tools/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/markdown_tools/remove_section.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/markdown_tools/replace_section.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/markdown_tools/utils.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/mermaid_validation.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/registry.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/web_search/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/web_search/anthropic.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/web_search/gemini.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/tools/web_search/utils.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/usage_manager.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/api_endpoints.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/attachments/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/attachments/errors.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/attachments/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/attachments/parser.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/attachments/processor.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/build_constants.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/clear.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/codebase/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/codebase/commands.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/codebase/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/compact.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/config.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/error_handler.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/feedback.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/run.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/spec/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/spec/backup.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/spec/commands.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/spec/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/spec/pull_service.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/update.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/cli/utils.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/benchmarks/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/benchmarks/benchmark_runner.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/benchmarks/exporters.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/benchmarks/formatters/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/benchmarks/formatters/base.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/benchmarks/formatters/json_formatter.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/benchmarks/formatters/markdown.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/benchmarks/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/call_resolution.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/change_detector.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/code_retrieval.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/cypher_models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/errors.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/base.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/factory.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/go/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/go/extractor.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/javascript/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/javascript/extractor.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/protocol.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/python/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/python/extractor.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/rust/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/rust/extractor.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/types.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/typescript/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/extractors/typescript/extractor.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/gitignore.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/ingestor.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/kuzu_compat.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/language_config.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/metrics_collector.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/metrics_types.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/nl_query.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/parallel_executor.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/parser_loader.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/work_distributor.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/core/worker.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/indexing_state.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/codebase/service.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/exceptions.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/llm_proxy/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/llm_proxy/clients.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/llm_proxy/constants.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/llm_proxy/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/logging_config.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/export.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/file_read.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/partials/codebase_understanding.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/partials/content_formatting.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/partials/interactive_mode.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/partials/router_delegation_mode.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/plan.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/research.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/router.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/specify.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/state/system_state.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/agents/tasks.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/codebase/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/codebase/cypher_query_patterns.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/codebase/cypher_system.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/codebase/enhanced_query_context.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/codebase/partials/cypher_rules.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/codebase/partials/graph_schema.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/codebase/partials/temporal_context.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/history/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/history/chunk_summarization.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/history/combine_summaries.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/history/incremental_summarization.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/history/summarization.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/loader.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/prompts/tools/web_search.j2 +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/py.typed +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/sdk/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/sdk/codebase.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/sdk/exceptions.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/sdk/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/sdk/services.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/settings.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/client.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/constants.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/exceptions.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/shared_specs/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/shared_specs/file_scanner.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/shared_specs/hasher.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/shared_specs/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/shared_specs/upload_pipeline.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/shared_specs/utils.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/specs_client.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/shotgun_web/supabase_client.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/telemetry.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/commands/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/components/attachment_bar.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/components/context_indicator.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/components/mode_indicator.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/components/prompt_input.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/components/splash.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/components/status_bar.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/components/update_indicator.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/containers.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/dependencies.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/filtered_codebase_service.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/layout.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/protocols.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/autopilot_startup.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat/chat.tcss +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat/codebase_index_selection.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat/help_text.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat/prompt_history.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat.tcss +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/attachment_hint.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/command_providers.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/history/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/history/chat_history.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/history/formatters.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/history/partial_response.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/chat_screen/messages.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/confirmation_dialog.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/database_locked_dialog.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/database_timeout_dialog.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/directory_setup.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/feedback.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/kuzu_error_dialog.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/model_picker.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/shared_specs/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/shared_specs/create_spec_dialog.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/shared_specs/models.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/shared_specs/share_specs_dialog.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/shared_specs/upload_progress_screen.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/spec_pull.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/screens/splash.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/services/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/services/conversation_service.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/services/ollama.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/state/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/state/processing_state.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/styles.tcss +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/templates/app_index.html +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/utils/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/utils/mode_progress.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/widgets/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/widgets/approval_widget.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/widgets/cascade_confirmation_widget.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/widgets/plan_panel.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/widgets/stage_approval_widget.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/widgets/step_checkpoint_widget.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/tui/widgets/widget_coordinator.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/utils/__init__.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/utils/datetime_utils.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/utils/env_utils.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/utils/file_system_utils.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/utils/format_utils.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/utils/marketing.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/utils/source_detection.py +0 -0
- {shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/utils/update_checker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shotgun-sh
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.3.dev2
|
|
4
4
|
Summary: AI-powered research, planning, and task management CLI tool
|
|
5
5
|
Project-URL: Homepage, https://shotgun.sh/
|
|
6
6
|
Project-URL: Repository, https://github.com/shotgun-sh/shotgun
|
|
@@ -34,7 +34,7 @@ Requires-Dist: packaging>=23.0
|
|
|
34
34
|
Requires-Dist: pathspec>=0.12.0
|
|
35
35
|
Requires-Dist: posthog>=3.0.0
|
|
36
36
|
Requires-Dist: psutil>=5.9.0
|
|
37
|
-
Requires-Dist: pydantic-ai==1.
|
|
37
|
+
Requires-Dist: pydantic-ai==1.59.0
|
|
38
38
|
Requires-Dist: pydantic-settings>=2.0.0
|
|
39
39
|
Requires-Dist: pyperclip>=1.10.0
|
|
40
40
|
Requires-Dist: real-ladybug==0.14.1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "shotgun-sh"
|
|
3
|
-
version = "0.10.
|
|
3
|
+
version = "0.10.3.dev2"
|
|
4
4
|
description = "AI-powered research, planning, and task management CLI tool"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -24,7 +24,7 @@ classifiers = [
|
|
|
24
24
|
dependencies = [
|
|
25
25
|
"typer>=0.12.0",
|
|
26
26
|
"rich>=13.0.0",
|
|
27
|
-
"pydantic-ai==1.
|
|
27
|
+
"pydantic-ai==1.59.0", # Pinned due to bug workaround in gemini3_patch.py
|
|
28
28
|
"pydantic-settings>=2.0.0",
|
|
29
29
|
"httpx>=0.27.0",
|
|
30
30
|
"jinja2>=3.1.0",
|
|
@@ -86,12 +86,14 @@ from shotgun.agents.models import (
|
|
|
86
86
|
)
|
|
87
87
|
from shotgun.attachments import FileAttachment
|
|
88
88
|
from shotgun.exceptions import IncompleteToolCallError
|
|
89
|
+
from shotgun.posthog_telemetry import flush as flush_telemetry
|
|
89
90
|
from shotgun.posthog_telemetry import track_event
|
|
90
91
|
from shotgun.tui.screens.chat_screen.hint_message import HintMessage
|
|
91
92
|
from shotgun.tui.screens.chat_screen.welcome_message import WelcomeMessage
|
|
92
93
|
from shotgun.utils.source_detection import detect_source
|
|
93
94
|
|
|
94
95
|
from .conversation.history.compaction import apply_persistent_compaction
|
|
96
|
+
from .conversation.history.constants import MAX_UI_HISTORY_MESSAGES
|
|
95
97
|
from .export import create_export_agent
|
|
96
98
|
from .messages import AgentSystemPrompt, InternalPromptPart
|
|
97
99
|
from .models import AgentDeps, AgentRuntimeOptions
|
|
@@ -422,6 +424,27 @@ class AgentManager(Widget):
|
|
|
422
424
|
)
|
|
423
425
|
self._agents_initialized = True
|
|
424
426
|
|
|
427
|
+
async def cleanup_agents(self) -> None:
|
|
428
|
+
"""Release all agent instances and their held resources."""
|
|
429
|
+
if self._router_deps is not None:
|
|
430
|
+
self._router_deps.sub_agent_cache.clear()
|
|
431
|
+
self._router_deps.parent_stream_handler = None
|
|
432
|
+
self._router_deps.on_plan_changed = None
|
|
433
|
+
|
|
434
|
+
self._research_agent = None
|
|
435
|
+
self._research_deps = None
|
|
436
|
+
self._plan_agent = None
|
|
437
|
+
self._plan_deps = None
|
|
438
|
+
self._tasks_agent = None
|
|
439
|
+
self._tasks_deps = None
|
|
440
|
+
self._specify_agent = None
|
|
441
|
+
self._specify_deps = None
|
|
442
|
+
self._export_agent = None
|
|
443
|
+
self._export_deps = None
|
|
444
|
+
self._router_agent = None
|
|
445
|
+
self._router_deps = None
|
|
446
|
+
self._agents_initialized = False
|
|
447
|
+
|
|
425
448
|
@property
|
|
426
449
|
def research_agent(self) -> ShotgunAgent:
|
|
427
450
|
"""Get research agent (must call _ensure_agents_initialized first)."""
|
|
@@ -1103,6 +1126,9 @@ class AgentManager(Widget):
|
|
|
1103
1126
|
raise
|
|
1104
1127
|
finally:
|
|
1105
1128
|
self._stream_state = None
|
|
1129
|
+
# Flush PostHog events between agent runs to prevent
|
|
1130
|
+
# unbounded queue growth during long-running sessions
|
|
1131
|
+
flush_telemetry()
|
|
1106
1132
|
|
|
1107
1133
|
# Agent ALWAYS returns AgentResponse with structured output
|
|
1108
1134
|
agent_response = result.output
|
|
@@ -1403,6 +1429,9 @@ class AgentManager(Widget):
|
|
|
1403
1429
|
extra={"agent_mode": self._current_agent_type.value},
|
|
1404
1430
|
)
|
|
1405
1431
|
|
|
1432
|
+
# Prune old hint/welcome messages to prevent unbounded UI history growth
|
|
1433
|
+
self._prune_ui_message_history()
|
|
1434
|
+
|
|
1406
1435
|
# Post final UI update after compaction completes
|
|
1407
1436
|
# This ensures widgets that depend on message_history (like context indicator)
|
|
1408
1437
|
# receive the updated history after compaction
|
|
@@ -1663,6 +1692,11 @@ class AgentManager(Widget):
|
|
|
1663
1692
|
# Mark as sub-agent response for rendering with ↳ prefix
|
|
1664
1693
|
final_message._shotgun_is_sub_agent = True # type: ignore[attr-defined]
|
|
1665
1694
|
self._sub_agent_messages.append(final_message)
|
|
1695
|
+
if len(self._sub_agent_messages) > 200:
|
|
1696
|
+
logger.warning(
|
|
1697
|
+
"_sub_agent_messages exceeded 200 entries, truncating to most recent 100"
|
|
1698
|
+
)
|
|
1699
|
+
self._sub_agent_messages = self._sub_agent_messages[-100:]
|
|
1666
1700
|
|
|
1667
1701
|
state.current_response = None
|
|
1668
1702
|
|
|
@@ -1696,6 +1730,16 @@ class AgentManager(Widget):
|
|
|
1696
1730
|
self.ui_message_history.insert(insert_idx + j, msg)
|
|
1697
1731
|
self._sub_agent_messages = []
|
|
1698
1732
|
|
|
1733
|
+
def _prune_ui_message_history(self) -> None:
|
|
1734
|
+
"""Keep only the last MAX_UI_HISTORY_MESSAGES items in ui_message_history.
|
|
1735
|
+
|
|
1736
|
+
Acts as a circular buffer — oldest messages of any type are dropped.
|
|
1737
|
+
"""
|
|
1738
|
+
if len(self.ui_message_history) <= MAX_UI_HISTORY_MESSAGES:
|
|
1739
|
+
return
|
|
1740
|
+
|
|
1741
|
+
self.ui_message_history = self.ui_message_history[-MAX_UI_HISTORY_MESSAGES:]
|
|
1742
|
+
|
|
1699
1743
|
def _build_partial_response(
|
|
1700
1744
|
self, parts: list[ModelResponsePart | ToolCallPartDelta]
|
|
1701
1745
|
) -> ModelResponse | None:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Provider management for LLM configuration."""
|
|
2
2
|
|
|
3
3
|
from copy import deepcopy
|
|
4
|
+
from functools import lru_cache
|
|
4
5
|
|
|
5
6
|
from pydantic import SecretStr
|
|
6
7
|
from pydantic_ai._json_schema import JsonSchema, JsonSchemaTransformer
|
|
@@ -105,10 +106,9 @@ class OllamaCompatibleJsonSchemaTransformer(JsonSchemaTransformer):
|
|
|
105
106
|
return schema
|
|
106
107
|
|
|
107
108
|
|
|
108
|
-
#
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
] = {}
|
|
109
|
+
# Max number of cached Model instances (LRU eviction)
|
|
110
|
+
_MAX_MODEL_CACHE_SIZE = 8
|
|
111
|
+
|
|
112
112
|
|
|
113
113
|
# Module-level model override for OpenAI-compatible mode (set via --model CLI flag)
|
|
114
114
|
_openai_compat_model_override: str | None = None
|
|
@@ -226,6 +226,7 @@ def get_default_model_for_provider(config: ShotgunConfig) -> ModelName:
|
|
|
226
226
|
return ModelName.CLAUDE_OPUS_4_5
|
|
227
227
|
|
|
228
228
|
|
|
229
|
+
@lru_cache(maxsize=_MAX_MODEL_CACHE_SIZE)
|
|
229
230
|
def get_or_create_model(
|
|
230
231
|
provider: ProviderType,
|
|
231
232
|
key_provider: "KeyProvider",
|
|
@@ -235,6 +236,8 @@ def get_or_create_model(
|
|
|
235
236
|
) -> Model:
|
|
236
237
|
"""Get or create a singleton Model instance.
|
|
237
238
|
|
|
239
|
+
Bounded by ``functools.lru_cache`` (maxsize=8) with automatic LRU eviction.
|
|
240
|
+
|
|
238
241
|
Args:
|
|
239
242
|
provider: Actual LLM provider (openai, anthropic, google)
|
|
240
243
|
key_provider: Authentication method (byok or shotgun)
|
|
@@ -248,111 +251,90 @@ def get_or_create_model(
|
|
|
248
251
|
Raises:
|
|
249
252
|
ValueError: If provider is not supported
|
|
250
253
|
"""
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
254
|
+
logger.debug(
|
|
255
|
+
"Creating new %s model instance via %s: %s",
|
|
256
|
+
provider.value,
|
|
257
|
+
key_provider.value,
|
|
258
|
+
model_name,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
# Get max_tokens from MODEL_SPECS (only for known models)
|
|
262
|
+
if isinstance(model_name, ModelName) and model_name in MODEL_SPECS:
|
|
263
|
+
max_tokens = MODEL_SPECS[model_name].max_output_tokens
|
|
264
|
+
else:
|
|
265
|
+
max_tokens = {
|
|
266
|
+
ProviderType.OPENAI: 16_000,
|
|
267
|
+
ProviderType.ANTHROPIC: 32_000,
|
|
268
|
+
ProviderType.GOOGLE: 64_000,
|
|
269
|
+
ProviderType.OPENAI_COMPATIBLE: 16_000,
|
|
270
|
+
}.get(provider, 16_000)
|
|
271
|
+
|
|
272
|
+
# Handle OpenAI-compatible endpoints (uses provided base_url or settings)
|
|
273
|
+
if provider == ProviderType.OPENAI_COMPATIBLE:
|
|
274
|
+
return _create_openai_compat_model(
|
|
275
|
+
api_key, str(model_name), max_tokens, base_url
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# At this point, model_name must be a ModelName (string handled above via OPENAI_COMPATIBLE)
|
|
279
|
+
if not isinstance(model_name, ModelName):
|
|
280
|
+
raise ValueError(
|
|
281
|
+
f"Unknown model name: {model_name}. "
|
|
282
|
+
"For custom models, set SHOTGUN_OPENAI_COMPAT_BASE_URL."
|
|
259
283
|
)
|
|
260
284
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
285
|
+
if key_provider == KeyProvider.SHOTGUN:
|
|
286
|
+
# Shotgun Account uses LiteLLM proxy with native model types where possible
|
|
287
|
+
if model_name in MODEL_SPECS:
|
|
288
|
+
litellm_model_name = MODEL_SPECS[model_name].litellm_proxy_model_name
|
|
264
289
|
else:
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
api_key, str(model_name), max_tokens, base_url
|
|
290
|
+
litellm_model_name = f"openai/{model_name.value}"
|
|
291
|
+
|
|
292
|
+
if provider == ProviderType.ANTHROPIC:
|
|
293
|
+
anthropic_provider = create_anthropic_proxy_provider(api_key)
|
|
294
|
+
return AnthropicModel(
|
|
295
|
+
model_name.value,
|
|
296
|
+
provider=anthropic_provider,
|
|
297
|
+
settings=AnthropicModelSettings(
|
|
298
|
+
max_tokens=max_tokens,
|
|
299
|
+
timeout=600,
|
|
300
|
+
),
|
|
277
301
|
)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
302
|
+
else:
|
|
303
|
+
litellm_provider = create_litellm_provider(api_key)
|
|
304
|
+
return OpenAIChatModel(
|
|
305
|
+
litellm_model_name,
|
|
306
|
+
provider=litellm_provider,
|
|
307
|
+
settings=ModelSettings(max_tokens=max_tokens),
|
|
308
|
+
)
|
|
309
|
+
elif key_provider == KeyProvider.BYOK:
|
|
310
|
+
if provider == ProviderType.OPENAI:
|
|
311
|
+
openai_provider = OpenAIProvider(api_key=api_key)
|
|
312
|
+
return OpenAIResponsesModel(
|
|
313
|
+
model_name,
|
|
314
|
+
provider=openai_provider,
|
|
315
|
+
settings=ModelSettings(max_tokens=max_tokens),
|
|
316
|
+
)
|
|
317
|
+
elif provider == ProviderType.ANTHROPIC:
|
|
318
|
+
anthropic_provider = AnthropicProvider(api_key=api_key)
|
|
319
|
+
return AnthropicModel(
|
|
320
|
+
model_name,
|
|
321
|
+
provider=anthropic_provider,
|
|
322
|
+
settings=AnthropicModelSettings(
|
|
323
|
+
max_tokens=max_tokens,
|
|
324
|
+
timeout=600,
|
|
325
|
+
),
|
|
326
|
+
)
|
|
327
|
+
elif provider == ProviderType.GOOGLE:
|
|
328
|
+
google_provider = GoogleProvider(api_key=api_key)
|
|
329
|
+
return GoogleModel(
|
|
330
|
+
model_name,
|
|
331
|
+
provider=google_provider,
|
|
332
|
+
settings=ModelSettings(max_tokens=max_tokens),
|
|
286
333
|
)
|
|
287
|
-
|
|
288
|
-
if key_provider == KeyProvider.SHOTGUN:
|
|
289
|
-
# Shotgun Account uses LiteLLM proxy with native model types where possible
|
|
290
|
-
if model_name in MODEL_SPECS:
|
|
291
|
-
litellm_model_name = MODEL_SPECS[model_name].litellm_proxy_model_name
|
|
292
|
-
else:
|
|
293
|
-
# Fallback for unmapped models
|
|
294
|
-
litellm_model_name = f"openai/{model_name.value}"
|
|
295
|
-
|
|
296
|
-
# Use native provider types to preserve API formats and features
|
|
297
|
-
if provider == ProviderType.ANTHROPIC:
|
|
298
|
-
# Anthropic: Use native AnthropicProvider with /anthropic endpoint
|
|
299
|
-
# This preserves Anthropic-specific features like tool_choice
|
|
300
|
-
# Note: Web search for Shotgun Account uses Gemini only (not Anthropic)
|
|
301
|
-
# Note: Anthropic API expects model name without prefix (e.g., "claude-sonnet-4-5")
|
|
302
|
-
anthropic_provider = create_anthropic_proxy_provider(api_key)
|
|
303
|
-
_model_cache[cache_key] = AnthropicModel(
|
|
304
|
-
model_name.value, # Use model name without "anthropic/" prefix
|
|
305
|
-
provider=anthropic_provider,
|
|
306
|
-
settings=AnthropicModelSettings(
|
|
307
|
-
max_tokens=max_tokens,
|
|
308
|
-
timeout=600, # 10 minutes timeout for large responses
|
|
309
|
-
),
|
|
310
|
-
)
|
|
311
|
-
else:
|
|
312
|
-
# OpenAI and Google: Use LiteLLMProvider (OpenAI-compatible format)
|
|
313
|
-
# Google's GoogleProvider doesn't support base_url, so use LiteLLM
|
|
314
|
-
# Note: Use OpenAIChatModel (not OpenAIResponsesModel) because LiteLLM's
|
|
315
|
-
# streaming Responses API doesn't return tool calls properly for Gemini 3
|
|
316
|
-
litellm_provider = create_litellm_provider(api_key)
|
|
317
|
-
_model_cache[cache_key] = OpenAIChatModel(
|
|
318
|
-
litellm_model_name,
|
|
319
|
-
provider=litellm_provider,
|
|
320
|
-
settings=ModelSettings(max_tokens=max_tokens),
|
|
321
|
-
)
|
|
322
|
-
elif key_provider == KeyProvider.BYOK:
|
|
323
|
-
# Use native provider implementations with user's API keys
|
|
324
|
-
if provider == ProviderType.OPENAI:
|
|
325
|
-
openai_provider = OpenAIProvider(api_key=api_key)
|
|
326
|
-
_model_cache[cache_key] = OpenAIResponsesModel(
|
|
327
|
-
model_name,
|
|
328
|
-
provider=openai_provider,
|
|
329
|
-
settings=ModelSettings(max_tokens=max_tokens),
|
|
330
|
-
)
|
|
331
|
-
elif provider == ProviderType.ANTHROPIC:
|
|
332
|
-
anthropic_provider = AnthropicProvider(api_key=api_key)
|
|
333
|
-
_model_cache[cache_key] = AnthropicModel(
|
|
334
|
-
model_name,
|
|
335
|
-
provider=anthropic_provider,
|
|
336
|
-
settings=AnthropicModelSettings(
|
|
337
|
-
max_tokens=max_tokens,
|
|
338
|
-
timeout=600, # 10 minutes timeout for large responses
|
|
339
|
-
),
|
|
340
|
-
)
|
|
341
|
-
elif provider == ProviderType.GOOGLE:
|
|
342
|
-
google_provider = GoogleProvider(api_key=api_key)
|
|
343
|
-
_model_cache[cache_key] = GoogleModel(
|
|
344
|
-
model_name,
|
|
345
|
-
provider=google_provider,
|
|
346
|
-
settings=ModelSettings(max_tokens=max_tokens),
|
|
347
|
-
)
|
|
348
|
-
else:
|
|
349
|
-
raise ValueError(f"Unsupported provider: {provider}")
|
|
350
334
|
else:
|
|
351
|
-
raise ValueError(f"Unsupported
|
|
335
|
+
raise ValueError(f"Unsupported provider: {provider}")
|
|
352
336
|
else:
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
return _model_cache[cache_key]
|
|
337
|
+
raise ValueError(f"Unsupported key provider: {key_provider}")
|
|
356
338
|
|
|
357
339
|
|
|
358
340
|
async def get_provider_model(
|
{shotgun_sh-0.10.2.dev2 → shotgun_sh-0.10.3.dev2}/src/shotgun/agents/context_analyzer/analyzer.py
RENAMED
|
@@ -20,6 +20,7 @@ from shotgun.agents.conversation.history.token_counting.utils import (
|
|
|
20
20
|
)
|
|
21
21
|
from shotgun.agents.conversation.history.token_estimation import (
|
|
22
22
|
estimate_tokens_from_messages,
|
|
23
|
+
get_last_api_token_count,
|
|
23
24
|
)
|
|
24
25
|
from shotgun.agents.messages import AgentSystemPrompt, SystemStatusPrompt
|
|
25
26
|
from shotgun.logging_config import get_logger
|
|
@@ -66,14 +67,9 @@ class ContextAnalyzer:
|
|
|
66
67
|
TokenAllocation with token counts by message/tool type
|
|
67
68
|
"""
|
|
68
69
|
# Step 1: Find the last response's usage data (ground truth for input tokens)
|
|
69
|
-
last_input_tokens =
|
|
70
|
+
last_input_tokens = get_last_api_token_count(message_history)
|
|
70
71
|
total_output_tokens = 0
|
|
71
72
|
|
|
72
|
-
for msg in reversed(message_history):
|
|
73
|
-
if isinstance(msg, ModelResponse) and msg.usage:
|
|
74
|
-
last_input_tokens = msg.usage.input_tokens + msg.usage.cache_read_tokens
|
|
75
|
-
break
|
|
76
|
-
|
|
77
73
|
if last_input_tokens == 0:
|
|
78
74
|
# Fallback to token estimation (no logging to reduce verbosity)
|
|
79
75
|
last_input_tokens = await estimate_tokens_from_messages(
|
|
@@ -7,7 +7,7 @@ from shotgun.agents.models import AgentDeps
|
|
|
7
7
|
from shotgun.logging_config import get_logger
|
|
8
8
|
from shotgun.posthog_telemetry import track_event
|
|
9
9
|
|
|
10
|
-
from .token_estimation import estimate_tokens_from_messages
|
|
10
|
+
from .token_estimation import estimate_tokens_from_messages, get_last_api_token_count
|
|
11
11
|
|
|
12
12
|
logger = get_logger(__name__)
|
|
13
13
|
|
|
@@ -36,7 +36,20 @@ async def apply_persistent_compaction(
|
|
|
36
36
|
|
|
37
37
|
try:
|
|
38
38
|
# Count tokens to decide if LLM-based compaction is needed
|
|
39
|
-
|
|
39
|
+
# Prefer API usage data (accurate) over text-based estimation (undercounts)
|
|
40
|
+
api_tokens = get_last_api_token_count(messages)
|
|
41
|
+
if api_tokens > 0:
|
|
42
|
+
estimated_tokens = api_tokens
|
|
43
|
+
logger.debug(
|
|
44
|
+
f"Using API usage data for compaction check: {estimated_tokens} tokens"
|
|
45
|
+
)
|
|
46
|
+
else:
|
|
47
|
+
estimated_tokens = await estimate_tokens_from_messages(
|
|
48
|
+
messages, deps.llm_model
|
|
49
|
+
)
|
|
50
|
+
logger.debug(
|
|
51
|
+
f"Using text estimation for compaction check: {estimated_tokens} tokens (no API usage data)"
|
|
52
|
+
)
|
|
40
53
|
|
|
41
54
|
# Create minimal usage info for compaction check
|
|
42
55
|
usage = RequestUsage(
|
|
@@ -15,6 +15,9 @@ CHUNK_TARGET_RATIO = 0.60 # Target chunk size as % of max_input_tokens
|
|
|
15
15
|
CHUNK_SAFE_RATIO = 0.70 # Max safe ratio before triggering chunked compaction
|
|
16
16
|
RETENTION_WINDOW_MESSAGES = 5 # Keep last N message groups outside compaction
|
|
17
17
|
|
|
18
|
+
# UI history pruning — keep the last N messages (any type) as a circular buffer
|
|
19
|
+
MAX_UI_HISTORY_MESSAGES = 50
|
|
20
|
+
|
|
18
21
|
|
|
19
22
|
class SummaryType(Enum):
|
|
20
23
|
"""Types of summarization requests for logging."""
|
|
@@ -35,6 +35,7 @@ from .token_estimation import (
|
|
|
35
35
|
from .token_estimation import (
|
|
36
36
|
estimate_post_summary_tokens,
|
|
37
37
|
estimate_tokens_from_messages,
|
|
38
|
+
estimate_tokens_hybrid,
|
|
38
39
|
)
|
|
39
40
|
|
|
40
41
|
if TYPE_CHECKING:
|
|
@@ -453,7 +454,7 @@ async def token_limit_compactor(
|
|
|
453
454
|
else:
|
|
454
455
|
# Check if total conversation exceeds threshold for full compaction
|
|
455
456
|
total_tokens = await _safe_token_estimation(
|
|
456
|
-
|
|
457
|
+
estimate_tokens_hybrid,
|
|
457
458
|
deps.llm_model.name,
|
|
458
459
|
model_max_tokens,
|
|
459
460
|
messages,
|
|
@@ -6,7 +6,7 @@ and libraries, replacing the old character-based estimation approach.
|
|
|
6
6
|
|
|
7
7
|
from typing import TYPE_CHECKING, Union
|
|
8
8
|
|
|
9
|
-
from pydantic_ai.messages import ModelMessage
|
|
9
|
+
from pydantic_ai.messages import ModelMessage, ModelResponse
|
|
10
10
|
|
|
11
11
|
from shotgun.agents.config.models import ModelConfig
|
|
12
12
|
|
|
@@ -15,9 +15,28 @@ if TYPE_CHECKING:
|
|
|
15
15
|
|
|
16
16
|
from shotgun.agents.models import AgentDeps
|
|
17
17
|
|
|
18
|
+
from shotgun.logging_config import get_logger
|
|
19
|
+
|
|
18
20
|
from .constants import INPUT_BUFFER_TOKENS, MIN_SUMMARY_TOKENS
|
|
19
21
|
from .token_counting import count_tokens_from_messages as _count_tokens_from_messages
|
|
20
22
|
|
|
23
|
+
logger = get_logger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_last_api_token_count(messages: list[ModelMessage]) -> int:
|
|
27
|
+
"""Extract the total input token count from the last ModelResponse's usage data.
|
|
28
|
+
|
|
29
|
+
API usage data is the most accurate source for token counts because it includes
|
|
30
|
+
message framing, tool schemas, system prompts, and binary content that text-based
|
|
31
|
+
estimation misses.
|
|
32
|
+
|
|
33
|
+
Returns 0 if no ModelResponse with nonzero usage data is found.
|
|
34
|
+
"""
|
|
35
|
+
for msg in reversed(messages):
|
|
36
|
+
if isinstance(msg, ModelResponse) and msg.usage:
|
|
37
|
+
return msg.usage.input_tokens + msg.usage.cache_read_tokens
|
|
38
|
+
return 0
|
|
39
|
+
|
|
21
40
|
|
|
22
41
|
async def estimate_tokens_from_messages(
|
|
23
42
|
messages: list[ModelMessage], model_config: ModelConfig
|
|
@@ -41,6 +60,54 @@ async def estimate_tokens_from_messages(
|
|
|
41
60
|
return await _count_tokens_from_messages(messages, model_config)
|
|
42
61
|
|
|
43
62
|
|
|
63
|
+
async def estimate_tokens_hybrid(
|
|
64
|
+
messages: list[ModelMessage], model_config: ModelConfig
|
|
65
|
+
) -> int:
|
|
66
|
+
"""Estimate total tokens using API usage data plus delta counting.
|
|
67
|
+
|
|
68
|
+
This is more efficient than counting all messages from scratch. It uses the
|
|
69
|
+
last ModelResponse's usage data (which includes framing, schemas, etc.) as
|
|
70
|
+
the base count, then only counts the new messages added since that response.
|
|
71
|
+
|
|
72
|
+
Falls back to full counting when no API usage data is available (e.g. first turn).
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
messages: List of messages to count tokens for
|
|
76
|
+
model_config: Model configuration with provider info
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Estimated token count
|
|
80
|
+
"""
|
|
81
|
+
# Single backward pass to find the last ModelResponse with usage data
|
|
82
|
+
api_count = 0
|
|
83
|
+
last_response_idx = -1
|
|
84
|
+
for i in range(len(messages) - 1, -1, -1):
|
|
85
|
+
msg = messages[i]
|
|
86
|
+
if isinstance(msg, ModelResponse) and msg.usage:
|
|
87
|
+
api_count = msg.usage.input_tokens + msg.usage.cache_read_tokens
|
|
88
|
+
if api_count > 0:
|
|
89
|
+
last_response_idx = i
|
|
90
|
+
break
|
|
91
|
+
|
|
92
|
+
if api_count == 0:
|
|
93
|
+
# First turn or no usage data — fall back to full counting
|
|
94
|
+
return await estimate_tokens_from_messages(messages, model_config)
|
|
95
|
+
|
|
96
|
+
delta_messages = messages[last_response_idx + 1 :]
|
|
97
|
+
|
|
98
|
+
if not delta_messages:
|
|
99
|
+
return api_count
|
|
100
|
+
|
|
101
|
+
delta_count = await estimate_tokens_from_messages(delta_messages, model_config)
|
|
102
|
+
|
|
103
|
+
logger.debug(
|
|
104
|
+
f"Hybrid token estimate: api_count={api_count}, delta_count={delta_count}, "
|
|
105
|
+
f"delta_messages={len(delta_messages)}, total={api_count + delta_count}"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
return api_count + delta_count
|
|
109
|
+
|
|
110
|
+
|
|
44
111
|
async def estimate_post_summary_tokens(
|
|
45
112
|
messages: list[ModelMessage], summary_index: int, model_config: ModelConfig
|
|
46
113
|
) -> int:
|
|
@@ -24,6 +24,38 @@ from .filters import (
|
|
|
24
24
|
|
|
25
25
|
SerializedMessage = dict[str, Any]
|
|
26
26
|
|
|
27
|
+
# Mapping of custom part_kind values to their pydantic-ai base part_kind.
|
|
28
|
+
# Custom subclasses (e.g. SystemStatusPrompt, InternalPromptPart) override
|
|
29
|
+
# part_kind with values that ModelMessagesTypeAdapter doesn't recognise,
|
|
30
|
+
# causing deserialization to fail. Remapping before validation fixes this.
|
|
31
|
+
_CUSTOM_PART_KIND_MAP: dict[str, str] = {
|
|
32
|
+
"system-status": "user-prompt", # SystemStatusPrompt -> UserPromptPart
|
|
33
|
+
"internal-prompt": "user-prompt", # InternalPromptPart -> UserPromptPart
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _sanitize_parts(messages: list[SerializedMessage]) -> list[SerializedMessage]:
|
|
38
|
+
"""Remap custom part_kind values so ModelMessagesTypeAdapter can deserialize them."""
|
|
39
|
+
sanitized: list[SerializedMessage] = []
|
|
40
|
+
for msg in messages:
|
|
41
|
+
parts = msg.get("parts")
|
|
42
|
+
if not parts:
|
|
43
|
+
sanitized.append(msg)
|
|
44
|
+
continue
|
|
45
|
+
new_parts = []
|
|
46
|
+
changed = False
|
|
47
|
+
for part in parts:
|
|
48
|
+
pk = part.get("part_kind")
|
|
49
|
+
if pk in _CUSTOM_PART_KIND_MAP:
|
|
50
|
+
part = {**part, "part_kind": _CUSTOM_PART_KIND_MAP[pk]}
|
|
51
|
+
changed = True
|
|
52
|
+
new_parts.append(part)
|
|
53
|
+
if changed:
|
|
54
|
+
sanitized.append({**msg, "parts": new_parts})
|
|
55
|
+
else:
|
|
56
|
+
sanitized.append(msg)
|
|
57
|
+
return sanitized
|
|
58
|
+
|
|
27
59
|
|
|
28
60
|
class FileReference(BaseModel):
|
|
29
61
|
"""Placeholder for binary content that was loaded from a file.
|
|
@@ -162,8 +194,9 @@ class ConversationHistory(BaseModel):
|
|
|
162
194
|
if not self.agent_history:
|
|
163
195
|
return []
|
|
164
196
|
|
|
165
|
-
#
|
|
166
|
-
|
|
197
|
+
# Sanitize custom part_kind values before deserialization
|
|
198
|
+
sanitized = _sanitize_parts(self.agent_history)
|
|
199
|
+
return ModelMessagesTypeAdapter.validate_python(sanitized)
|
|
167
200
|
|
|
168
201
|
def get_ui_messages(self) -> list[ModelMessage | HintMessage | WelcomeMessage]:
|
|
169
202
|
"""Get ui_history as a list of Model, hint, or welcome messages."""
|
|
@@ -189,7 +222,9 @@ class ConversationHistory(BaseModel):
|
|
|
189
222
|
payload = item
|
|
190
223
|
if isinstance(payload, dict):
|
|
191
224
|
payload = {k: v for k, v in payload.items() if k != "message_type"}
|
|
192
|
-
deserialized = ModelMessagesTypeAdapter.validate_python(
|
|
225
|
+
deserialized = ModelMessagesTypeAdapter.validate_python(
|
|
226
|
+
_sanitize_parts([payload])
|
|
227
|
+
)
|
|
193
228
|
messages.append(deserialized[0])
|
|
194
229
|
|
|
195
230
|
return messages
|