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.
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/PKG-INFO +8 -9
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/README.md +6 -6
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/pyproject.toml +3 -4
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/agent_manager.py +100 -16
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/common.py +142 -28
- shotgun_sh-0.1.0.dev23/src/shotgun/agents/conversation_history.py +56 -0
- shotgun_sh-0.1.0.dev23/src/shotgun/agents/conversation_manager.py +105 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/export.py +5 -2
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/models.py +21 -7
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/plan.py +2 -1
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/research.py +2 -1
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/specify.py +2 -1
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tasks.py +5 -2
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/codebase_shell.py +2 -2
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/directory_lister.py +1 -1
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/file_read.py +1 -1
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/query_graph.py +1 -1
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/retrieve_code.py +1 -1
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/file_management.py +67 -2
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/main.py +9 -1
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/export.j2 +14 -11
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/partials/codebase_understanding.j2 +9 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +6 -9
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/plan.j2 +9 -13
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/research.j2 +11 -14
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/specify.j2 +9 -12
- shotgun_sh-0.1.0.dev23/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +19 -0
- shotgun_sh-0.1.0.dev23/src/shotgun/prompts/agents/state/system_state.j2 +31 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/tasks.j2 +12 -12
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sdk/models.py +1 -1
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sdk/services.py +0 -14
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/app.py +9 -4
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/chat.py +92 -30
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/chat_screen/command_providers.py +1 -1
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/chat_screen/history.py +6 -0
- shotgun_sh-0.1.0.dev23/src/shotgun/tui/utils/__init__.py +5 -0
- shotgun_sh-0.1.0.dev23/src/shotgun/tui/utils/mode_progress.py +257 -0
- shotgun_sh-0.1.0.dev20/src/shotgun/agents/artifact_state.py +0 -58
- shotgun_sh-0.1.0.dev20/src/shotgun/agents/tools/artifact_management.py +0 -481
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/__init__.py +0 -17
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/exceptions.py +0 -89
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/manager.py +0 -530
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/models.py +0 -334
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/service.py +0 -463
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/__init__.py +0 -10
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/loader.py +0 -252
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/models.py +0 -136
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/plan/delivery_and_release_plan.yaml +0 -66
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/research/market_research.yaml +0 -585
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/research/sdk_comparison.yaml +0 -257
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/specify/prd.yaml +0 -331
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/templates/specify/product_spec.yaml +0 -301
- shotgun_sh-0.1.0.dev20/src/shotgun/artifacts/utils.py +0 -76
- shotgun_sh-0.1.0.dev20/src/shotgun/prompts/agents/partials/artifact_system.j2 +0 -32
- shotgun_sh-0.1.0.dev20/src/shotgun/prompts/agents/state/artifact_templates_available.j2 +0 -20
- shotgun_sh-0.1.0.dev20/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +0 -15
- shotgun_sh-0.1.0.dev20/src/shotgun/prompts/agents/state/existing_artifacts_available.j2 +0 -25
- shotgun_sh-0.1.0.dev20/src/shotgun/prompts/agents/state/system_state.j2 +0 -9
- shotgun_sh-0.1.0.dev20/src/shotgun/sdk/artifact_models.py +0 -186
- shotgun_sh-0.1.0.dev20/src/shotgun/sdk/artifacts.py +0 -448
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/.gitignore +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/LICENSE +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/hatch_build.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/config/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/config/constants.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/config/manager.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/config/models.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/config/provider.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/compaction.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/constants.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/context_extraction.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/history_building.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/history_processors.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/message_utils.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/token_counting.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/history/token_estimation.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/codebase/models.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/user_interaction.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/web_search/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/web_search/anthropic.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/web_search/gemini.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/web_search/openai.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/agents/tools/web_search/utils.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/build_constants.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/codebase/commands.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/codebase/models.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/config.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/export.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/models.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/plan.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/research.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/specify.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/tasks.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/update.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/cli/utils.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/change_detector.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/code_retrieval.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/ingestor.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/language_config.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/manager.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/nl_query.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/core/parser_loader.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/models.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/codebase/service.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/logging_config.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/posthog_telemetry.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/partials/content_formatting.j2 +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/agents/partials/interactive_mode.j2 +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/cypher_query_patterns.j2 +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/cypher_system.j2 +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/enhanced_query_context.j2 +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/partials/cypher_rules.j2 +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/partials/graph_schema.j2 +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/codebase/partials/temporal_context.j2 +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/history/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/history/incremental_summarization.j2 +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/history/summarization.j2 +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/prompts/loader.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/py.typed +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sdk/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sdk/codebase.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sdk/exceptions.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/sentry_telemetry.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/telemetry.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/commands/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/components/prompt_input.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/components/spinner.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/components/splash.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/components/vertical_tail.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/chat.tcss +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/chat_screen/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/directory_setup.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/provider_config.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/screens/splash.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/tui/styles.tcss +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/utils/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/utils/env_utils.py +0 -0
- {shotgun_sh-0.1.0.dev20 → shotgun_sh-0.1.0.dev23}/src/shotgun/utils/file_system_utils.py +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
295
|
+
pyenv install 3.11
|
|
297
296
|
```
|
|
298
297
|
|
|
299
298
|
If using **uv** (recommended):
|
|
300
299
|
```bash
|
|
301
|
-
uv python install 3.
|
|
302
|
-
uv sync --python 3.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
242
|
+
pyenv install 3.11
|
|
243
243
|
```
|
|
244
244
|
|
|
245
245
|
If using **uv** (recommended):
|
|
246
246
|
```bash
|
|
247
|
-
uv python install 3.
|
|
248
|
-
uv sync --python 3.
|
|
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.
|
|
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.
|
|
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
|
+
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.
|
|
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
|
|
7
|
-
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
#
|
|
75
|
-
|
|
67
|
+
# Get existing files for the agent
|
|
68
|
+
existing_files = get_agent_existing_files(deps.agent_mode)
|
|
76
69
|
|
|
77
|
-
|
|
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
|
-
|
|
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
|
-
|
|
82
|
+
ModelRequest(
|
|
87
83
|
parts=[
|
|
88
|
-
|
|
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
|
|
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)
|