shotgun-sh 0.1.15.dev2__tar.gz → 0.2.1.dev1__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.
Potentially problematic release.
This version of shotgun-sh might be problematic. Click here for more details.
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/.gitignore +3 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/PKG-INFO +2 -2
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/pyproject.toml +2 -2
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/common.py +4 -5
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/config/constants.py +33 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/config/manager.py +147 -39
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/config/models.py +158 -0
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/config/provider.py +309 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/history/compaction.py +1 -1
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/history/history_processors.py +18 -9
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/history/token_counting/__init__.py +31 -0
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/history/token_counting/anthropic.py +89 -0
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/history/token_counting/base.py +67 -0
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/history/token_counting/openai.py +80 -0
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/history/token_counting/sentencepiece_counter.py +119 -0
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/history/token_counting/tokenizer_cache.py +90 -0
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/history/token_counting/utils.py +147 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/history/token_estimation.py +12 -12
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/llm.py +62 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/models.py +2 -2
- shotgun_sh-0.2.1.dev1/src/shotgun/agents/tools/web_search/__init__.py +87 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/web_search/anthropic.py +46 -40
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/web_search/gemini.py +31 -20
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/web_search/openai.py +4 -4
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/config.py +14 -55
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/feedback.py +1 -1
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/models.py +2 -2
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/models.py +4 -4
- shotgun_sh-0.2.1.dev1/src/shotgun/llm_proxy/__init__.py +16 -0
- shotgun_sh-0.2.1.dev1/src/shotgun/llm_proxy/clients.py +39 -0
- shotgun_sh-0.2.1.dev1/src/shotgun/llm_proxy/constants.py +8 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/main.py +6 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/posthog_telemetry.py +5 -3
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/app.py +3 -1
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/screens/chat_screen/command_providers.py +20 -0
- shotgun_sh-0.2.1.dev1/src/shotgun/tui/screens/model_picker.py +214 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/screens/provider_config.py +39 -26
- shotgun_sh-0.1.15.dev2/src/shotgun/agents/config/constants.py +0 -17
- shotgun_sh-0.1.15.dev2/src/shotgun/agents/config/models.py +0 -185
- shotgun_sh-0.1.15.dev2/src/shotgun/agents/config/provider.py +0 -206
- shotgun_sh-0.1.15.dev2/src/shotgun/agents/history/token_counting.py +0 -429
- shotgun_sh-0.1.15.dev2/src/shotgun/agents/tools/web_search/__init__.py +0 -60
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/LICENSE +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/README.md +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/hatch_build.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/agent_manager.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/config/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/conversation_history.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/conversation_manager.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/export.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/history/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/history/constants.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/history/context_extraction.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/history/history_building.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/history/message_utils.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/messages.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/plan.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/research.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/specify.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tasks.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/codebase/codebase_shell.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/codebase/directory_lister.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/codebase/file_read.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/codebase/models.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/codebase/query_graph.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/codebase/retrieve_code.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/file_management.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/user_interaction.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/agents/tools/web_search/utils.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/build_constants.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/codebase/commands.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/codebase/models.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/export.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/plan.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/research.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/specify.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/tasks.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/update.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/cli/utils.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/core/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/core/change_detector.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/core/code_retrieval.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/core/cypher_models.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/core/ingestor.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/core/language_config.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/core/manager.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/core/nl_query.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/core/parser_loader.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/codebase/service.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/logging_config.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/export.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/partials/codebase_understanding.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/partials/content_formatting.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/partials/interactive_mode.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/plan.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/research.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/specify.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/state/system_state.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/agents/tasks.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/codebase/cypher_query_patterns.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/codebase/cypher_system.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/codebase/enhanced_query_context.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/codebase/partials/cypher_rules.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/codebase/partials/graph_schema.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/codebase/partials/temporal_context.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/history/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/history/incremental_summarization.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/history/summarization.j2 +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/prompts/loader.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/py.typed +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/sdk/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/sdk/codebase.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/sdk/exceptions.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/sdk/models.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/sdk/services.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/sentry_telemetry.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/telemetry.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/commands/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/components/prompt_input.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/components/spinner.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/components/splash.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/components/vertical_tail.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/filtered_codebase_service.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/screens/chat.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/screens/chat.tcss +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/screens/chat_screen/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/screens/chat_screen/hint_message.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/screens/chat_screen/history.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/screens/directory_setup.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/screens/feedback.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/screens/splash.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/styles.tcss +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/utils/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/tui/utils/mode_progress.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/utils/__init__.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/utils/env_utils.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/utils/file_system_utils.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/utils/source_detection.py +0 -0
- {shotgun_sh-0.1.15.dev2 → shotgun_sh-0.2.1.dev1}/src/shotgun/utils/update_checker.py +0 -0
|
@@ -15,6 +15,9 @@ src/shotgun/build_constants.py
|
|
|
15
15
|
|
|
16
16
|
.DS_Store
|
|
17
17
|
|
|
18
|
+
# Tokenizer model files (downloaded on first use)
|
|
19
|
+
*.model
|
|
20
|
+
|
|
18
21
|
# Created by https://www.toptal.com/developers/gitignore/api/python,visualstudiocode
|
|
19
22
|
# Edit at https://www.toptal.com/developers/gitignore?templates=python,visualstudiocode
|
|
20
23
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shotgun-sh
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.2.1.dev1
|
|
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
|
|
@@ -22,7 +22,6 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
22
22
|
Classifier: Topic :: Utilities
|
|
23
23
|
Requires-Python: >=3.11
|
|
24
24
|
Requires-Dist: anthropic>=0.39.0
|
|
25
|
-
Requires-Dist: google-generativeai>=0.8.5
|
|
26
25
|
Requires-Dist: httpx>=0.27.0
|
|
27
26
|
Requires-Dist: jinja2>=3.1.0
|
|
28
27
|
Requires-Dist: kuzu>=0.7.0
|
|
@@ -32,6 +31,7 @@ Requires-Dist: packaging>=23.0
|
|
|
32
31
|
Requires-Dist: posthog>=3.0.0
|
|
33
32
|
Requires-Dist: pydantic-ai>=0.0.14
|
|
34
33
|
Requires-Dist: rich>=13.0.0
|
|
34
|
+
Requires-Dist: sentencepiece>=0.2.0
|
|
35
35
|
Requires-Dist: sentry-sdk[pure-eval]>=2.0.0
|
|
36
36
|
Requires-Dist: textual-dev>=1.7.0
|
|
37
37
|
Requires-Dist: textual>=6.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "shotgun-sh"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.2.1.dev1"
|
|
4
4
|
description = "AI-powered research, planning, and task management CLI tool"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -42,8 +42,8 @@ dependencies = [
|
|
|
42
42
|
"watchdog>=4.0.0",
|
|
43
43
|
"openai>=1.0.0",
|
|
44
44
|
"anthropic>=0.39.0",
|
|
45
|
-
"google-generativeai>=0.8.5",
|
|
46
45
|
"tiktoken>=0.7.0",
|
|
46
|
+
"sentencepiece>=0.2.0",
|
|
47
47
|
"packaging>=23.0",
|
|
48
48
|
]
|
|
49
49
|
|
|
@@ -18,7 +18,7 @@ from pydantic_ai.messages import (
|
|
|
18
18
|
ModelRequest,
|
|
19
19
|
)
|
|
20
20
|
|
|
21
|
-
from shotgun.agents.config import ProviderType,
|
|
21
|
+
from shotgun.agents.config import ProviderType, get_provider_model
|
|
22
22
|
from shotgun.agents.models import AgentType
|
|
23
23
|
from shotgun.logging_config import get_logger
|
|
24
24
|
from shotgun.prompts import PromptLoader
|
|
@@ -115,14 +115,13 @@ def create_base_agent(
|
|
|
115
115
|
"""
|
|
116
116
|
ensure_shotgun_directory_exists()
|
|
117
117
|
|
|
118
|
-
# Get configured model or fall back to
|
|
118
|
+
# Get configured model or fall back to first available provider
|
|
119
119
|
try:
|
|
120
120
|
model_config = get_provider_model(provider)
|
|
121
|
-
|
|
122
|
-
provider_name = provider or config_manager.load().default_provider
|
|
121
|
+
provider_name = model_config.provider
|
|
123
122
|
logger.debug(
|
|
124
123
|
"🤖 Creating agent with configured %s model: %s",
|
|
125
|
-
provider_name.upper(),
|
|
124
|
+
provider_name.value.upper(),
|
|
126
125
|
model_config.name,
|
|
127
126
|
)
|
|
128
127
|
# Use the Model instance directly (has API key baked in)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Configuration constants for Shotgun agents."""
|
|
2
|
+
|
|
3
|
+
from enum import StrEnum, auto
|
|
4
|
+
|
|
5
|
+
# Field names
|
|
6
|
+
API_KEY_FIELD = "api_key"
|
|
7
|
+
USER_ID_FIELD = "user_id"
|
|
8
|
+
CONFIG_VERSION_FIELD = "config_version"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ConfigSection(StrEnum):
|
|
12
|
+
"""Configuration file section names (JSON keys)."""
|
|
13
|
+
|
|
14
|
+
OPENAI = auto()
|
|
15
|
+
ANTHROPIC = auto()
|
|
16
|
+
GOOGLE = auto()
|
|
17
|
+
SHOTGUN = auto()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Backwards compatibility - deprecated
|
|
21
|
+
OPENAI_PROVIDER = ConfigSection.OPENAI.value
|
|
22
|
+
ANTHROPIC_PROVIDER = ConfigSection.ANTHROPIC.value
|
|
23
|
+
GOOGLE_PROVIDER = ConfigSection.GOOGLE.value
|
|
24
|
+
SHOTGUN_PROVIDER = ConfigSection.SHOTGUN.value
|
|
25
|
+
|
|
26
|
+
# Environment variable names
|
|
27
|
+
OPENAI_API_KEY_ENV = "OPENAI_API_KEY"
|
|
28
|
+
ANTHROPIC_API_KEY_ENV = "ANTHROPIC_API_KEY"
|
|
29
|
+
GEMINI_API_KEY_ENV = "GEMINI_API_KEY"
|
|
30
|
+
SHOTGUN_API_KEY_ENV = "SHOTGUN_API_KEY"
|
|
31
|
+
|
|
32
|
+
# Token limits
|
|
33
|
+
MEDIUM_TEXT_8K_TOKENS = 8192 # Default max_tokens for web search requests
|
|
@@ -13,17 +13,26 @@ from shotgun.utils import get_shotgun_home
|
|
|
13
13
|
|
|
14
14
|
from .constants import (
|
|
15
15
|
ANTHROPIC_API_KEY_ENV,
|
|
16
|
-
ANTHROPIC_PROVIDER,
|
|
17
16
|
API_KEY_FIELD,
|
|
18
17
|
GEMINI_API_KEY_ENV,
|
|
19
|
-
GOOGLE_PROVIDER,
|
|
20
18
|
OPENAI_API_KEY_ENV,
|
|
21
|
-
|
|
19
|
+
ConfigSection,
|
|
20
|
+
)
|
|
21
|
+
from .models import (
|
|
22
|
+
AnthropicConfig,
|
|
23
|
+
GoogleConfig,
|
|
24
|
+
ModelName,
|
|
25
|
+
OpenAIConfig,
|
|
26
|
+
ProviderType,
|
|
27
|
+
ShotgunAccountConfig,
|
|
28
|
+
ShotgunConfig,
|
|
22
29
|
)
|
|
23
|
-
from .models import ProviderType, ShotgunConfig
|
|
24
30
|
|
|
25
31
|
logger = get_logger(__name__)
|
|
26
32
|
|
|
33
|
+
# Type alias for provider configuration objects
|
|
34
|
+
ProviderConfig = OpenAIConfig | AnthropicConfig | GoogleConfig | ShotgunAccountConfig
|
|
35
|
+
|
|
27
36
|
|
|
28
37
|
class ConfigManager:
|
|
29
38
|
"""Manager for Shotgun configuration."""
|
|
@@ -69,20 +78,56 @@ class ConfigManager:
|
|
|
69
78
|
self._config = ShotgunConfig.model_validate(data)
|
|
70
79
|
logger.debug("Configuration loaded successfully from %s", self.config_path)
|
|
71
80
|
|
|
72
|
-
#
|
|
73
|
-
if not self.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
# Validate selected_model if in BYOK mode (no Shotgun key)
|
|
82
|
+
if not self._provider_has_api_key(self._config.shotgun):
|
|
83
|
+
should_save = False
|
|
84
|
+
|
|
85
|
+
# If selected_model is set, verify its provider has a key
|
|
86
|
+
if self._config.selected_model:
|
|
87
|
+
from .models import MODEL_SPECS
|
|
88
|
+
|
|
89
|
+
if self._config.selected_model in MODEL_SPECS:
|
|
90
|
+
spec = MODEL_SPECS[self._config.selected_model]
|
|
91
|
+
if not self.has_provider_key(spec.provider):
|
|
92
|
+
logger.info(
|
|
93
|
+
"Selected model %s provider has no API key, finding available model",
|
|
94
|
+
self._config.selected_model.value,
|
|
95
|
+
)
|
|
96
|
+
self._config.selected_model = None
|
|
97
|
+
should_save = True
|
|
98
|
+
else:
|
|
78
99
|
logger.info(
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
provider.value,
|
|
100
|
+
"Selected model %s not found in MODEL_SPECS, resetting",
|
|
101
|
+
self._config.selected_model.value,
|
|
82
102
|
)
|
|
83
|
-
self._config.
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
self._config.selected_model = None
|
|
104
|
+
should_save = True
|
|
105
|
+
|
|
106
|
+
# If no selected_model or it was invalid, find first available model
|
|
107
|
+
if not self._config.selected_model:
|
|
108
|
+
for provider in ProviderType:
|
|
109
|
+
if self.has_provider_key(provider):
|
|
110
|
+
# Set to that provider's default model
|
|
111
|
+
from .models import MODEL_SPECS, ModelName
|
|
112
|
+
|
|
113
|
+
# Find default model for this provider
|
|
114
|
+
provider_models = {
|
|
115
|
+
ProviderType.OPENAI: ModelName.GPT_5,
|
|
116
|
+
ProviderType.ANTHROPIC: ModelName.CLAUDE_OPUS_4_1,
|
|
117
|
+
ProviderType.GOOGLE: ModelName.GEMINI_2_5_PRO,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if provider in provider_models:
|
|
121
|
+
self._config.selected_model = provider_models[provider]
|
|
122
|
+
logger.info(
|
|
123
|
+
"Set selected_model to %s (first available provider)",
|
|
124
|
+
self._config.selected_model.value,
|
|
125
|
+
)
|
|
126
|
+
should_save = True
|
|
127
|
+
break
|
|
128
|
+
|
|
129
|
+
if should_save:
|
|
130
|
+
self.save(self._config)
|
|
86
131
|
|
|
87
132
|
return self._config
|
|
88
133
|
|
|
@@ -107,7 +152,6 @@ class ConfigManager:
|
|
|
107
152
|
# Create a new config with generated user_id
|
|
108
153
|
config = ShotgunConfig(
|
|
109
154
|
user_id=str(uuid.uuid4()),
|
|
110
|
-
config_version=1,
|
|
111
155
|
)
|
|
112
156
|
|
|
113
157
|
# Ensure directory exists
|
|
@@ -136,8 +180,13 @@ class ConfigManager:
|
|
|
136
180
|
**kwargs: Configuration fields to update (only api_key supported)
|
|
137
181
|
"""
|
|
138
182
|
config = self.load()
|
|
139
|
-
|
|
140
|
-
|
|
183
|
+
|
|
184
|
+
# Get provider config and check if it's shotgun
|
|
185
|
+
provider_config, is_shotgun = self._get_provider_config_and_type(
|
|
186
|
+
config, provider
|
|
187
|
+
)
|
|
188
|
+
# For non-shotgun providers, we need the enum for default provider logic
|
|
189
|
+
provider_enum = None if is_shotgun else self._ensure_provider_enum(provider)
|
|
141
190
|
|
|
142
191
|
# Only support api_key updates
|
|
143
192
|
if API_KEY_FIELD in kwargs:
|
|
@@ -152,23 +201,47 @@ class ConfigManager:
|
|
|
152
201
|
raise ValueError(f"Unsupported configuration fields: {unsupported_fields}")
|
|
153
202
|
|
|
154
203
|
# If no other providers have keys configured and we just added one,
|
|
155
|
-
# set
|
|
156
|
-
if API_KEY_FIELD in kwargs and api_key_value is not None:
|
|
204
|
+
# set selected_model to that provider's default model (only for LLM providers, not shotgun)
|
|
205
|
+
if not is_shotgun and API_KEY_FIELD in kwargs and api_key_value is not None:
|
|
206
|
+
# provider_enum is guaranteed to be non-None here since is_shotgun is False
|
|
207
|
+
if provider_enum is None:
|
|
208
|
+
raise RuntimeError("Provider enum should not be None for LLM providers")
|
|
157
209
|
other_providers = [p for p in ProviderType if p != provider_enum]
|
|
158
210
|
has_other_keys = any(self.has_provider_key(p) for p in other_providers)
|
|
159
211
|
if not has_other_keys:
|
|
160
|
-
|
|
212
|
+
# Set selected_model to this provider's default model
|
|
213
|
+
from .models import ModelName
|
|
214
|
+
|
|
215
|
+
provider_models = {
|
|
216
|
+
ProviderType.OPENAI: ModelName.GPT_5,
|
|
217
|
+
ProviderType.ANTHROPIC: ModelName.CLAUDE_OPUS_4_1,
|
|
218
|
+
ProviderType.GOOGLE: ModelName.GEMINI_2_5_PRO,
|
|
219
|
+
}
|
|
220
|
+
if provider_enum in provider_models:
|
|
221
|
+
config.selected_model = provider_models[provider_enum]
|
|
161
222
|
|
|
162
223
|
self.save(config)
|
|
163
224
|
|
|
164
225
|
def clear_provider_key(self, provider: ProviderType | str) -> None:
|
|
165
|
-
"""Remove the API key for the given provider."""
|
|
226
|
+
"""Remove the API key for the given provider (LLM provider or shotgun)."""
|
|
166
227
|
config = self.load()
|
|
167
|
-
|
|
168
|
-
|
|
228
|
+
|
|
229
|
+
# Get provider config (shotgun or LLM provider)
|
|
230
|
+
provider_config, _ = self._get_provider_config_and_type(config, provider)
|
|
231
|
+
|
|
169
232
|
provider_config.api_key = None
|
|
170
233
|
self.save(config)
|
|
171
234
|
|
|
235
|
+
def update_selected_model(self, model_name: "ModelName") -> None:
|
|
236
|
+
"""Update the selected model.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
model_name: Model to select
|
|
240
|
+
"""
|
|
241
|
+
config = self.load()
|
|
242
|
+
config.selected_model = model_name
|
|
243
|
+
self.save(config)
|
|
244
|
+
|
|
172
245
|
def has_provider_key(self, provider: ProviderType | str) -> bool:
|
|
173
246
|
"""Check if the given provider has a non-empty API key configured.
|
|
174
247
|
|
|
@@ -195,7 +268,8 @@ class ConfigManager:
|
|
|
195
268
|
def has_any_provider_key(self) -> bool:
|
|
196
269
|
"""Determine whether any provider has a configured API key."""
|
|
197
270
|
config = self.load()
|
|
198
|
-
|
|
271
|
+
# Check LLM provider keys (BYOK)
|
|
272
|
+
has_llm_key = any(
|
|
199
273
|
self._provider_has_api_key(self._get_provider_config(config, provider))
|
|
200
274
|
for provider in (
|
|
201
275
|
ProviderType.OPENAI,
|
|
@@ -203,6 +277,9 @@ class ConfigManager:
|
|
|
203
277
|
ProviderType.GOOGLE,
|
|
204
278
|
)
|
|
205
279
|
)
|
|
280
|
+
# Also check Shotgun Account key
|
|
281
|
+
has_shotgun_key = self._provider_has_api_key(config.shotgun)
|
|
282
|
+
return has_llm_key or has_shotgun_key
|
|
206
283
|
|
|
207
284
|
def initialize(self) -> ShotgunConfig:
|
|
208
285
|
"""Initialize configuration with defaults and save to file.
|
|
@@ -213,7 +290,6 @@ class ConfigManager:
|
|
|
213
290
|
# Generate unique user ID for new config
|
|
214
291
|
config = ShotgunConfig(
|
|
215
292
|
user_id=str(uuid.uuid4()),
|
|
216
|
-
config_version=1,
|
|
217
293
|
)
|
|
218
294
|
self.save(config)
|
|
219
295
|
logger.info(
|
|
@@ -225,26 +301,26 @@ class ConfigManager:
|
|
|
225
301
|
|
|
226
302
|
def _convert_secrets_to_secretstr(self, data: dict[str, Any]) -> None:
|
|
227
303
|
"""Convert plain text secrets in data to SecretStr objects."""
|
|
228
|
-
for
|
|
229
|
-
if
|
|
304
|
+
for section in ConfigSection:
|
|
305
|
+
if section.value in data and isinstance(data[section.value], dict):
|
|
230
306
|
if (
|
|
231
|
-
API_KEY_FIELD in data[
|
|
232
|
-
and data[
|
|
307
|
+
API_KEY_FIELD in data[section.value]
|
|
308
|
+
and data[section.value][API_KEY_FIELD] is not None
|
|
233
309
|
):
|
|
234
|
-
data[
|
|
235
|
-
data[
|
|
310
|
+
data[section.value][API_KEY_FIELD] = SecretStr(
|
|
311
|
+
data[section.value][API_KEY_FIELD]
|
|
236
312
|
)
|
|
237
313
|
|
|
238
314
|
def _convert_secretstr_to_plain(self, data: dict[str, Any]) -> None:
|
|
239
315
|
"""Convert SecretStr objects in data to plain text for JSON serialization."""
|
|
240
|
-
for
|
|
241
|
-
if
|
|
316
|
+
for section in ConfigSection:
|
|
317
|
+
if section.value in data and isinstance(data[section.value], dict):
|
|
242
318
|
if (
|
|
243
|
-
API_KEY_FIELD in data[
|
|
244
|
-
and data[
|
|
319
|
+
API_KEY_FIELD in data[section.value]
|
|
320
|
+
and data[section.value][API_KEY_FIELD] is not None
|
|
245
321
|
):
|
|
246
|
-
if hasattr(data[
|
|
247
|
-
data[
|
|
322
|
+
if hasattr(data[section.value][API_KEY_FIELD], "get_secret_value"):
|
|
323
|
+
data[section.value][API_KEY_FIELD] = data[section.value][
|
|
248
324
|
API_KEY_FIELD
|
|
249
325
|
].get_secret_value()
|
|
250
326
|
|
|
@@ -279,6 +355,38 @@ class ConfigManager:
|
|
|
279
355
|
|
|
280
356
|
return bool(value.strip())
|
|
281
357
|
|
|
358
|
+
def _is_shotgun_provider(self, provider: ProviderType | str) -> bool:
|
|
359
|
+
"""Check if provider string represents Shotgun Account.
|
|
360
|
+
|
|
361
|
+
Args:
|
|
362
|
+
provider: Provider type or string
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
True if provider is shotgun account
|
|
366
|
+
"""
|
|
367
|
+
return (
|
|
368
|
+
isinstance(provider, str)
|
|
369
|
+
and provider.lower() == ConfigSection.SHOTGUN.value
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
def _get_provider_config_and_type(
|
|
373
|
+
self, config: ShotgunConfig, provider: ProviderType | str
|
|
374
|
+
) -> tuple[ProviderConfig, bool]:
|
|
375
|
+
"""Get provider config, handling shotgun as special case.
|
|
376
|
+
|
|
377
|
+
Args:
|
|
378
|
+
config: Shotgun configuration
|
|
379
|
+
provider: Provider type or string
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
Tuple of (provider_config, is_shotgun)
|
|
383
|
+
"""
|
|
384
|
+
if self._is_shotgun_provider(provider):
|
|
385
|
+
return (config.shotgun, True)
|
|
386
|
+
|
|
387
|
+
provider_enum = self._ensure_provider_enum(provider)
|
|
388
|
+
return (self._get_provider_config(config, provider_enum), False)
|
|
389
|
+
|
|
282
390
|
def get_user_id(self) -> str:
|
|
283
391
|
"""Get the user ID from configuration.
|
|
284
392
|
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""Pydantic models for configuration."""
|
|
2
|
+
|
|
3
|
+
from enum import StrEnum
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field, PrivateAttr, SecretStr
|
|
6
|
+
from pydantic_ai.models import Model
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ProviderType(StrEnum):
|
|
10
|
+
"""Provider types for AI services."""
|
|
11
|
+
|
|
12
|
+
OPENAI = "openai"
|
|
13
|
+
ANTHROPIC = "anthropic"
|
|
14
|
+
GOOGLE = "google"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class KeyProvider(StrEnum):
|
|
18
|
+
"""Authentication method for accessing AI models."""
|
|
19
|
+
|
|
20
|
+
BYOK = "byok" # Bring Your Own Key (individual provider keys)
|
|
21
|
+
SHOTGUN = "shotgun" # Shotgun Account (unified LiteLLM proxy)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ModelName(StrEnum):
|
|
25
|
+
"""Available AI model names."""
|
|
26
|
+
|
|
27
|
+
GPT_5 = "gpt-5"
|
|
28
|
+
GPT_5_MINI = "gpt-5-mini"
|
|
29
|
+
CLAUDE_OPUS_4_1 = "claude-opus-4-1"
|
|
30
|
+
GEMINI_2_5_PRO = "gemini-2.5-pro"
|
|
31
|
+
GEMINI_2_5_FLASH = "gemini-2.5-flash"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ModelSpec(BaseModel):
|
|
35
|
+
"""Static specification for a model - just metadata."""
|
|
36
|
+
|
|
37
|
+
name: ModelName # Model identifier
|
|
38
|
+
provider: ProviderType
|
|
39
|
+
max_input_tokens: int
|
|
40
|
+
max_output_tokens: int
|
|
41
|
+
litellm_proxy_model_name: (
|
|
42
|
+
str # LiteLLM format (e.g., "openai/gpt-5", "gemini/gemini-2-pro")
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ModelConfig(BaseModel):
|
|
47
|
+
"""A fully configured model with API key and settings."""
|
|
48
|
+
|
|
49
|
+
name: ModelName # Model identifier
|
|
50
|
+
provider: ProviderType # Actual LLM provider (openai, anthropic, google)
|
|
51
|
+
key_provider: KeyProvider # Authentication method (byok or shotgun)
|
|
52
|
+
max_input_tokens: int
|
|
53
|
+
max_output_tokens: int
|
|
54
|
+
api_key: str
|
|
55
|
+
_model_instance: Model | None = PrivateAttr(default=None)
|
|
56
|
+
|
|
57
|
+
class Config:
|
|
58
|
+
arbitrary_types_allowed = True
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def model_instance(self) -> Model:
|
|
62
|
+
"""Lazy load the Model instance."""
|
|
63
|
+
if self._model_instance is None:
|
|
64
|
+
from .provider import get_or_create_model
|
|
65
|
+
|
|
66
|
+
self._model_instance = get_or_create_model(
|
|
67
|
+
self.provider, self.key_provider, self.name, self.api_key
|
|
68
|
+
)
|
|
69
|
+
return self._model_instance
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def pydantic_model_name(self) -> str:
|
|
73
|
+
"""Compute the full Pydantic AI model identifier. For backward compatibility."""
|
|
74
|
+
provider_prefix = {
|
|
75
|
+
ProviderType.OPENAI: "openai",
|
|
76
|
+
ProviderType.ANTHROPIC: "anthropic",
|
|
77
|
+
ProviderType.GOOGLE: "google-gla",
|
|
78
|
+
}
|
|
79
|
+
return f"{provider_prefix[self.provider]}:{self.name}"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# Model specifications registry (static metadata)
|
|
83
|
+
MODEL_SPECS: dict[ModelName, ModelSpec] = {
|
|
84
|
+
ModelName.GPT_5: ModelSpec(
|
|
85
|
+
name=ModelName.GPT_5,
|
|
86
|
+
provider=ProviderType.OPENAI,
|
|
87
|
+
max_input_tokens=400_000,
|
|
88
|
+
max_output_tokens=128_000,
|
|
89
|
+
litellm_proxy_model_name="openai/gpt-5",
|
|
90
|
+
),
|
|
91
|
+
ModelName.GPT_5_MINI: ModelSpec(
|
|
92
|
+
name=ModelName.GPT_5_MINI,
|
|
93
|
+
provider=ProviderType.OPENAI,
|
|
94
|
+
max_input_tokens=400_000,
|
|
95
|
+
max_output_tokens=128_000,
|
|
96
|
+
litellm_proxy_model_name="openai/gpt-5-mini",
|
|
97
|
+
),
|
|
98
|
+
ModelName.CLAUDE_OPUS_4_1: ModelSpec(
|
|
99
|
+
name=ModelName.CLAUDE_OPUS_4_1,
|
|
100
|
+
provider=ProviderType.ANTHROPIC,
|
|
101
|
+
max_input_tokens=200_000,
|
|
102
|
+
max_output_tokens=32_000,
|
|
103
|
+
litellm_proxy_model_name="anthropic/claude-opus-4-1",
|
|
104
|
+
),
|
|
105
|
+
ModelName.GEMINI_2_5_PRO: ModelSpec(
|
|
106
|
+
name=ModelName.GEMINI_2_5_PRO,
|
|
107
|
+
provider=ProviderType.GOOGLE,
|
|
108
|
+
max_input_tokens=1_000_000,
|
|
109
|
+
max_output_tokens=64_000,
|
|
110
|
+
litellm_proxy_model_name="gemini/gemini-2.5-pro",
|
|
111
|
+
),
|
|
112
|
+
ModelName.GEMINI_2_5_FLASH: ModelSpec(
|
|
113
|
+
name=ModelName.GEMINI_2_5_FLASH,
|
|
114
|
+
provider=ProviderType.GOOGLE,
|
|
115
|
+
max_input_tokens=1_000_000,
|
|
116
|
+
max_output_tokens=64_000,
|
|
117
|
+
litellm_proxy_model_name="gemini/gemini-2.5-flash",
|
|
118
|
+
),
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class OpenAIConfig(BaseModel):
|
|
123
|
+
"""Configuration for OpenAI provider."""
|
|
124
|
+
|
|
125
|
+
api_key: SecretStr | None = None
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class AnthropicConfig(BaseModel):
|
|
129
|
+
"""Configuration for Anthropic provider."""
|
|
130
|
+
|
|
131
|
+
api_key: SecretStr | None = None
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class GoogleConfig(BaseModel):
|
|
135
|
+
"""Configuration for Google provider."""
|
|
136
|
+
|
|
137
|
+
api_key: SecretStr | None = None
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class ShotgunAccountConfig(BaseModel):
|
|
141
|
+
"""Configuration for Shotgun Account (LiteLLM proxy)."""
|
|
142
|
+
|
|
143
|
+
api_key: SecretStr | None = None
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class ShotgunConfig(BaseModel):
|
|
147
|
+
"""Main configuration for Shotgun CLI."""
|
|
148
|
+
|
|
149
|
+
openai: OpenAIConfig = Field(default_factory=OpenAIConfig)
|
|
150
|
+
anthropic: AnthropicConfig = Field(default_factory=AnthropicConfig)
|
|
151
|
+
google: GoogleConfig = Field(default_factory=GoogleConfig)
|
|
152
|
+
shotgun: ShotgunAccountConfig = Field(default_factory=ShotgunAccountConfig)
|
|
153
|
+
selected_model: ModelName | None = Field(
|
|
154
|
+
default=None,
|
|
155
|
+
description="User-selected model",
|
|
156
|
+
)
|
|
157
|
+
user_id: str = Field(description="Unique anonymous user identifier")
|
|
158
|
+
config_version: int = Field(default=2, description="Configuration schema version")
|