shotgun-sh 0.1.0.dev20__tar.gz → 0.1.0.dev23__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.

Files changed (152) hide show
  1. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/PKG-INFO +8 -9
  2. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/README.md +6 -6
  3. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/pyproject.toml +3 -4
  4. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/agent_manager.py +100 -16
  5. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/common.py +142 -28
  6. shotgun_sh-0.1.0.dev23/src/shotgun/agents/conversation_history.py +56 -0
  7. shotgun_sh-0.1.0.dev23/src/shotgun/agents/conversation_manager.py +105 -0
  8. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/export.py +5 -2
  9. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/models.py +21 -7
  10. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/plan.py +2 -1
  11. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/research.py +2 -1
  12. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/specify.py +2 -1
  13. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tasks.py +5 -2
  14. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/codebase_shell.py +2 -2
  15. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/directory_lister.py +1 -1
  16. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/file_read.py +1 -1
  17. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/query_graph.py +1 -1
  18. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/retrieve_code.py +1 -1
  19. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/file_management.py +67 -2
  20. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/main.py +9 -1
  21. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/export.j2 +14 -11
  22. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/partials/codebase_understanding.j2 +9 -0
  23. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +6 -9
  24. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/plan.j2 +9 -13
  25. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/research.j2 +11 -14
  26. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/specify.j2 +9 -12
  27. shotgun_sh-0.1.0.dev23/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +19 -0
  28. shotgun_sh-0.1.0.dev23/src/shotgun/prompts/agents/state/system_state.j2 +31 -0
  29. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/tasks.j2 +12 -12
  30. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sdk/models.py +1 -1
  31. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sdk/services.py +0 -14
  32. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/app.py +9 -4
  33. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/chat.py +92 -30
  34. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/chat_screen/command_providers.py +1 -1
  35. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/chat_screen/history.py +6 -0
  36. shotgun_sh-0.1.0.dev23/src/shotgun/tui/utils/__init__.py +5 -0
  37. shotgun_sh-0.1.0.dev23/src/shotgun/tui/utils/mode_progress.py +257 -0
  38. shotgun_sh-0.1.0.dev20/src/shotgun/agents/artifact_state.py +0 -58
  39. shotgun_sh-0.1.0.dev20/src/shotgun/agents/tools/artifact_management.py +0 -481
  40. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/__init__.py +0 -17
  41. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/exceptions.py +0 -89
  42. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/manager.py +0 -530
  43. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/models.py +0 -334
  44. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/service.py +0 -463
  45. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/__init__.py +0 -10
  46. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/loader.py +0 -252
  47. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/models.py +0 -136
  48. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/plan/delivery_and_release_plan.yaml +0 -66
  49. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/research/market_research.yaml +0 -585
  50. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/research/sdk_comparison.yaml +0 -257
  51. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/specify/prd.yaml +0 -331
  52. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/specify/product_spec.yaml +0 -301
  53. shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/utils.py +0 -76
  54. shotgun_sh-0.1.0.dev20/src/shotgun/prompts/agents/partials/artifact_system.j2 +0 -32
  55. shotgun_sh-0.1.0.dev20/src/shotgun/prompts/agents/state/artifact_templates_available.j2 +0 -20
  56. shotgun_sh-0.1.0.dev20/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +0 -15
  57. shotgun_sh-0.1.0.dev20/src/shotgun/prompts/agents/state/existing_artifacts_available.j2 +0 -25
  58. shotgun_sh-0.1.0.dev20/src/shotgun/prompts/agents/state/system_state.j2 +0 -9
  59. shotgun_sh-0.1.0.dev20/src/shotgun/sdk/artifact_models.py +0 -186
  60. shotgun_sh-0.1.0.dev20/src/shotgun/sdk/artifacts.py +0 -448
  61. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/.gitignore +0 -0
  62. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/LICENSE +0 -0
  63. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/hatch_build.py +0 -0
  64. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/__init__.py +0 -0
  65. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/__init__.py +0 -0
  66. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/config/__init__.py +0 -0
  67. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/config/constants.py +0 -0
  68. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/config/manager.py +0 -0
  69. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/config/models.py +0 -0
  70. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/config/provider.py +0 -0
  71. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/__init__.py +0 -0
  72. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/compaction.py +0 -0
  73. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/constants.py +0 -0
  74. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/context_extraction.py +0 -0
  75. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/history_building.py +0 -0
  76. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/history_processors.py +0 -0
  77. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/message_utils.py +0 -0
  78. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/token_counting.py +0 -0
  79. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/token_estimation.py +0 -0
  80. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/__init__.py +0 -0
  81. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/__init__.py +0 -0
  82. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/models.py +0 -0
  83. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/user_interaction.py +0 -0
  84. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/web_search/__init__.py +0 -0
  85. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/web_search/anthropic.py +0 -0
  86. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/web_search/gemini.py +0 -0
  87. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/web_search/openai.py +0 -0
  88. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/web_search/utils.py +0 -0
  89. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/build_constants.py +0 -0
  90. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/__init__.py +0 -0
  91. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/codebase/__init__.py +0 -0
  92. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/codebase/commands.py +0 -0
  93. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/codebase/models.py +0 -0
  94. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/config.py +0 -0
  95. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/export.py +0 -0
  96. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/models.py +0 -0
  97. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/plan.py +0 -0
  98. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/research.py +0 -0
  99. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/specify.py +0 -0
  100. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/tasks.py +0 -0
  101. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/update.py +0 -0
  102. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/utils.py +0 -0
  103. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/__init__.py +0 -0
  104. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/__init__.py +0 -0
  105. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/change_detector.py +0 -0
  106. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/code_retrieval.py +0 -0
  107. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/ingestor.py +0 -0
  108. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/language_config.py +0 -0
  109. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/manager.py +0 -0
  110. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/nl_query.py +0 -0
  111. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/parser_loader.py +0 -0
  112. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/models.py +0 -0
  113. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/service.py +0 -0
  114. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/logging_config.py +0 -0
  115. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/posthog_telemetry.py +0 -0
  116. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/__init__.py +0 -0
  117. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/__init__.py +0 -0
  118. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/partials/content_formatting.j2 +0 -0
  119. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/partials/interactive_mode.j2 +0 -0
  120. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/__init__.py +0 -0
  121. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/cypher_query_patterns.j2 +0 -0
  122. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/cypher_system.j2 +0 -0
  123. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/enhanced_query_context.j2 +0 -0
  124. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/partials/cypher_rules.j2 +0 -0
  125. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/partials/graph_schema.j2 +0 -0
  126. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/partials/temporal_context.j2 +0 -0
  127. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/history/__init__.py +0 -0
  128. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/history/incremental_summarization.j2 +0 -0
  129. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/history/summarization.j2 +0 -0
  130. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/loader.py +0 -0
  131. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/py.typed +0 -0
  132. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sdk/__init__.py +0 -0
  133. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sdk/codebase.py +0 -0
  134. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sdk/exceptions.py +0 -0
  135. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sentry_telemetry.py +0 -0
  136. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/telemetry.py +0 -0
  137. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/__init__.py +0 -0
  138. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/commands/__init__.py +0 -0
  139. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/components/prompt_input.py +0 -0
  140. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/components/spinner.py +0 -0
  141. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/components/splash.py +0 -0
  142. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/components/vertical_tail.py +0 -0
  143. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/chat.tcss +0 -0
  144. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/chat_screen/__init__.py +0 -0
  145. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/directory_setup.py +0 -0
  146. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/provider_config.py +0 -0
  147. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/splash.py +0 -0
  148. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/styles.tcss +0 -0
  149. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/utils/__init__.py +0 -0
  150. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/utils/env_utils.py +0 -0
  151. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/utils/file_system_utils.py +0 -0
  152. {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/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.1.0.dev20
3
+ Version: 0.1.0.dev23
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
@@ -16,12 +16,11 @@ Classifier: Intended Audience :: Developers
16
16
  Classifier: License :: OSI Approved :: MIT License
17
17
  Classifier: Operating System :: OS Independent
18
18
  Classifier: Programming Language :: Python :: 3
19
- Classifier: Programming Language :: Python :: 3.10
20
19
  Classifier: Programming Language :: Python :: 3.11
21
20
  Classifier: Programming Language :: Python :: 3.12
22
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
22
  Classifier: Topic :: Utilities
24
- Requires-Python: >=3.10
23
+ Requires-Python: >=3.11
25
24
  Requires-Dist: anthropic>=0.39.0
26
25
  Requires-Dist: google-generativeai>=0.8.5
27
26
  Requires-Dist: httpx>=0.27.0
@@ -177,7 +176,7 @@ The update command automatically detects and uses the appropriate method:
177
176
 
178
177
  ### Requirements
179
178
 
180
- - **Python 3.10+** (3.13 recommended)
179
+ - **Python 3.11+** (3.13 recommended)
181
180
  - **uv** - Fast Python package installer and resolver
182
181
  - **actionlint** (optional) - For GitHub Actions workflow validation
183
182
 
@@ -289,17 +288,17 @@ go install github.com/rhysd/actionlint/cmd/actionlint@latest
289
288
 
290
289
  ### Python Version Management
291
290
 
292
- The project supports **Python 3.10+**. The `.python-version` file specifies Python 3.10 to ensure development against the minimum supported version.
291
+ The project supports **Python 3.11+**. The `.python-version` file specifies Python 3.11 to ensure development against the minimum supported version.
293
292
 
294
293
  If using **pyenv**:
295
294
  ```bash
296
- pyenv install 3.10.16 # or latest 3.10.x
295
+ pyenv install 3.11
297
296
  ```
298
297
 
299
298
  If using **uv** (recommended):
300
299
  ```bash
301
- uv python install 3.10
302
- uv sync --python 3.10
300
+ uv python install 3.11
301
+ uv sync --python 3.11
303
302
  ```
304
303
 
305
304
  ### Commit Message Convention
@@ -350,7 +349,7 @@ uv run cz commit
350
349
 
351
350
  GitHub Actions automatically:
352
351
  - Runs on pull requests and pushes to main
353
- - Tests with Python 3.10
352
+ - Tests with Python 3.11
354
353
  - Validates code with ruff, ruff-format, and mypy
355
354
  - Ensures all checks pass before merge
356
355
 
@@ -123,7 +123,7 @@ The update command automatically detects and uses the appropriate method:
123
123
 
124
124
  ### Requirements
125
125
 
126
- - **Python 3.10+** (3.13 recommended)
126
+ - **Python 3.11+** (3.13 recommended)
127
127
  - **uv** - Fast Python package installer and resolver
128
128
  - **actionlint** (optional) - For GitHub Actions workflow validation
129
129
 
@@ -235,17 +235,17 @@ go install github.com/rhysd/actionlint/cmd/actionlint@latest
235
235
 
236
236
  ### Python Version Management
237
237
 
238
- The project supports **Python 3.10+**. The `.python-version` file specifies Python 3.10 to ensure development against the minimum supported version.
238
+ The project supports **Python 3.11+**. The `.python-version` file specifies Python 3.11 to ensure development against the minimum supported version.
239
239
 
240
240
  If using **pyenv**:
241
241
  ```bash
242
- pyenv install 3.10.16 # or latest 3.10.x
242
+ pyenv install 3.11
243
243
  ```
244
244
 
245
245
  If using **uv** (recommended):
246
246
  ```bash
247
- uv python install 3.10
248
- uv sync --python 3.10
247
+ uv python install 3.11
248
+ uv sync --python 3.11
249
249
  ```
250
250
 
251
251
  ### Commit Message Convention
@@ -296,7 +296,7 @@ uv run cz commit
296
296
 
297
297
  GitHub Actions automatically:
298
298
  - Runs on pull requests and pushes to main
299
- - Tests with Python 3.10
299
+ - Tests with Python 3.11
300
300
  - Validates code with ruff, ruff-format, and mypy
301
301
  - Ensures all checks pass before merge
302
302
 
@@ -1,20 +1,19 @@
1
1
  [project]
2
2
  name = "shotgun-sh"
3
- version = "0.1.0.dev20"
3
+ version = "0.1.0.dev23"
4
4
  description = "AI-powered research, planning, and task management CLI tool"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
7
7
  authors = [
8
8
  { name = "Proofs.io", email = "hello@proofs.io" }
9
9
  ]
10
- requires-python = ">=3.10"
10
+ requires-python = ">=3.11"
11
11
  keywords = ["cli", "ai", "agent", "research", "planning", "task-management", "productivity", "llm", "pydantic-ai"]
12
12
  classifiers = [
13
13
  "Development Status :: 3 - Alpha",
14
14
  "Intended Audience :: Developers",
15
15
  "License :: OSI Approved :: MIT License",
16
16
  "Programming Language :: Python :: 3",
17
- "Programming Language :: Python :: 3.10",
18
17
  "Programming Language :: Python :: 3.11",
19
18
  "Programming Language :: Python :: 3.12",
20
19
  "Topic :: Software Development :: Libraries :: Python Modules",
@@ -101,7 +100,7 @@ ignore = ["E501", "T201"]
101
100
  "test/**/*.py" = ["S101", "B017"] # Allow assert statements and broad exceptions in tests
102
101
 
103
102
  [tool.mypy]
104
- python_version = "3.10"
103
+ python_version = "3.11"
105
104
  strict = true
106
105
  warn_return_any = true
107
106
  warn_unused_configs = true
@@ -1,10 +1,12 @@
1
1
  """Agent manager for coordinating multiple AI agents with shared message history."""
2
2
 
3
3
  import logging
4
- from collections.abc import AsyncIterable
5
- from dataclasses import dataclass, field
6
- from enum import Enum
7
- from typing import Any, cast
4
+ from collections.abc import AsyncIterable, Sequence
5
+ from dataclasses import dataclass, field, is_dataclass, replace
6
+ from typing import TYPE_CHECKING, Any, cast
7
+
8
+ if TYPE_CHECKING:
9
+ from shotgun.agents.conversation_history import ConversationState
8
10
 
9
11
  from pydantic_ai import (
10
12
  Agent,
@@ -21,6 +23,7 @@ from pydantic_ai.messages import (
21
23
  FunctionToolResultEvent,
22
24
  ModelMessage,
23
25
  ModelRequest,
26
+ ModelRequestPart,
24
27
  ModelResponse,
25
28
  ModelResponsePart,
26
29
  PartDeltaEvent,
@@ -32,11 +35,12 @@ from pydantic_ai.messages import (
32
35
  from textual.message import Message
33
36
  from textual.widget import Widget
34
37
 
35
- from shotgun.agents.common import add_system_prompt_message
38
+ from shotgun.agents.common import add_system_prompt_message, add_system_status_message
39
+ from shotgun.agents.models import AgentType, FileOperation
36
40
 
37
41
  from .export import create_export_agent
38
42
  from .history.compaction import apply_persistent_compaction
39
- from .models import AgentDeps, AgentRuntimeOptions, FileOperation
43
+ from .models import AgentDeps, AgentRuntimeOptions
40
44
  from .plan import create_plan_agent
41
45
  from .research import create_research_agent
42
46
  from .specify import create_specify_agent
@@ -45,16 +49,6 @@ from .tasks import create_tasks_agent
45
49
  logger = logging.getLogger(__name__)
46
50
 
47
51
 
48
- class AgentType(Enum):
49
- """Enumeration for available agent types (for Python < 3.11)."""
50
-
51
- RESEARCH = "research"
52
- PLAN = "plan"
53
- TASKS = "tasks"
54
- SPECIFY = "specify"
55
- EXPORT = "export"
56
-
57
-
58
52
  class MessageHistoryUpdated(Message):
59
53
  """Event posted when the message history is updated."""
60
54
 
@@ -122,6 +116,7 @@ class AgentManager(Widget):
122
116
  agent_runtime_options = AgentRuntimeOptions(
123
117
  interactive_mode=self.deps.interactive_mode,
124
118
  working_directory=self.deps.working_directory,
119
+ is_tui_context=self.deps.is_tui_context,
125
120
  max_iterations=self.deps.max_iterations,
126
121
  queue=self.deps.queue,
127
122
  tasks=self.deps.tasks,
@@ -280,6 +275,11 @@ class AgentManager(Widget):
280
275
  # Start with persistent message history
281
276
  message_history = self.message_history
282
277
 
278
+ deps.agent_mode = self._current_agent_type
279
+
280
+ # Add a system status message so the agent knows whats going on
281
+ message_history = await add_system_status_message(deps, message_history)
282
+
283
283
  # Check if the message history already has a system prompt
284
284
  has_system_prompt = any(
285
285
  hasattr(msg, "parts")
@@ -459,3 +459,87 @@ class AgentManager(Widget):
459
459
  file_operations=file_operations,
460
460
  )
461
461
  )
462
+
463
+ def _filter_system_prompts(
464
+ self, messages: list[ModelMessage]
465
+ ) -> list[ModelMessage]:
466
+ """Filter out system prompts from messages for UI display.
467
+
468
+ Args:
469
+ messages: List of messages that may contain system prompts
470
+
471
+ Returns:
472
+ List of messages without system prompt parts
473
+ """
474
+ from pydantic_ai.messages import SystemPromptPart
475
+
476
+ filtered_messages: list[ModelMessage] = []
477
+ for msg in messages:
478
+ parts: Sequence[ModelRequestPart] | Sequence[ModelResponsePart] | None = (
479
+ msg.parts if hasattr(msg, "parts") else None
480
+ )
481
+ if not parts:
482
+ filtered_messages.append(msg)
483
+ continue
484
+
485
+ non_system_parts = [
486
+ part for part in parts if not isinstance(part, SystemPromptPart)
487
+ ]
488
+
489
+ if not non_system_parts:
490
+ # Skip messages made up entirely of system prompt parts (e.g. system message)
491
+ continue
492
+
493
+ if len(non_system_parts) == len(parts):
494
+ # Nothing was filtered – keep original message
495
+ filtered_messages.append(msg)
496
+ continue
497
+
498
+ if is_dataclass(msg):
499
+ filtered_messages.append(
500
+ # ignore types because of the convoluted Request | Response types
501
+ replace(msg, parts=cast(Any, non_system_parts))
502
+ )
503
+ else:
504
+ filtered_messages.append(msg)
505
+ return filtered_messages
506
+
507
+ def get_conversation_state(self) -> "ConversationState":
508
+ """Get the current conversation state.
509
+
510
+ Returns:
511
+ ConversationState object containing UI and agent messages and current type
512
+ """
513
+ from shotgun.agents.conversation_history import ConversationState
514
+
515
+ return ConversationState(
516
+ agent_messages=self.message_history.copy(),
517
+ agent_type=self._current_agent_type.value,
518
+ )
519
+
520
+ def restore_conversation_state(self, state: "ConversationState") -> None:
521
+ """Restore conversation state from a saved state.
522
+
523
+ Args:
524
+ state: ConversationState object to restore
525
+ """
526
+ # Restore message history for agents (includes system prompts)
527
+ self.message_history = state.agent_messages.copy()
528
+
529
+ # Filter out system prompts for UI display
530
+ self.ui_message_history = self._filter_system_prompts(state.agent_messages)
531
+
532
+ # Restore agent type
533
+ self._current_agent_type = AgentType(state.agent_type)
534
+
535
+ # Notify listeners about the restored messages
536
+ self._post_messages_updated()
537
+
538
+
539
+ # Re-export AgentType for backward compatibility
540
+ __all__ = [
541
+ "AgentManager",
542
+ "AgentType",
543
+ "MessageHistoryUpdated",
544
+ "PartialResponseMessage",
545
+ ]
@@ -15,16 +15,16 @@ from pydantic_ai.agent import AgentRunResult
15
15
  from pydantic_ai.messages import (
16
16
  ModelMessage,
17
17
  ModelRequest,
18
- ModelResponse,
19
18
  SystemPromptPart,
20
- TextPart,
21
19
  )
22
20
 
23
21
  from shotgun.agents.config import ProviderType, get_config_manager, get_provider_model
22
+ from shotgun.agents.models import AgentType
24
23
  from shotgun.logging_config import get_logger
25
24
  from shotgun.prompts import PromptLoader
26
- from shotgun.sdk.services import get_artifact_service, get_codebase_service
25
+ from shotgun.sdk.services import get_codebase_service
27
26
  from shotgun.utils import ensure_shotgun_directory_exists
27
+ from shotgun.utils.file_system_utils import get_shotgun_base_path
28
28
 
29
29
  from .history import token_limit_compactor
30
30
  from .history.compaction import apply_persistent_compaction
@@ -40,14 +40,7 @@ from .tools import (
40
40
  retrieve_code,
41
41
  write_file,
42
42
  )
43
- from .tools.artifact_management import (
44
- create_artifact,
45
- list_artifact_templates,
46
- list_artifacts,
47
- read_artifact,
48
- read_artifact_section,
49
- write_artifact_section,
50
- )
43
+ from .tools.file_management import AGENT_DIRECTORIES
51
44
 
52
45
  logger = get_logger(__name__)
53
46
 
@@ -71,21 +64,24 @@ async def add_system_status_message(
71
64
  message_history = message_history or []
72
65
  codebase_understanding_graphs = await deps.codebase_service.list_graphs()
73
66
 
74
- # Collect artifact state information
75
- from .artifact_state import collect_artifact_state
67
+ # Get existing files for the agent
68
+ existing_files = get_agent_existing_files(deps.agent_mode)
76
69
 
77
- artifact_state = collect_artifact_state()
70
+ # Extract table of contents from the agent's markdown file
71
+ markdown_toc = extract_markdown_toc(deps.agent_mode)
78
72
 
79
73
  system_state = prompt_loader.render(
80
74
  "agents/state/system_state.j2",
81
75
  codebase_understanding_graphs=codebase_understanding_graphs,
82
- **artifact_state,
76
+ is_tui_context=deps.is_tui_context,
77
+ existing_files=existing_files,
78
+ markdown_toc=markdown_toc,
83
79
  )
84
80
 
85
81
  message_history.append(
86
- ModelResponse(
82
+ ModelRequest(
87
83
  parts=[
88
- TextPart(content=system_state),
84
+ SystemPromptPart(content=system_state),
89
85
  ]
90
86
  )
91
87
  )
@@ -98,14 +94,17 @@ def create_base_agent(
98
94
  load_codebase_understanding_tools: bool = True,
99
95
  additional_tools: list[Any] | None = None,
100
96
  provider: ProviderType | None = None,
97
+ agent_mode: AgentType | None = None,
101
98
  ) -> tuple[Agent[AgentDeps, str | DeferredToolRequests], AgentDeps]:
102
99
  """Create a base agent with common configuration.
103
100
 
104
101
  Args:
105
102
  system_prompt_fn: Function that will be decorated as system_prompt
106
103
  agent_runtime_options: Agent runtime options for the agent
104
+ load_codebase_understanding_tools: Whether to load codebase understanding tools
107
105
  additional_tools: Optional list of additional tools
108
106
  provider: Optional provider override. If None, uses configured default
107
+ agent_mode: The mode of the agent (research, plan, tasks, specify, export)
109
108
 
110
109
  Returns:
111
110
  Tuple of (Configured Pydantic AI agent, Agent dependencies)
@@ -127,13 +126,12 @@ def create_base_agent(
127
126
 
128
127
  # Create deps with model config and services
129
128
  codebase_service = get_codebase_service()
130
- artifact_service = get_artifact_service()
131
129
  deps = AgentDeps(
132
130
  **agent_runtime_options.model_dump(),
133
131
  llm_model=model_config,
134
132
  codebase_service=codebase_service,
135
- artifact_service=artifact_service,
136
133
  system_prompt_fn=system_prompt_fn,
134
+ agent_mode=agent_mode,
137
135
  )
138
136
 
139
137
  except Exception as e:
@@ -181,14 +179,6 @@ def create_base_agent(
181
179
  agent.tool(append_file)
182
180
  agent.tool(read_file)
183
181
 
184
- # Register artifact management tools (always available)
185
- agent.tool(create_artifact)
186
- agent.tool(list_artifacts)
187
- agent.tool(list_artifact_templates)
188
- agent.tool(read_artifact)
189
- agent.tool(read_artifact_section)
190
- agent.tool(write_artifact_section)
191
-
192
182
  # Register codebase understanding tools (conditional)
193
183
  if load_codebase_understanding_tools:
194
184
  agent.tool(query_graph)
@@ -200,10 +190,134 @@ def create_base_agent(
200
190
  else:
201
191
  logger.debug("🚫🧠 Codebase understanding tools not registered")
202
192
 
203
- logger.debug("✅ Agent creation complete with artifact and codebase tools")
193
+ logger.debug("✅ Agent creation complete with codebase tools")
204
194
  return agent, deps
205
195
 
206
196
 
197
+ def extract_markdown_toc(agent_mode: AgentType | None) -> str | None:
198
+ """Extract table of contents from agent's markdown file.
199
+
200
+ Args:
201
+ agent_mode: The agent mode to extract TOC for
202
+
203
+ Returns:
204
+ Formatted TOC string (up to 2000 chars) or None if not applicable
205
+ """
206
+ # Skip for EXPORT mode or no mode
207
+ if (
208
+ not agent_mode
209
+ or agent_mode == AgentType.EXPORT
210
+ or agent_mode not in AGENT_DIRECTORIES
211
+ ):
212
+ return None
213
+
214
+ base_path = get_shotgun_base_path()
215
+ md_file = AGENT_DIRECTORIES[agent_mode]
216
+ md_path = base_path / md_file
217
+
218
+ # Check if the markdown file exists
219
+ if not md_path.exists():
220
+ return None
221
+
222
+ try:
223
+ content = md_path.read_text(encoding="utf-8")
224
+ lines = content.split("\n")
225
+
226
+ # Extract headings
227
+ toc_lines = []
228
+ for line in lines:
229
+ stripped = line.strip()
230
+ if stripped.startswith("#"):
231
+ # Count the heading level
232
+ level = 0
233
+ for char in stripped:
234
+ if char == "#":
235
+ level += 1
236
+ else:
237
+ break
238
+
239
+ # Get the heading text (remove the # symbols and clean up)
240
+ heading_text = stripped[level:].strip()
241
+ if heading_text:
242
+ # Add indentation based on level
243
+ indent = " " * (level - 1)
244
+ toc_lines.append(f"{indent}{'#' * level} {heading_text}")
245
+
246
+ if not toc_lines:
247
+ return None
248
+
249
+ # Join and truncate to 2000 characters
250
+ toc = "\n".join(toc_lines)
251
+ if len(toc) > 2000:
252
+ toc = toc[:1997] + "..."
253
+
254
+ return toc
255
+
256
+ except Exception as e:
257
+ logger.debug(f"Failed to extract TOC from {md_file}: {e}")
258
+ return None
259
+
260
+
261
+ def get_agent_existing_files(agent_mode: AgentType | None = None) -> list[str]:
262
+ """Get list of existing files for the given agent mode.
263
+
264
+ Args:
265
+ agent_mode: The agent mode to check files for. If None, lists all files.
266
+
267
+ Returns:
268
+ List of existing file paths relative to .shotgun directory
269
+ """
270
+ base_path = get_shotgun_base_path()
271
+ existing_files = []
272
+
273
+ # If no agent mode, list all files in base path and first level subdirectories
274
+ if agent_mode is None:
275
+ # List files in the root .shotgun directory
276
+ for item in base_path.iterdir():
277
+ if item.is_file():
278
+ existing_files.append(item.name)
279
+ elif item.is_dir():
280
+ # List files in first-level subdirectories
281
+ for subitem in item.iterdir():
282
+ if subitem.is_file():
283
+ relative_path = subitem.relative_to(base_path)
284
+ existing_files.append(str(relative_path))
285
+ return existing_files
286
+
287
+ # Handle specific agent modes
288
+ if agent_mode not in AGENT_DIRECTORIES:
289
+ return []
290
+
291
+ if agent_mode == AgentType.EXPORT:
292
+ # For export agent, list all files in exports directory
293
+ exports_dir = base_path / "exports"
294
+ if exports_dir.exists():
295
+ for file_path in exports_dir.rglob("*"):
296
+ if file_path.is_file():
297
+ relative_path = file_path.relative_to(base_path)
298
+ existing_files.append(str(relative_path))
299
+ else:
300
+ # For other agents, check both .md file and directory with same name
301
+ allowed_file = AGENT_DIRECTORIES[agent_mode]
302
+
303
+ # Check for the .md file
304
+ md_file_path = base_path / allowed_file
305
+ if md_file_path.exists():
306
+ existing_files.append(allowed_file)
307
+
308
+ # Check for directory with same base name (e.g., research/ for research.md)
309
+ base_name = allowed_file.replace(".md", "")
310
+ dir_path = base_path / base_name
311
+ if dir_path.exists() and dir_path.is_dir():
312
+ # List all files in the directory
313
+ for file_path in dir_path.rglob("*"):
314
+ if file_path.is_file():
315
+ relative_path = file_path.relative_to(base_path)
316
+ existing_files.append(str(relative_path))
317
+
318
+ return existing_files
319
+
320
+
207
321
  def build_agent_system_prompt(
208
322
  agent_type: str,
209
323
  ctx: RunContext[AgentDeps],
@@ -0,0 +1,56 @@
1
+ """Models and utilities for persisting TUI conversation history."""
2
+
3
+ from datetime import datetime
4
+ from typing import Any
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field
7
+ from pydantic_ai.messages import (
8
+ ModelMessage,
9
+ ModelMessagesTypeAdapter,
10
+ )
11
+ from pydantic_core import to_jsonable_python
12
+
13
+
14
+ class ConversationState(BaseModel):
15
+ """Represents the complete state of a conversation in memory."""
16
+
17
+ agent_messages: list[ModelMessage]
18
+ agent_type: str # Will store AgentType.value
19
+
20
+ model_config = ConfigDict(arbitrary_types_allowed=True)
21
+
22
+
23
+ class ConversationHistory(BaseModel):
24
+ """Persistent conversation history for TUI sessions."""
25
+
26
+ version: int = 1
27
+ agent_history: list[dict[str, Any]] = Field(
28
+ default_factory=list
29
+ ) # Will store serialized ModelMessage objects
30
+ last_agent_model: str = "research"
31
+ updated_at: datetime = Field(default_factory=datetime.now)
32
+
33
+ model_config = ConfigDict(arbitrary_types_allowed=True)
34
+
35
+ def set_agent_messages(self, messages: list[ModelMessage]) -> None:
36
+ """Set agent_history from a list of ModelMessage objects.
37
+
38
+ Args:
39
+ messages: List of ModelMessage objects to serialize and store
40
+ """
41
+ # Serialize ModelMessage list to JSON-serializable format
42
+ self.agent_history = to_jsonable_python(
43
+ messages, fallback=lambda x: str(x), exclude_none=True
44
+ )
45
+
46
+ def get_agent_messages(self) -> list[ModelMessage]:
47
+ """Get agent_history as a list of ModelMessage objects.
48
+
49
+ Returns:
50
+ List of deserialized ModelMessage objects
51
+ """
52
+ if not self.agent_history:
53
+ return []
54
+
55
+ # Deserialize from JSON format back to ModelMessage objects
56
+ return ModelMessagesTypeAdapter.validate_python(self.agent_history)