shotgun-sh 0.1.0.dev26__tar.gz → 0.1.0.dev28__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.dev26 → shotgun_sh-0.1.0.dev28}/PKG-INFO +1 -1
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/pyproject.toml +1 -1
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/agent_manager.py +46 -8
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/common.py +10 -9
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/history/history_processors.py +41 -25
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/history/message_utils.py +39 -1
- shotgun_sh-0.1.0.dev28/src/shotgun/agents/messages.py +35 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/file_management.py +18 -14
- shotgun_sh-0.1.0.dev28/src/shotgun/prompts/agents/export.j2 +350 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/agents/state/system_state.j2 +2 -4
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/agents/tasks.j2 +45 -7
- shotgun_sh-0.1.0.dev26/src/shotgun/prompts/agents/export.j2 +0 -214
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/.gitignore +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/LICENSE +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/README.md +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/hatch_build.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/config/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/config/constants.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/config/manager.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/config/models.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/config/provider.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/conversation_history.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/conversation_manager.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/export.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/history/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/history/compaction.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/history/constants.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/history/context_extraction.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/history/history_building.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/history/token_counting.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/history/token_estimation.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/models.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/plan.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/research.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/specify.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tasks.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/codebase/codebase_shell.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/codebase/directory_lister.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/codebase/file_read.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/codebase/models.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/codebase/query_graph.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/codebase/retrieve_code.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/user_interaction.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/web_search/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/web_search/anthropic.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/web_search/gemini.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/web_search/openai.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/web_search/utils.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/build_constants.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/codebase/commands.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/codebase/models.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/config.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/export.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/models.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/plan.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/research.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/specify.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/tasks.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/update.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/cli/utils.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/codebase/core/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/codebase/core/change_detector.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/codebase/core/code_retrieval.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/codebase/core/ingestor.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/codebase/core/language_config.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/codebase/core/manager.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/codebase/core/nl_query.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/codebase/core/parser_loader.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/codebase/models.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/codebase/service.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/logging_config.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/main.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/posthog_telemetry.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/agents/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/agents/partials/codebase_understanding.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/agents/partials/content_formatting.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/agents/partials/interactive_mode.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/agents/plan.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/agents/research.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/agents/specify.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/codebase/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/codebase/cypher_query_patterns.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/codebase/cypher_system.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/codebase/enhanced_query_context.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/codebase/partials/cypher_rules.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/codebase/partials/graph_schema.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/codebase/partials/temporal_context.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/history/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/history/incremental_summarization.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/history/summarization.j2 +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/prompts/loader.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/py.typed +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/sdk/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/sdk/codebase.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/sdk/exceptions.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/sdk/models.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/sdk/services.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/sentry_telemetry.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/telemetry.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/app.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/commands/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/components/prompt_input.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/components/spinner.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/components/splash.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/components/vertical_tail.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/screens/chat.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/screens/chat.tcss +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/screens/chat_screen/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/screens/chat_screen/command_providers.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/screens/chat_screen/hint_message.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/screens/chat_screen/history.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/screens/directory_setup.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/screens/provider_config.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/screens/splash.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/styles.tcss +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/utils/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/tui/utils/mode_progress.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/utils/__init__.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/utils/env_utils.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/utils/file_system_utils.py +0 -0
- {shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/utils/update_checker.py +0 -0
|
@@ -41,6 +41,7 @@ from shotgun.tui.screens.chat_screen.hint_message import HintMessage
|
|
|
41
41
|
|
|
42
42
|
from .export import create_export_agent
|
|
43
43
|
from .history.compaction import apply_persistent_compaction
|
|
44
|
+
from .messages import AgentSystemPrompt
|
|
44
45
|
from .models import AgentDeps, AgentRuntimeOptions
|
|
45
46
|
from .plan import create_plan_agent
|
|
46
47
|
from .research import create_research_agent
|
|
@@ -269,6 +270,9 @@ class AgentManager(Widget):
|
|
|
269
270
|
if deps is None:
|
|
270
271
|
raise ValueError("AgentDeps must be provided")
|
|
271
272
|
|
|
273
|
+
# Clear file tracker before each run to track only this run's operations
|
|
274
|
+
deps.file_tracker.clear()
|
|
275
|
+
|
|
272
276
|
if prompt:
|
|
273
277
|
self.ui_message_history.append(ModelRequest.user_text_prompt(prompt))
|
|
274
278
|
self._post_messages_updated()
|
|
@@ -278,15 +282,51 @@ class AgentManager(Widget):
|
|
|
278
282
|
|
|
279
283
|
deps.agent_mode = self._current_agent_type
|
|
280
284
|
|
|
285
|
+
# Filter out system prompts from other agent types
|
|
286
|
+
from pydantic_ai.messages import ModelRequestPart
|
|
287
|
+
|
|
288
|
+
filtered_history: list[ModelMessage] = []
|
|
289
|
+
for message in message_history:
|
|
290
|
+
# Keep all non-ModelRequest messages as-is
|
|
291
|
+
if not isinstance(message, ModelRequest):
|
|
292
|
+
filtered_history.append(message)
|
|
293
|
+
continue
|
|
294
|
+
|
|
295
|
+
# Filter out AgentSystemPrompts from other agent types
|
|
296
|
+
filtered_parts: list[ModelRequestPart] = []
|
|
297
|
+
for part in message.parts:
|
|
298
|
+
# Keep non-AgentSystemPrompt parts
|
|
299
|
+
if not isinstance(part, AgentSystemPrompt):
|
|
300
|
+
filtered_parts.append(part)
|
|
301
|
+
continue
|
|
302
|
+
|
|
303
|
+
# Only keep system prompts from the same agent type
|
|
304
|
+
if part.agent_mode == deps.agent_mode:
|
|
305
|
+
filtered_parts.append(part)
|
|
306
|
+
|
|
307
|
+
# Only add the message if it has parts remaining
|
|
308
|
+
if filtered_parts:
|
|
309
|
+
filtered_history.append(ModelRequest(parts=filtered_parts))
|
|
310
|
+
|
|
311
|
+
message_history = filtered_history
|
|
312
|
+
|
|
281
313
|
# Add a system status message so the agent knows whats going on
|
|
282
314
|
message_history = await add_system_status_message(deps, message_history)
|
|
283
315
|
|
|
284
|
-
# Check if the message history already has a system prompt
|
|
285
|
-
has_system_prompt =
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
316
|
+
# Check if the message history already has a system prompt from the same agent type
|
|
317
|
+
has_system_prompt = False
|
|
318
|
+
for message in message_history:
|
|
319
|
+
if not isinstance(message, ModelRequest):
|
|
320
|
+
continue
|
|
321
|
+
|
|
322
|
+
for part in message.parts:
|
|
323
|
+
if not isinstance(part, AgentSystemPrompt):
|
|
324
|
+
continue
|
|
325
|
+
|
|
326
|
+
# Check if it's from the same agent type
|
|
327
|
+
if part.agent_mode == deps.agent_mode:
|
|
328
|
+
has_system_prompt = True
|
|
329
|
+
break
|
|
290
330
|
|
|
291
331
|
# Always ensure we have a system prompt for the agent
|
|
292
332
|
# (compaction may remove it from persistent history, but agent needs it)
|
|
@@ -472,8 +512,6 @@ class AgentManager(Widget):
|
|
|
472
512
|
Returns:
|
|
473
513
|
List of messages without system prompt parts
|
|
474
514
|
"""
|
|
475
|
-
from pydantic_ai.messages import SystemPromptPart
|
|
476
|
-
|
|
477
515
|
filtered_messages: list[ModelMessage | HintMessage] = []
|
|
478
516
|
for msg in messages:
|
|
479
517
|
if isinstance(msg, HintMessage):
|
|
@@ -16,7 +16,6 @@ from pydantic_ai.agent import AgentRunResult
|
|
|
16
16
|
from pydantic_ai.messages import (
|
|
17
17
|
ModelMessage,
|
|
18
18
|
ModelRequest,
|
|
19
|
-
SystemPromptPart,
|
|
20
19
|
)
|
|
21
20
|
|
|
22
21
|
from shotgun.agents.config import ProviderType, get_config_manager, get_provider_model
|
|
@@ -29,6 +28,7 @@ from shotgun.utils.file_system_utils import get_shotgun_base_path
|
|
|
29
28
|
|
|
30
29
|
from .history import token_limit_compactor
|
|
31
30
|
from .history.compaction import apply_persistent_compaction
|
|
31
|
+
from .messages import AgentSystemPrompt, SystemStatusPrompt
|
|
32
32
|
from .models import AgentDeps, AgentRuntimeOptions, PipelineConfigEntry
|
|
33
33
|
from .tools import (
|
|
34
34
|
append_file,
|
|
@@ -85,7 +85,7 @@ async def add_system_status_message(
|
|
|
85
85
|
message_history.append(
|
|
86
86
|
ModelRequest(
|
|
87
87
|
parts=[
|
|
88
|
-
|
|
88
|
+
SystemStatusPrompt(content=system_state),
|
|
89
89
|
]
|
|
90
90
|
)
|
|
91
91
|
)
|
|
@@ -315,10 +315,9 @@ def extract_markdown_toc(agent_mode: AgentType | None) -> str | None:
|
|
|
315
315
|
# Only show # and ## headings from prior files, max 500 chars each
|
|
316
316
|
prior_toc = _extract_file_toc_content(file_path, max_depth=2, max_chars=500)
|
|
317
317
|
if prior_toc:
|
|
318
|
-
# Add section
|
|
319
|
-
file_label = prior_file.replace(".md", "").replace("_", " ").title()
|
|
318
|
+
# Add section with XML tags
|
|
320
319
|
toc_sections.append(
|
|
321
|
-
f"
|
|
320
|
+
f'<TABLE_OF_CONTENTS file_name="{prior_file}">\n{prior_toc}\n</TABLE_OF_CONTENTS>'
|
|
322
321
|
)
|
|
323
322
|
|
|
324
323
|
# Extract TOC from own file (full detail)
|
|
@@ -326,10 +325,10 @@ def extract_markdown_toc(agent_mode: AgentType | None) -> str | None:
|
|
|
326
325
|
own_path = base_path / config.own_file
|
|
327
326
|
own_toc = _extract_file_toc_content(own_path, max_depth=None, max_chars=2000)
|
|
328
327
|
if own_toc:
|
|
329
|
-
|
|
330
|
-
# Put own file TOC at the beginning
|
|
328
|
+
# Put own file TOC at the beginning with XML tags
|
|
331
329
|
toc_sections.insert(
|
|
332
|
-
0,
|
|
330
|
+
0,
|
|
331
|
+
f'<TABLE_OF_CONTENTS file_name="{config.own_file}">\n{own_toc}\n</TABLE_OF_CONTENTS>',
|
|
333
332
|
)
|
|
334
333
|
|
|
335
334
|
# Combine all sections
|
|
@@ -484,7 +483,9 @@ async def add_system_prompt_message(
|
|
|
484
483
|
|
|
485
484
|
# Create system message and prepend to message history
|
|
486
485
|
system_message = ModelRequest(
|
|
487
|
-
parts=[
|
|
486
|
+
parts=[
|
|
487
|
+
AgentSystemPrompt(content=system_prompt_content, agent_mode=deps.agent_mode)
|
|
488
|
+
]
|
|
488
489
|
)
|
|
489
490
|
message_history.insert(0, system_message)
|
|
490
491
|
logger.debug("✅ System prompt prepended as first message")
|
{shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/history/history_processors.py
RENAMED
|
@@ -6,12 +6,12 @@ from pydantic_ai.messages import (
|
|
|
6
6
|
ModelMessage,
|
|
7
7
|
ModelRequest,
|
|
8
8
|
ModelResponse,
|
|
9
|
-
SystemPromptPart,
|
|
10
9
|
TextPart,
|
|
11
10
|
UserPromptPart,
|
|
12
11
|
)
|
|
13
12
|
|
|
14
13
|
from shotgun.agents.config.models import shotgun_model_request
|
|
14
|
+
from shotgun.agents.messages import AgentSystemPrompt, SystemStatusPrompt
|
|
15
15
|
from shotgun.agents.models import AgentDeps
|
|
16
16
|
from shotgun.logging_config import get_logger
|
|
17
17
|
from shotgun.prompts import PromptLoader
|
|
@@ -20,8 +20,9 @@ from .constants import SUMMARY_MARKER, TOKEN_LIMIT_RATIO
|
|
|
20
20
|
from .context_extraction import extract_context_from_messages
|
|
21
21
|
from .history_building import ensure_ends_with_model_request
|
|
22
22
|
from .message_utils import (
|
|
23
|
+
get_agent_system_prompt,
|
|
23
24
|
get_first_user_request,
|
|
24
|
-
|
|
25
|
+
get_latest_system_status,
|
|
25
26
|
)
|
|
26
27
|
from .token_estimation import (
|
|
27
28
|
calculate_max_summarization_tokens as _calculate_max_summarization_tokens,
|
|
@@ -274,31 +275,39 @@ async def token_limit_compactor(
|
|
|
274
275
|
new_summary_part = create_marked_summary_part(summary_response)
|
|
275
276
|
|
|
276
277
|
# Extract essential context from messages before the last summary (if any)
|
|
277
|
-
|
|
278
|
+
agent_prompt = ""
|
|
279
|
+
system_status = ""
|
|
278
280
|
first_user_prompt = ""
|
|
279
281
|
if last_summary_index > 0:
|
|
280
|
-
# Get system and first user from original conversation
|
|
281
|
-
|
|
282
|
+
# Get agent system prompt and first user from original conversation
|
|
283
|
+
agent_prompt = get_agent_system_prompt(messages[:last_summary_index]) or ""
|
|
282
284
|
first_user_prompt = (
|
|
283
285
|
get_first_user_request(messages[:last_summary_index]) or ""
|
|
284
286
|
)
|
|
285
287
|
|
|
288
|
+
# Get the latest system status from all messages
|
|
289
|
+
system_status = get_latest_system_status(messages) or ""
|
|
290
|
+
|
|
286
291
|
# Create the updated summary message
|
|
287
292
|
updated_summary_message = ModelResponse(parts=[new_summary_part])
|
|
288
293
|
|
|
289
294
|
# Build final compacted history with CLEAN structure
|
|
290
295
|
compacted_messages: list[ModelMessage] = []
|
|
291
296
|
|
|
292
|
-
#
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
)
|
|
297
|
+
# Build parts for the initial request
|
|
298
|
+
from pydantic_ai.messages import ModelRequestPart
|
|
299
|
+
|
|
300
|
+
parts: list[ModelRequestPart] = []
|
|
301
|
+
if agent_prompt:
|
|
302
|
+
parts.append(AgentSystemPrompt(content=agent_prompt))
|
|
303
|
+
if system_status:
|
|
304
|
+
parts.append(SystemStatusPrompt(content=system_status))
|
|
305
|
+
if first_user_prompt:
|
|
306
|
+
parts.append(UserPromptPart(content=first_user_prompt))
|
|
307
|
+
|
|
308
|
+
# Only add if we have at least one part
|
|
309
|
+
if parts:
|
|
310
|
+
compacted_messages.append(ModelRequest(parts=parts))
|
|
302
311
|
|
|
303
312
|
# Add the summary
|
|
304
313
|
compacted_messages.append(updated_summary_message)
|
|
@@ -390,19 +399,26 @@ async def _full_compaction(
|
|
|
390
399
|
marked_summary_part = create_marked_summary_part(summary_response)
|
|
391
400
|
|
|
392
401
|
# Build compacted history structure
|
|
393
|
-
|
|
402
|
+
agent_prompt = get_agent_system_prompt(messages) or ""
|
|
403
|
+
system_status = get_latest_system_status(messages) or ""
|
|
394
404
|
user_prompt = get_first_user_request(messages) or ""
|
|
395
405
|
|
|
406
|
+
# Build parts for the initial request
|
|
407
|
+
from pydantic_ai.messages import ModelRequestPart
|
|
408
|
+
|
|
409
|
+
parts: list[ModelRequestPart] = []
|
|
410
|
+
if agent_prompt:
|
|
411
|
+
parts.append(AgentSystemPrompt(content=agent_prompt))
|
|
412
|
+
if system_status:
|
|
413
|
+
parts.append(SystemStatusPrompt(content=system_status))
|
|
414
|
+
if user_prompt:
|
|
415
|
+
parts.append(UserPromptPart(content=user_prompt))
|
|
416
|
+
|
|
396
417
|
# Create base structure
|
|
397
|
-
compacted_messages: list[ModelMessage] = [
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
UserPromptPart(content=user_prompt),
|
|
402
|
-
]
|
|
403
|
-
),
|
|
404
|
-
ModelResponse(parts=[marked_summary_part]),
|
|
405
|
-
]
|
|
418
|
+
compacted_messages: list[ModelMessage] = []
|
|
419
|
+
if parts:
|
|
420
|
+
compacted_messages.append(ModelRequest(parts=parts))
|
|
421
|
+
compacted_messages.append(ModelResponse(parts=[marked_summary_part]))
|
|
406
422
|
|
|
407
423
|
# Ensure history ends with ModelRequest for PydanticAI compatibility
|
|
408
424
|
compacted_messages = ensure_ends_with_model_request(compacted_messages, messages)
|
{shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/history/message_utils.py
RENAMED
|
@@ -7,6 +7,8 @@ from pydantic_ai.messages import (
|
|
|
7
7
|
UserPromptPart,
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
+
from shotgun.agents.messages import AgentSystemPrompt, SystemStatusPrompt
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
def get_first_user_request(messages: list[ModelMessage]) -> str | None:
|
|
12
14
|
"""Extract first user request content from messages."""
|
|
@@ -37,10 +39,46 @@ def get_user_content_from_request(request: ModelRequest) -> str | None:
|
|
|
37
39
|
|
|
38
40
|
|
|
39
41
|
def get_system_prompt(messages: list[ModelMessage]) -> str | None:
|
|
40
|
-
"""Extract system prompt from messages."""
|
|
42
|
+
"""Extract system prompt from messages (any SystemPromptPart)."""
|
|
41
43
|
for msg in messages:
|
|
42
44
|
if isinstance(msg, ModelRequest):
|
|
43
45
|
for part in msg.parts:
|
|
44
46
|
if isinstance(part, SystemPromptPart):
|
|
45
47
|
return part.content
|
|
46
48
|
return None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_agent_system_prompt(messages: list[ModelMessage]) -> str | None:
|
|
52
|
+
"""Extract the main agent system prompt from messages.
|
|
53
|
+
|
|
54
|
+
Prioritizes AgentSystemPrompt but falls back to generic SystemPromptPart
|
|
55
|
+
if no AgentSystemPrompt is found.
|
|
56
|
+
"""
|
|
57
|
+
# First try to find AgentSystemPrompt
|
|
58
|
+
for msg in messages:
|
|
59
|
+
if isinstance(msg, ModelRequest):
|
|
60
|
+
for part in msg.parts:
|
|
61
|
+
if isinstance(part, AgentSystemPrompt):
|
|
62
|
+
return part.content
|
|
63
|
+
|
|
64
|
+
# Fall back to any SystemPromptPart (excluding SystemStatusPrompt)
|
|
65
|
+
for msg in messages:
|
|
66
|
+
if isinstance(msg, ModelRequest):
|
|
67
|
+
for part in msg.parts:
|
|
68
|
+
if isinstance(part, SystemPromptPart) and not isinstance(
|
|
69
|
+
part, SystemStatusPrompt
|
|
70
|
+
):
|
|
71
|
+
return part.content
|
|
72
|
+
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def get_latest_system_status(messages: list[ModelMessage]) -> str | None:
|
|
77
|
+
"""Extract the most recent system status prompt from messages."""
|
|
78
|
+
# Iterate in reverse to find the most recent status
|
|
79
|
+
for msg in reversed(messages):
|
|
80
|
+
if isinstance(msg, ModelRequest):
|
|
81
|
+
for part in msg.parts:
|
|
82
|
+
if isinstance(part, SystemStatusPrompt):
|
|
83
|
+
return part.content
|
|
84
|
+
return None
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Custom message types for Shotgun agents.
|
|
2
|
+
|
|
3
|
+
This module defines specialized SystemPromptPart subclasses to distinguish
|
|
4
|
+
between different types of system prompts in the agent pipeline.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
|
|
9
|
+
from pydantic_ai.messages import SystemPromptPart
|
|
10
|
+
|
|
11
|
+
from shotgun.agents.models import AgentType
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class AgentSystemPrompt(SystemPromptPart):
|
|
16
|
+
"""System prompt containing the main agent instructions.
|
|
17
|
+
|
|
18
|
+
This is the primary system prompt that defines the agent's role,
|
|
19
|
+
capabilities, and behavior. It should be preserved during compaction.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
prompt_type: str = "agent"
|
|
23
|
+
agent_mode: AgentType | None = field(default=None)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class SystemStatusPrompt(SystemPromptPart):
|
|
28
|
+
"""System prompt containing current system status information.
|
|
29
|
+
|
|
30
|
+
This includes table of contents, available files, and other contextual
|
|
31
|
+
information about the current state. Only the most recent status should
|
|
32
|
+
be preserved during compaction.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
prompt_type: str = "status"
|
{shotgun_sh-0.1.0.dev26 → shotgun_sh-0.1.0.dev28}/src/shotgun/agents/tools/file_management.py
RENAMED
|
@@ -20,7 +20,15 @@ AGENT_DIRECTORIES = {
|
|
|
20
20
|
AgentType.SPECIFY: "specification.md",
|
|
21
21
|
AgentType.PLAN: "plan.md",
|
|
22
22
|
AgentType.TASKS: "tasks.md",
|
|
23
|
-
AgentType.EXPORT: "
|
|
23
|
+
AgentType.EXPORT: "*", # Export agent can write anywhere except protected files
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Files protected from export agent modifications
|
|
27
|
+
PROTECTED_AGENT_FILES = {
|
|
28
|
+
"research.md",
|
|
29
|
+
"specification.md",
|
|
30
|
+
"plan.md",
|
|
31
|
+
"tasks.md",
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
|
|
@@ -40,21 +48,17 @@ def _validate_agent_scoped_path(filename: str, agent_mode: AgentType | None) ->
|
|
|
40
48
|
base_path = get_shotgun_base_path()
|
|
41
49
|
|
|
42
50
|
if agent_mode and agent_mode in AGENT_DIRECTORIES:
|
|
43
|
-
# For export mode, allow writing to any file
|
|
51
|
+
# For export mode, allow writing to any file except protected agent files
|
|
44
52
|
if agent_mode == AgentType.EXPORT:
|
|
45
|
-
#
|
|
46
|
-
if
|
|
47
|
-
filename = f"exports/{filename}"
|
|
48
|
-
full_path = (base_path / filename).resolve()
|
|
49
|
-
|
|
50
|
-
# Ensure it's within .shotgun/exports/
|
|
51
|
-
exports_dir = base_path / "exports"
|
|
52
|
-
try:
|
|
53
|
-
full_path.relative_to(exports_dir.resolve())
|
|
54
|
-
except ValueError as e:
|
|
53
|
+
# Check if trying to write to a protected file
|
|
54
|
+
if filename in PROTECTED_AGENT_FILES:
|
|
55
55
|
raise ValueError(
|
|
56
|
-
f"Export agent
|
|
57
|
-
|
|
56
|
+
f"Export agent cannot write to protected file '{filename}'. "
|
|
57
|
+
f"Protected files are: {', '.join(sorted(PROTECTED_AGENT_FILES))}"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Allow writing anywhere else in .shotgun directory
|
|
61
|
+
full_path = (base_path / filename).resolve()
|
|
58
62
|
else:
|
|
59
63
|
# For other agents, only allow writing to their specific file
|
|
60
64
|
allowed_file = AGENT_DIRECTORIES[agent_mode]
|