shotgun-sh 0.1.0.dev17__py3-none-any.whl → 0.1.0.dev19__py3-none-any.whl

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.

@@ -17,17 +17,24 @@ from pydantic_ai.agent import AgentRunResult
17
17
  from pydantic_ai.messages import (
18
18
  AgentStreamEvent,
19
19
  FinalResultEvent,
20
+ FunctionToolCallEvent,
21
+ FunctionToolResultEvent,
20
22
  ModelMessage,
21
23
  ModelRequest,
22
24
  ModelResponse,
23
25
  ModelResponsePart,
24
26
  PartDeltaEvent,
25
27
  PartStartEvent,
28
+ SystemPromptPart,
29
+ ToolCallPart,
26
30
  ToolCallPartDelta,
27
31
  )
28
32
  from textual.message import Message
29
33
  from textual.widget import Widget
30
34
 
35
+ from shotgun.agents.common import add_system_prompt_message
36
+
37
+ from .export import create_export_agent
31
38
  from .history.compaction import apply_persistent_compaction
32
39
  from .models import AgentDeps, AgentRuntimeOptions, FileOperation
33
40
  from .plan import create_plan_agent
@@ -45,6 +52,7 @@ class AgentType(Enum):
45
52
  PLAN = "plan"
46
53
  TASKS = "tasks"
47
54
  SPECIFY = "specify"
55
+ EXPORT = "export"
48
56
 
49
57
 
50
58
  class MessageHistoryUpdated(Message):
@@ -132,6 +140,9 @@ class AgentManager(Widget):
132
140
  self.specify_agent, self.specify_deps = create_specify_agent(
133
141
  agent_runtime_options=agent_runtime_options
134
142
  )
143
+ self.export_agent, self.export_deps = create_export_agent(
144
+ agent_runtime_options=agent_runtime_options
145
+ )
135
146
 
136
147
  # Track current active agent
137
148
  self._current_agent_type: AgentType = initial_type
@@ -167,6 +178,7 @@ class AgentManager(Widget):
167
178
  AgentType.PLAN: self.plan_agent,
168
179
  AgentType.TASKS: self.tasks_agent,
169
180
  AgentType.SPECIFY: self.specify_agent,
181
+ AgentType.EXPORT: self.export_agent,
170
182
  }
171
183
  return agent_map[agent_type]
172
184
 
@@ -184,6 +196,7 @@ class AgentManager(Widget):
184
196
  AgentType.PLAN: self.plan_deps,
185
197
  AgentType.TASKS: self.tasks_deps,
186
198
  AgentType.SPECIFY: self.specify_deps,
199
+ AgentType.EXPORT: self.export_deps,
187
200
  }
188
201
  return deps_map[agent_type]
189
202
 
@@ -264,11 +277,6 @@ class AgentManager(Widget):
264
277
  self.ui_message_history.append(ModelRequest.user_text_prompt(prompt))
265
278
  self._post_messages_updated()
266
279
 
267
- # Ensure system prompt is added to message history before running agent
268
- from pydantic_ai.messages import SystemPromptPart
269
-
270
- from shotgun.agents.common import add_system_prompt_message
271
-
272
280
  # Start with persistent message history
273
281
  message_history = self.message_history
274
282
 
@@ -389,19 +397,33 @@ class AgentManager(Widget):
389
397
  state.latest_partial = partial_message
390
398
  self._post_partial_message(partial_message, False)
391
399
 
400
+ elif isinstance(event, FunctionToolCallEvent):
401
+ existing_call_idx = next(
402
+ (
403
+ i
404
+ for i, part in enumerate(partial_parts)
405
+ if isinstance(part, ToolCallPart)
406
+ and part.tool_call_id == event.part.tool_call_id
407
+ ),
408
+ None,
409
+ )
410
+ if existing_call_idx is not None:
411
+ partial_parts[existing_call_idx] = event.part
412
+ else:
413
+ partial_parts.append(event.part)
414
+ partial_message = self._build_partial_response(partial_parts)
415
+ if partial_message is not None:
416
+ state.latest_partial = partial_message
417
+ self._post_partial_message(partial_message, False)
418
+ elif isinstance(event, FunctionToolResultEvent):
419
+ self.ui_message_history.append(ModelRequest(parts=[event.result]))
420
+ self._post_messages_updated() ## this is what the user responded with
392
421
  elif isinstance(event, FinalResultEvent):
393
422
  final_message = (
394
423
  state.latest_partial
395
424
  or self._build_partial_response(partial_parts)
396
425
  )
397
- self._post_partial_message(final_message, True)
398
- state.latest_partial = None
399
- state.final_sent = True
400
- partial_parts.clear()
401
- self._stream_state = None
402
- break
403
-
404
- # Ignore other AgentStreamEvent variants (e.g. tool call notifications) for partial UI updates.
426
+ self._post_partial_message(final_message, False)
405
427
 
406
428
  except Exception: # pragma: no cover - defensive logging
407
429
  logger.exception(
shotgun/agents/common.py CHANGED
@@ -160,6 +160,7 @@ def create_base_agent(
160
160
  deps_type=AgentDeps,
161
161
  instrument=True,
162
162
  history_processors=[history_processor],
163
+ retries=3, # Default retry count for tool calls and output validation
163
164
  )
164
165
 
165
166
  # System prompt function is stored in deps and will be called manually in run_agent
@@ -176,9 +177,9 @@ def create_base_agent(
176
177
  logger.debug("📞 Interactive mode enabled - ask_user tool registered")
177
178
 
178
179
  # Register common file management tools (always available)
179
- agent.tool(read_file)
180
180
  agent.tool(write_file)
181
181
  agent.tool(append_file)
182
+ agent.tool(read_file)
182
183
 
183
184
  # Register artifact management tools (always available)
184
185
  agent.tool(create_artifact)
@@ -102,7 +102,7 @@ MODEL_SPECS: dict[str, ModelSpec] = {
102
102
  name="claude-3-5-sonnet-latest",
103
103
  provider=ProviderType.ANTHROPIC,
104
104
  max_input_tokens=200_000,
105
- max_output_tokens=20_000,
105
+ max_output_tokens=8_192,
106
106
  ),
107
107
  "gemini-2.5-pro": ModelSpec(
108
108
  name="gemini-2.5-pro",
@@ -4,12 +4,13 @@ import os
4
4
 
5
5
  from pydantic import SecretStr
6
6
  from pydantic_ai.models import Model
7
- from pydantic_ai.models.anthropic import AnthropicModel
7
+ from pydantic_ai.models.anthropic import AnthropicModel, AnthropicModelSettings
8
8
  from pydantic_ai.models.google import GoogleModel
9
9
  from pydantic_ai.models.openai import OpenAIChatModel
10
10
  from pydantic_ai.providers.anthropic import AnthropicProvider
11
11
  from pydantic_ai.providers.google import GoogleProvider
12
12
  from pydantic_ai.providers.openai import OpenAIProvider
13
+ from pydantic_ai.settings import ModelSettings
13
14
 
14
15
  from shotgun.logging_config import get_logger
15
16
 
@@ -47,18 +48,47 @@ def get_or_create_model(provider: ProviderType, model_name: str, api_key: str) -
47
48
  logger.debug("Creating new %s model instance: %s", provider.value, model_name)
48
49
 
49
50
  if provider == ProviderType.OPENAI:
51
+ # Get max_tokens from MODEL_SPECS to use full capacity
52
+ if model_name in MODEL_SPECS:
53
+ max_tokens = MODEL_SPECS[model_name].max_output_tokens
54
+ else:
55
+ max_tokens = 16_000 # Default for GPT models
56
+
50
57
  openai_provider = OpenAIProvider(api_key=api_key)
51
58
  _model_cache[cache_key] = OpenAIChatModel(
52
- model_name, provider=openai_provider
59
+ model_name,
60
+ provider=openai_provider,
61
+ settings=ModelSettings(max_tokens=max_tokens),
53
62
  )
54
63
  elif provider == ProviderType.ANTHROPIC:
64
+ # Get max_tokens from MODEL_SPECS to use full capacity
65
+ if model_name in MODEL_SPECS:
66
+ max_tokens = MODEL_SPECS[model_name].max_output_tokens
67
+ else:
68
+ max_tokens = 32_000 # Default for Claude models
69
+
55
70
  anthropic_provider = AnthropicProvider(api_key=api_key)
56
71
  _model_cache[cache_key] = AnthropicModel(
57
- model_name, provider=anthropic_provider
72
+ model_name,
73
+ provider=anthropic_provider,
74
+ settings=AnthropicModelSettings(
75
+ max_tokens=max_tokens,
76
+ timeout=600, # 10 minutes timeout for large responses
77
+ ),
58
78
  )
59
79
  elif provider == ProviderType.GOOGLE:
80
+ # Get max_tokens from MODEL_SPECS to use full capacity
81
+ if model_name in MODEL_SPECS:
82
+ max_tokens = MODEL_SPECS[model_name].max_output_tokens
83
+ else:
84
+ max_tokens = 64_000 # Default for Gemini models
85
+
60
86
  google_provider = GoogleProvider(api_key=api_key)
61
- _model_cache[cache_key] = GoogleModel(model_name, provider=google_provider)
87
+ _model_cache[cache_key] = GoogleModel(
88
+ model_name,
89
+ provider=google_provider,
90
+ settings=ModelSettings(max_tokens=max_tokens),
91
+ )
62
92
  else:
63
93
  raise ValueError(f"Unsupported provider: {provider}")
64
94
  else:
@@ -0,0 +1,93 @@
1
+ """Export agent factory and functions using Pydantic AI with file-based memory."""
2
+
3
+ from functools import partial
4
+
5
+ from pydantic_ai import (
6
+ Agent,
7
+ DeferredToolRequests,
8
+ )
9
+ from pydantic_ai.agent import AgentRunResult
10
+ from pydantic_ai.messages import ModelMessage
11
+
12
+ from shotgun.agents.config import ProviderType
13
+ from shotgun.logging_config import get_logger
14
+
15
+ from .common import (
16
+ add_system_status_message,
17
+ build_agent_system_prompt,
18
+ create_base_agent,
19
+ create_usage_limits,
20
+ run_agent,
21
+ )
22
+ from .models import AgentDeps, AgentRuntimeOptions
23
+
24
+ logger = get_logger(__name__)
25
+
26
+
27
+ def create_export_agent(
28
+ agent_runtime_options: AgentRuntimeOptions, provider: ProviderType | None = None
29
+ ) -> tuple[Agent[AgentDeps, str | DeferredToolRequests], AgentDeps]:
30
+ """Create an export agent with file management capabilities.
31
+
32
+ Args:
33
+ agent_runtime_options: Agent runtime options for the agent
34
+ provider: Optional provider override. If None, uses configured default
35
+
36
+ Returns:
37
+ Tuple of (Configured Pydantic AI agent for export management, Agent dependencies)
38
+ """
39
+ logger.debug("Initializing export agent")
40
+ # Use partial to create system prompt function for export agent
41
+ system_prompt_fn = partial(build_agent_system_prompt, "export")
42
+
43
+ agent, deps = create_base_agent(
44
+ system_prompt_fn, agent_runtime_options, provider=provider
45
+ )
46
+ return agent, deps
47
+
48
+
49
+ async def run_export_agent(
50
+ agent: Agent[AgentDeps, str | DeferredToolRequests],
51
+ instruction: str,
52
+ deps: AgentDeps,
53
+ message_history: list[ModelMessage] | None = None,
54
+ ) -> AgentRunResult[str | DeferredToolRequests]:
55
+ """Export artifacts based on the given instruction.
56
+
57
+ Args:
58
+ agent: The configured export agent
59
+ instruction: The export instruction
60
+ deps: Agent dependencies
61
+ message_history: Optional message history for conversation continuity
62
+
63
+ Returns:
64
+ AgentRunResult containing the export process output
65
+ """
66
+ logger.debug("📤 Starting export for instruction: %s", instruction)
67
+
68
+ message_history = await add_system_status_message(deps, message_history)
69
+
70
+ # Let the agent use its tools to read existing artifacts and export them
71
+ full_prompt = f"Export artifacts or findings based on: {instruction}"
72
+
73
+ try:
74
+ # Create usage limits for responsible API usage
75
+ usage_limits = create_usage_limits()
76
+
77
+ result = await run_agent(
78
+ agent=agent,
79
+ prompt=full_prompt,
80
+ deps=deps,
81
+ message_history=message_history,
82
+ usage_limits=usage_limits,
83
+ )
84
+
85
+ logger.debug("✅ Export completed successfully")
86
+ return result
87
+
88
+ except Exception as e:
89
+ import traceback
90
+
91
+ logger.error("Full traceback:\n%s", traceback.format_exc())
92
+ logger.error("❌ Export failed: %s", str(e))
93
+ raise
@@ -13,8 +13,9 @@ logger = get_logger(__name__)
13
13
  async def ask_user(ctx: RunContext[AgentDeps], question: str) -> str:
14
14
  """Ask the human a question and return the answer.
15
15
 
16
+
16
17
  Args:
17
- question: The question to ask the user
18
+ question: The question to ask the user with a clear CTA at the end. Needs to be is readable, clear, and easy to understand. Use Markdown formatting. Make key phrases and words stand out.
18
19
 
19
20
  Returns:
20
21
  The user's response as a string
shotgun/cli/export.py ADDED
@@ -0,0 +1,81 @@
1
+ """Export command for shotgun CLI."""
2
+
3
+ import asyncio
4
+ from typing import Annotated
5
+
6
+ import typer
7
+
8
+ from shotgun.agents.config import ProviderType
9
+ from shotgun.agents.export import (
10
+ create_export_agent,
11
+ run_export_agent,
12
+ )
13
+ from shotgun.agents.models import AgentRuntimeOptions
14
+ from shotgun.logging_config import get_logger
15
+
16
+ app = typer.Typer(
17
+ name="export", help="Export artifacts to various formats with agentic approach"
18
+ )
19
+ logger = get_logger(__name__)
20
+
21
+
22
+ @app.callback(invoke_without_command=True)
23
+ def export(
24
+ instruction: Annotated[
25
+ str, typer.Argument(help="Export instruction or format specification")
26
+ ],
27
+ non_interactive: Annotated[
28
+ bool,
29
+ typer.Option(
30
+ "--non-interactive", "-n", help="Disable user interaction (for CI/CD)"
31
+ ),
32
+ ] = False,
33
+ provider: Annotated[
34
+ ProviderType | None,
35
+ typer.Option("--provider", "-p", help="AI provider to use (overrides default)"),
36
+ ] = None,
37
+ ) -> None:
38
+ """Export artifacts and findings to various formats.
39
+
40
+ This command exports research, plans, tasks, and other project artifacts
41
+ to different formats like Markdown, HTML, JSON, CSV, or project management
42
+ tool formats. The AI agent will analyze available content and transform
43
+ it according to your export requirements.
44
+ """
45
+
46
+ logger.info("📤 Export Instruction: %s", instruction)
47
+
48
+ try:
49
+ # Track export command usage
50
+ from shotgun.posthog_telemetry import track_event
51
+
52
+ track_event(
53
+ "export_command",
54
+ {
55
+ "non_interactive": non_interactive,
56
+ "provider": provider.value if provider else "default",
57
+ },
58
+ )
59
+
60
+ # Create agent dependencies
61
+ agent_runtime_options = AgentRuntimeOptions(
62
+ interactive_mode=not non_interactive
63
+ )
64
+
65
+ # Create the export agent with deps and provider
66
+ agent, deps = create_export_agent(agent_runtime_options, provider)
67
+
68
+ # Start export process
69
+ logger.info("🎯 Starting export...")
70
+ result = asyncio.run(run_export_agent(agent, instruction, deps))
71
+
72
+ # Display results
73
+ logger.info("✅ Export Complete!")
74
+ logger.info("📤 Results:")
75
+ logger.info("%s", result.output)
76
+
77
+ except Exception as e:
78
+ logger.error("❌ Error during export: %s", str(e))
79
+ import traceback
80
+
81
+ logger.debug("Full traceback:\n%s", traceback.format_exc())
@@ -27,6 +27,14 @@ from shotgun.logging_config import get_logger
27
27
  logger = get_logger(__name__)
28
28
 
29
29
 
30
+ class CodebaseAlreadyIndexedError(Exception):
31
+ """Raised when a codebase is already indexed."""
32
+
33
+ def __init__(self, repo_path: str):
34
+ self.repo_path = repo_path
35
+ super().__init__(f"Codebase already indexed: {repo_path}")
36
+
37
+
30
38
  class CodebaseFileHandler(FileSystemEventHandler):
31
39
  """Handles file system events for code graph updates."""
32
40
 
@@ -339,9 +347,7 @@ class CodebaseGraphManager:
339
347
 
340
348
  # Check if graph already exists
341
349
  if graph_path.exists():
342
- raise ValueError(
343
- f"Graph already exists for {repo_path}. Use update_graph() to modify it."
344
- )
350
+ raise CodebaseAlreadyIndexedError(repo_path)
345
351
 
346
352
  # Import the builder from local core module
347
353
  from shotgun.codebase.core import CodebaseIngestor
shotgun/main.py CHANGED
@@ -7,7 +7,7 @@ from dotenv import load_dotenv
7
7
 
8
8
  from shotgun import __version__
9
9
  from shotgun.agents.config import get_config_manager
10
- from shotgun.cli import codebase, config, plan, research, specify, tasks, update
10
+ from shotgun.cli import codebase, config, export, plan, research, specify, tasks, update
11
11
  from shotgun.logging_config import configure_root_logger, get_logger
12
12
  from shotgun.posthog_telemetry import setup_posthog_observability
13
13
  from shotgun.sentry_telemetry import setup_sentry_observability
@@ -66,6 +66,7 @@ app.add_typer(research.app, name="research", help="Perform research with agentic
66
66
  app.add_typer(plan.app, name="plan", help="Generate structured plans")
67
67
  app.add_typer(specify.app, name="specify", help="Generate comprehensive specifications")
68
68
  app.add_typer(tasks.app, name="tasks", help="Generate task lists with agentic approach")
69
+ app.add_typer(export.app, name="export", help="Export artifacts to various formats")
69
70
  app.add_typer(update.app, name="update", help="Check for and install updates")
70
71
 
71
72
 
@@ -0,0 +1,83 @@
1
+ You are an experienced Export Specialist and Data Transformation Expert.
2
+
3
+ Your job is to help export artifacts, research findings, plans, and other project data to various formats and destinations.
4
+
5
+ {% include 'agents/partials/common_agent_system_prompt.j2' %}
6
+
7
+ ## EXPORT WORKFLOW
8
+
9
+ For export tasks:
10
+ 1. **Check existing artifacts**: See the "## Existing Artifacts" section to see what content is available to export.
11
+ 2. **Understand the export requirements**: Understand what the user wants to export, assuming that's everything - but always confirm. For example some research might not be relevant for export. Priority: Tasks, Plan, Specify, Research.
12
+ 3. **Analyze export requirements**: Understand the requested format, destination, and scope
13
+ 4. **Read source content**: Read the content of all the relevant artifacts.
14
+ 5. **Transform and format**: Convert content to the requested format
15
+ 5. **Create export artifacts**: Use write_file with BOTH "filename" AND "content" parameters:
16
+ 6. **Validate output**: Ensure the export meets requirements and is properly formatted using read_file()
17
+
18
+ ## SUPPORTED EXPORT FORMATS
19
+
20
+ - **AGENTS.md**: See below
21
+ - **Markdown (.md)**: Nicely formatted Markdown file with everything the user wants to export
22
+
23
+ ### AGENTS.md
24
+
25
+ Your task: generate an **AGENTS.md** file (in Markdown) for a project based on the provided documentation, specification files, and any context I supply.
26
+
27
+ **Instructions / constraints**:
28
+ - Use clear headings (e.g. “Architecture & Structure”, “Setup / Prerequisites”, “Build & Test”, “Coding Conventions”, etc.).
29
+ - For sections with commands, wrap them in backticks so they can be executed directly.
30
+ - Provide enough detail so that an AI coding agent can understand how to build, test, validate, deploy, and work with the project, without needing to hunt in scattered docs.
31
+ - Link or refer to deeper docs (README, design docs) rather than duplicating large content.
32
+ - If the project is a monorepo or modular, mention whether nested AGENTS.md may override parts.
33
+ - Do **not** include large prose — focus on actionable instructions and bullet lists.
34
+ - Assume the agent must obey programmatic checks listed in the file after generating code.
35
+
36
+
37
+ ## EXPORT PRINCIPLES
38
+
39
+ - Preserve content structure and meaning during transformation
40
+ - Include proper headers, metadata, and formatting for target format
41
+ - Maintain links, references, and cross-references where applicable
42
+ - Create self-contained exports that can be used independently
43
+ - Add appropriate file extensions and format indicators
44
+ - Include export timestamp and source information
45
+ - Validate exported content is properly formatted and complete
46
+ - Handle missing or incomplete source data gracefully
47
+ - Consider target audience and use case for formatting decisions
48
+
49
+ {% if interactive_mode %}
50
+ USER INTERACTION - CLARIFY EXPORT REQUIREMENTS:
51
+
52
+ - ALWAYS ask clarifying questions when export requirements are unclear
53
+ - Use ask_user tool to gather specific details about:
54
+ - Target format and file type preferences
55
+ - Intended use case and audience for the export
56
+ - Specific content sections or artifacts to include/exclude
57
+ - Output structure and organization preferences
58
+ - Destination (where to save the file)
59
+ - Ask follow-up questions to ensure exports meet exact needs
60
+ - Confirm export scope and format before proceeding with large exports
61
+ - Better to ask 2-3 targeted questions than create generic exports
62
+ {% else %}
63
+ NON-INTERACTIVE MODE - MAKE REASONABLE EXPORT DECISIONS:
64
+
65
+ - Make reasonable assumptions about format based on content type
66
+ - Use standard formats and conventions for the target format
67
+ - Include comprehensive content unless scope is clearly limited
68
+ - Apply sensible default formatting and structure
69
+ - Export to commonly used and widely compatible formats
70
+ - Include standard metadata and documentation
71
+ {% endif %}
72
+
73
+ IMPORTANT RULES:
74
+ - Always verify source content exists before attempting export
75
+ - Preserve all critical information during format conversion
76
+ - Include source attribution and export metadata
77
+ - Create well-structured, properly formatted output
78
+ {% if interactive_mode %}
79
+ - When export requirements are ambiguous, ASK before proceeding
80
+ {% else %}
81
+ - When requirements are unclear, use industry standard practices
82
+ {% endif %}
83
+ - Ensure exported content is self-contained and usable
@@ -7,16 +7,20 @@ Your extensive expertise spans, among other things:
7
7
 
8
8
  ## KEY RULES
9
9
 
10
- 0. Above all, prefer using tools to do the work and NEVER respond with text.
11
- 1. **Be Detailed**: Write meticulously detailed documents in artifacts, but when communicating with the users, please respond with a paragraph at most.
12
- 2. **Be Helpful**: Always prioritize user needs and provide actionable assistance
13
- 3. **Be Precise**: Provide specific, detailed responses rather than vague generalities
14
- 4. **Be Collaborative**: Work effectively with other agents when needed
15
- 5. **Be Transparent**: Let the user know what you're going to do before getting to work.
16
- 6. **Be Efficient**: Avoid redundant work - check existing artifacts and agent outputs
17
- 7. **Be Creative**: If the user seems not to know something, always be creative and come up with ideas that fit their thinking.
18
- 8. Greet the user when you're just starting to work.
19
- 9. DO NOT repeat yourself.
10
+ {% if interactive_mode %}
11
+ 0. Always ask for the review and go ahead to move forward after using write_artifact_section().
12
+ {% endif %}
13
+ 1. Above all, prefer using tools to do the work and NEVER respond with text.
14
+ 2. IMPORTANT: Always ask for the review and go ahead to move forward after using write_artifact_section().
15
+ 3. **Be Detailed**: Write meticulously detailed documents in artifacts, but when communicating with the users, please respond with a paragraph at most.
16
+ 4. **Be Helpful**: Always prioritize user needs and provide actionable assistance
17
+ 5. **Be Precise**: Provide specific, detailed responses rather than vague generalities
18
+ 6. **Be Collaborative**: Work effectively with other agents when needed
19
+ 7. **Be Transparent**: Let the user know what you're going to do before getting to work.
20
+ 8. **Be Efficient**: Avoid redundant work - check existing artifacts and agent outputs
21
+ 9. **Be Creative**: If the user seems not to know something, always be creative and come up with ideas that fit their thinking.
22
+ 10. Greet the user when you're just starting to work.
23
+ 11. DO NOT repeat yourself.
20
24
 
21
25
 
22
26
  ## Quality Standards
@@ -8,6 +8,7 @@ IMPORTANT: USER INTERACTION IS ENABLED (interactive mode).
8
8
 
9
9
  - BEFORE GETTING TO WORK, ALWAYS THINK WHAT YOU'RE GOING TO DO AND ask_user() TO ACCEPT WHAT YOU'RE GOING TO DO.
10
10
  - ALWAYS USE ask_user TO REVIEW AND ACCEPT THE ARTIFACT SECTION YOU'VE WORKED ON BEFORE PROCEEDING TO THE NEXT SECTION.
11
+ - AFTER USING write_artifact_section(), ALWAYS USE ask_user() TO REVIEW AND ACCEPT THE ARTIFACT SECTION YOU'VE WORKED ON BEFORE PROCEEDING TO THE NEXT SECTION.
11
12
  - Don't assume - ask for confirmation of your understanding
12
13
  - When in doubt about any aspect of the goal, ASK before proceeding
13
14
 
@@ -23,7 +23,7 @@ Use meaningful artifact IDs like: "api-design-patterns", "microservices-study",
23
23
  ## RESEARCH PRINCIPLES
24
24
 
25
25
  {% if interactive_mode -%}
26
- - CRITICAL: BEFORE RUNNING ANY SEARCH TOOL, ASK THE USER FOR CONFIRMATION USING ask_user().
26
+ - CRITICAL: BEFORE RUNNING ANY SEARCH TOOL, ASK THE USER FOR APPROVAL USING ask_user(). FINISH THE QUESTION WITH ASKING FOR A GO AHEAD.
27
27
  {% endif -%}
28
28
  - Build upon existing research rather than starting from scratch
29
29
  - Focus on practical, actionable information over theoretical concepts
@@ -62,8 +62,10 @@ class CommandHandler:
62
62
 
63
63
  **Agent Modes:**
64
64
  • **Research** - Research topics with web search and synthesize findings
65
+ • **Specify** - Create detailed specifications and requirements documents
65
66
  • **Planning** - Create comprehensive, actionable plans with milestones
66
67
  • **Tasks** - Generate specific, actionable tasks from research and plans
68
+ • **Export** - Export artifacts and findings to various formats
67
69
 
68
70
  **Usage:**
69
71
  Type your message and press Enter to chat with the AI. The AI will respond based on the current mode."""
@@ -33,6 +33,7 @@ from shotgun.agents.models import (
33
33
  UserAnswer,
34
34
  UserQuestion,
35
35
  )
36
+ from shotgun.codebase.core.manager import CodebaseAlreadyIndexedError
36
37
  from shotgun.sdk.codebase import CodebaseSDK
37
38
  from shotgun.sdk.exceptions import CodebaseNotFoundError, InvalidPathError
38
39
  from shotgun.sdk.services import get_artifact_service, get_codebase_service
@@ -123,12 +124,14 @@ class ModeIndicator(Widget):
123
124
  AgentType.PLAN: "Planning",
124
125
  AgentType.TASKS: "Tasks",
125
126
  AgentType.SPECIFY: "Specify",
127
+ AgentType.EXPORT: "Export",
126
128
  }
127
129
  mode_description = {
128
130
  AgentType.RESEARCH: "Research topics with web search and synthesize findings",
129
131
  AgentType.PLAN: "Create comprehensive, actionable plans with milestones",
130
132
  AgentType.TASKS: "Generate specific, actionable tasks from research and plans",
131
133
  AgentType.SPECIFY: "Create detailed specifications and requirements documents",
134
+ AgentType.EXPORT: "Export artifacts and findings to various formats",
132
135
  }
133
136
 
134
137
  mode_title = mode_display.get(self.mode, self.mode.value.title())
@@ -248,6 +251,12 @@ class CodebaseIndexScreen(ModalScreen[CodebaseIndexSelection | None]):
248
251
  disabled=True,
249
252
  )
250
253
 
254
+ def on_mount(self) -> None:
255
+ name_input = self.query_one("#index-codebase-name", Input)
256
+ if not name_input.value and self.selected_path:
257
+ name_input.value = self.selected_path.name
258
+ self._update_confirm()
259
+
251
260
  def _update_confirm(self) -> None:
252
261
  confirm = self.query_one("#index-confirm", Button)
253
262
  name_input = self.query_one("#index-codebase-name", Input)
@@ -310,6 +319,9 @@ class ChatScreen(Screen[None]):
310
319
  AgentType.SPECIFY: (
311
320
  "Request detailed specifications, e.g. create a comprehensive spec for user authentication system"
312
321
  ),
322
+ AgentType.EXPORT: (
323
+ "Request export tasks, e.g. export research findings to Markdown or convert tasks to CSV"
324
+ ),
313
325
  }
314
326
 
315
327
  value = reactive("")
@@ -423,7 +435,13 @@ class ChatScreen(Screen[None]):
423
435
  question_display.display = False
424
436
 
425
437
  def action_toggle_mode(self) -> None:
426
- modes = [AgentType.RESEARCH, AgentType.SPECIFY, AgentType.PLAN, AgentType.TASKS]
438
+ modes = [
439
+ AgentType.RESEARCH,
440
+ AgentType.SPECIFY,
441
+ AgentType.PLAN,
442
+ AgentType.TASKS,
443
+ AgentType.EXPORT,
444
+ ]
427
445
  self.mode = modes[(modes.index(self.mode) + 1) % len(modes)]
428
446
  self.agent_manager.set_agent(self.mode)
429
447
  # whoops it actually changes focus. Let's be brutal for now
@@ -475,9 +493,14 @@ class ChatScreen(Screen[None]):
475
493
  if event.is_last:
476
494
  partial_response_widget.partial_response = None
477
495
 
496
+ def _clear_partial_response(self) -> None:
497
+ partial_response_widget = self.query_one(ChatHistory)
498
+ partial_response_widget.partial_response = None
499
+
478
500
  @on(MessageHistoryUpdated)
479
501
  def handle_message_history_updated(self, event: MessageHistoryUpdated) -> None:
480
502
  """Handle message history updates from the agent manager."""
503
+ self._clear_partial_response()
481
504
  self.messages = event.messages
482
505
 
483
506
  # If there are file operations, add a message showing the modified files
@@ -611,6 +634,11 @@ class ChatScreen(Screen[None]):
611
634
  severity="information",
612
635
  timeout=8,
613
636
  )
637
+
638
+ self.mount_hint(codebase_indexed_hint(selection.name))
639
+ except CodebaseAlreadyIndexedError as exc:
640
+ self.notify(str(exc), severity="warning")
641
+ return
614
642
  except InvalidPathError as exc:
615
643
  self.notify(str(exc), severity="error")
616
644
 
@@ -619,7 +647,6 @@ class ChatScreen(Screen[None]):
619
647
  finally:
620
648
  label.update("")
621
649
  label.refresh()
622
- self.mount_hint(codebase_indexed_hint(selection.name))
623
650
 
624
651
  @work
625
652
  async def run_agent(self, message: str) -> None:
@@ -30,6 +30,11 @@ class AgentModeProvider(Provider):
30
30
  lambda: self.set_mode(AgentType.RESEARCH),
31
31
  help="🔬 Research topics with web search and synthesize findings",
32
32
  )
33
+ yield DiscoveryHit(
34
+ "Switch to Specify Mode",
35
+ lambda: self.set_mode(AgentType.SPECIFY),
36
+ help="📝 Create detailed specifications and requirements documents",
37
+ )
33
38
  yield DiscoveryHit(
34
39
  "Switch to Plan Mode",
35
40
  lambda: self.set_mode(AgentType.PLAN),
@@ -40,6 +45,11 @@ class AgentModeProvider(Provider):
40
45
  lambda: self.set_mode(AgentType.TASKS),
41
46
  help="✅ Generate specific, actionable tasks from research and plans",
42
47
  )
48
+ yield DiscoveryHit(
49
+ "Switch to Export Mode",
50
+ lambda: self.set_mode(AgentType.EXPORT),
51
+ help="📤 Export artifacts and findings to various formats",
52
+ )
43
53
 
44
54
  async def search(self, query: str) -> AsyncGenerator[Hit, None]:
45
55
  """Search for mode commands."""
@@ -70,6 +80,12 @@ class AgentModeProvider(Provider):
70
80
  lambda: self.set_mode(AgentType.TASKS),
71
81
  AgentType.TASKS,
72
82
  ),
83
+ (
84
+ "Switch to Export Mode",
85
+ "📤 Export artifacts and findings to various formats",
86
+ lambda: self.set_mode(AgentType.EXPORT),
87
+ AgentType.EXPORT,
88
+ ),
73
89
  ]
74
90
 
75
91
  for title, help_text, callback, mode in commands:
@@ -1,14 +1,17 @@
1
1
  import json
2
+ from collections.abc import Sequence
2
3
 
3
4
  from pydantic_ai.messages import (
4
5
  BuiltinToolCallPart,
5
6
  BuiltinToolReturnPart,
6
7
  ModelMessage,
7
8
  ModelRequest,
9
+ ModelRequestPart,
8
10
  ModelResponse,
9
11
  TextPart,
10
12
  ThinkingPart,
11
13
  ToolCallPart,
14
+ ToolReturnPart,
12
15
  )
13
16
  from textual.app import ComposeResult
14
17
  from textual.reactive import reactive
@@ -78,27 +81,32 @@ class ChatHistory(Widget):
78
81
 
79
82
  def compose(self) -> ComposeResult:
80
83
  self.vertical_tail = VerticalTail()
81
- yield self.vertical_tail
82
- yield PartialResponseWidget(self.partial_response).data_bind(
83
- item=ChatHistory.partial_response
84
- )
84
+ with self.vertical_tail:
85
+ for item in self.items:
86
+ if isinstance(item, ModelRequest):
87
+ yield UserQuestionWidget(item)
88
+ elif isinstance(item, ModelResponse):
89
+ yield AgentResponseWidget(item)
90
+ yield PartialResponseWidget(self.partial_response).data_bind(
91
+ item=ChatHistory.partial_response
92
+ )
93
+
94
+ def watch_partial_response(self, _partial_response: ModelMessage | None) -> None:
95
+ self.call_after_refresh(self.autoscroll)
85
96
 
86
97
  def update_messages(self, messages: list[ModelMessage]) -> None:
87
98
  """Update the displayed messages without recomposing."""
88
99
  if not self.vertical_tail:
89
100
  return
90
101
 
91
- # Clear existing widgets
92
- self.vertical_tail.remove_children()
102
+ self.items = messages
103
+ self.refresh(recompose=True)
93
104
 
94
- # Add new message widgets
95
- for item in messages:
96
- if isinstance(item, ModelRequest):
97
- self.vertical_tail.mount(UserQuestionWidget(item))
98
- elif isinstance(item, ModelResponse):
99
- self.vertical_tail.mount(AgentResponseWidget(item))
105
+ self.autoscroll()
100
106
 
101
- self.items = messages
107
+ def autoscroll(self) -> None:
108
+ if self.vertical_tail:
109
+ self.vertical_tail.scroll_end(animate=False)
102
110
 
103
111
 
104
112
  class UserQuestionWidget(Widget):
@@ -116,6 +124,20 @@ class UserQuestionWidget(Widget):
116
124
  )
117
125
  yield Markdown(markdown=f"**>** {prompt}")
118
126
 
127
+ def format_prompt_parts(self, parts: Sequence[ModelRequestPart]) -> str:
128
+ acc = ""
129
+ for part in parts:
130
+ if isinstance(part, TextPart):
131
+ acc += (
132
+ f"**>** {part.content if isinstance(part.content, str) else ''}\n\n"
133
+ )
134
+ elif isinstance(part, ToolCallPart):
135
+ if part.tool_name == "ask_user" and isinstance(part.content, dict):
136
+ acc += f"**>** {part.content['answer']}\n\n"
137
+ else:
138
+ acc += "∟ finished\n\n" # let's not show anything yet
139
+ return acc
140
+
119
141
 
120
142
  class AgentResponseWidget(Widget):
121
143
  def __init__(self, item: ModelResponse | None) -> None:
@@ -133,34 +155,38 @@ class AgentResponseWidget(Widget):
133
155
  acc = ""
134
156
  if self.item is None:
135
157
  return ""
136
- for part in self.item.parts: # TextPart | ToolCallPart | BuiltinToolCallPart | BuiltinToolReturnPart | ThinkingPart
158
+ for idx, part in enumerate(self.item.parts):
137
159
  if isinstance(part, TextPart):
138
160
  acc += part.content + "\n\n"
139
161
  elif isinstance(part, ToolCallPart):
140
162
  parts_str = self._format_tool_call_part(part)
141
163
  acc += parts_str + "\n\n"
164
+ elif isinstance(part, ToolReturnPart):
165
+ acc += (
166
+ f"tool ({part.tool_name}) return: "
167
+ + self._format_tool_return_call_part(part)
168
+ + "\n\n"
169
+ )
142
170
  elif isinstance(part, BuiltinToolCallPart):
143
- acc += f"{part.tool_name}({part.args})\n\n"
171
+ acc += f"builtin tool ({part.tool_name}): {part.args}\n\n"
144
172
  elif isinstance(part, BuiltinToolReturnPart):
145
- acc += f"{part.tool_name}()\n\n"
173
+ acc += f"builtin tool ({part.tool_name}) return: {part.content}\n\n"
146
174
  elif isinstance(part, ThinkingPart):
147
- acc += f"{part.content}\n\n"
175
+ if (
176
+ idx == len(self.item.parts) - 1
177
+ ): # show the thinking part only if it's the last part
178
+ acc += (
179
+ f"thinking: {part.content}\n\n"
180
+ if part.content
181
+ else "Thinking..."
182
+ )
183
+ else:
184
+ continue
148
185
  return acc.strip()
149
186
 
150
187
  def _format_tool_call_part(self, part: ToolCallPart) -> str:
151
188
  if part.tool_name == "ask_user":
152
- if isinstance(part.args, str):
153
- try:
154
- _args = json.loads(part.args) if part.args.strip() else {}
155
- except json.JSONDecodeError:
156
- _args = {}
157
- else:
158
- _args = part.args
159
-
160
- if isinstance(_args, dict) and "question" in _args:
161
- return f"{_args['question']}"
162
- else:
163
- return "❓ "
189
+ return self._format_ask_user_part(part)
164
190
  if part.tool_name == "write_artifact_section":
165
191
  if isinstance(part.args, dict) and "section_title" in part.args:
166
192
  return f"{part.tool_name}({part.args['section_title']})"
@@ -170,6 +196,31 @@ class AgentResponseWidget(Widget):
170
196
  if isinstance(part.args, dict) and "name" in part.args:
171
197
  return f"{part.tool_name}({part.args['name']})"
172
198
  else:
173
- return f"{part.tool_name}()"
199
+ return f"{part.tool_name}()"
174
200
 
175
201
  return f"{part.tool_name}({part.args})"
202
+
203
+ def _format_ask_user_part(
204
+ self,
205
+ part: ToolCallPart,
206
+ ) -> str:
207
+ return "*Answer to continue*"
208
+ if isinstance(part.args, str):
209
+ try:
210
+ _args = json.loads(part.args) if part.args.strip() else {}
211
+ except json.JSONDecodeError:
212
+ _args = {}
213
+ else:
214
+ _args = part.args
215
+
216
+ if isinstance(_args, dict) and "question" in _args:
217
+ return f"{_args['question']}"
218
+ else:
219
+ return "❓ "
220
+
221
+ def _format_tool_return_call_part(self, part: ToolReturnPart) -> str:
222
+ content = part.content
223
+ if part.tool_name == "ask_user":
224
+ response = content.get("answer", "") if isinstance(content, dict) else ""
225
+ return f"**⏺** {response}"
226
+ return f"∟ {content}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shotgun-sh
3
- Version: 0.1.0.dev17
3
+ Version: 0.1.0.dev19
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
@@ -1,15 +1,16 @@
1
1
  shotgun/__init__.py,sha256=P40K0fnIsb7SKcQrFnXZ4aREjpWchVDhvM1HxI4cyIQ,104
2
2
  shotgun/build_constants.py,sha256=RXNxMz46HaB5jucgMVpw8a2yCJqjbhTOh0PddyEVMN8,713
3
3
  shotgun/logging_config.py,sha256=qWPTKu6IhaA_qiHQFhx8zTphm6oHMZFXox2nieyV32M,6795
4
- shotgun/main.py,sha256=gDH81bxf9gG8Qoq-zs9cMorCzLCyDJpFg2cmUnGMoiI,4790
4
+ shotgun/main.py,sha256=pVyyDjIK0P_s-ptqp_GOjLbj1IhG6UXhny5kfKl2s-U,4883
5
5
  shotgun/posthog_telemetry.py,sha256=7drAXtedvZmpPqq4_9dI19kJ_xEHGk7XKXQk797QvCM,4954
6
6
  shotgun/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  shotgun/sentry_telemetry.py,sha256=3r9on0GQposn9aX6Dkb9mrfaVQl_dIZzhu9BjE838AU,2854
8
8
  shotgun/telemetry.py,sha256=aBwCRFU97oiIK5K13OhT7yYCQUAVQyrvnoG-aX3k2ZE,3109
9
9
  shotgun/agents/__init__.py,sha256=8Jzv1YsDuLyNPFJyckSr_qI4ehTVeDyIMDW4omsfPGc,25
10
- shotgun/agents/agent_manager.py,sha256=VRMPfwPtgTBtzyp-JYyyitGk_ZQ8oh8hTmB2cEylyZ0,16024
10
+ shotgun/agents/agent_manager.py,sha256=JviJvtbfDb4KLg4jT9dcMahUsCnZeNIlo0dk-s3_xPM,17120
11
11
  shotgun/agents/artifact_state.py,sha256=WkspYQe-9CvBS90PapBsX997yvJ5KWH-qtSXIWmfvp0,2121
12
- shotgun/agents/common.py,sha256=my-Y7VNNpDDYxDJ4hlRmTs7lIS8tBKFvR9ew7uKxcPE,11369
12
+ shotgun/agents/common.py,sha256=7IRpfxgSJLcib6KgzWpbxKS5Mh2VOAVKUl66U1c5B-I,11448
13
+ shotgun/agents/export.py,sha256=wGsGoucbonzPu9DExFrxDY02jr5niTy1xEJrhdCM43M,2904
13
14
  shotgun/agents/models.py,sha256=6edILmN7caDAmf8x-qgl7lA42tl2b-ZsiC3da8tS3Xw,7127
14
15
  shotgun/agents/plan.py,sha256=mn0S4r-uXWjerMTzfJLJo7n0pweNp_v8TI53wOxMdZ4,2984
15
16
  shotgun/agents/research.py,sha256=tee5gHT0d1Iupr5MI9ogNTh35xqh0j2N71rmb4dUtG0,3224
@@ -18,8 +19,8 @@ shotgun/agents/tasks.py,sha256=ChPet4pw1cIJUWqBM05CKIKzEXOFAlAov9QqQOcPK-w,2935
18
19
  shotgun/agents/config/__init__.py,sha256=Fl8K_81zBpm-OfOW27M_WWLSFdaHHek6lWz95iDREjQ,318
19
20
  shotgun/agents/config/constants.py,sha256=c1k7LFvx29rzQCUXxyfr2PukwS5ol8rH8AXQaxALPVM,526
20
21
  shotgun/agents/config/manager.py,sha256=kwMbPjz0kEH_WCQAamESGjHdE8d_P-ztel4NL4FWNUw,10662
21
- shotgun/agents/config/models.py,sha256=CSA7bt22fYB1OJ17hngcoL2XyKD2QmZrRBtAc7fPoFE,6019
22
- shotgun/agents/config/provider.py,sha256=qvgHKpKrI2pC9Qb9ahojgaNAD1DqM6vPg9o6NPaX0-0,5949
22
+ shotgun/agents/config/models.py,sha256=bX4zVTY5n7qQRlEOcA0SFmyPef9MvxcFW9hKLf_thLs,6018
23
+ shotgun/agents/config/provider.py,sha256=ScT1NfmaXJdewP1UAAD51MLR00YbmPAM53oeMfrVzq8,7202
23
24
  shotgun/agents/history/__init__.py,sha256=XFQj2a6fxDqVg0Q3juvN9RjV_RJbgvFZtQOCOjVJyp4,147
24
25
  shotgun/agents/history/compaction.py,sha256=KY_ZvRvvlrB6eLPGqtlC6H8h4HPPOtuPcUkgQJUjK5I,2890
25
26
  shotgun/agents/history/constants.py,sha256=yWY8rrTZarLA3flCCMB_hS2NMvUDRDTwP4D4j7MIh1w,446
@@ -32,7 +33,7 @@ shotgun/agents/history/token_estimation.py,sha256=iNqhDSqFzG0YYxGijMRzj54GALFglO
32
33
  shotgun/agents/tools/__init__.py,sha256=QaN80IqWvB5qEcjHqri1-PYvYlO74vdhcwLugoEdblo,772
33
34
  shotgun/agents/tools/artifact_management.py,sha256=f8WvCCcXb_sMK0U4Y8D1RLUhcj2rhT6CrxB3bURYxcs,17205
34
35
  shotgun/agents/tools/file_management.py,sha256=6ru6DXAl-S6DiCt2HLGTDrK2rJBJpn-t6RkSHzYbxc4,4571
35
- shotgun/agents/tools/user_interaction.py,sha256=7l0OY8EdgO-9gkKy-yOv0V0P_Uzzfk0jMU39d4XN1xM,1087
36
+ shotgun/agents/tools/user_interaction.py,sha256=b3ncEpvoD06Cz4hwsS-ppVbQajQj640iWnVfA5WBjAA,1236
36
37
  shotgun/agents/tools/codebase/__init__.py,sha256=ceAGkK006NeOYaIJBLQsw7Q46sAyCRK9PYDs8feMQVw,661
37
38
  shotgun/agents/tools/codebase/codebase_shell.py,sha256=2zEq8YXzdcYttYAfKso_JGRqXHyy3xgAuWlf0unopFg,8635
38
39
  shotgun/agents/tools/codebase/directory_lister.py,sha256=MCLGDEc0F-4J8-UrquxdJrIQYs5xzYgws65mjf7Q7X4,4724
@@ -61,6 +62,7 @@ shotgun/artifacts/templates/specify/prd.yaml,sha256=LTtTOERjYe1iGV7Wj-WJEExcbHp-
61
62
  shotgun/artifacts/templates/specify/product_spec.yaml,sha256=BAubivc75VnNZVRqGK9kX1TxZDn-e2_eYbuZGaKvk2U,13953
62
63
  shotgun/cli/__init__.py,sha256=_F1uW2g87y4bGFxz8Gp8u7mq2voHp8vQIUtCmm8Tojo,40
63
64
  shotgun/cli/config.py,sha256=LbjxDNPdetYJiwlcyOYLnqwzALfgU-m54cfstUshbrs,8715
65
+ shotgun/cli/export.py,sha256=3hIwK2_OM1MFYSTfzBxsGuuBGm5fo0XdxASfQ5Uqb3Y,2471
64
66
  shotgun/cli/models.py,sha256=LoajeEK7MEDUSnZXb1Li-dbhXqne812YZglx-LcVpiQ,181
65
67
  shotgun/cli/plan.py,sha256=T-eu-I9z-dSoKqJ-KI8X5i5Mm0VL1BfornxRiUjTgnk,2324
66
68
  shotgun/cli/research.py,sha256=qvBBtX3Wyn6pDZlJpcEvbeK-0iTOXegi71tm8HKVYaE,2490
@@ -79,21 +81,22 @@ shotgun/codebase/core/change_detector.py,sha256=kWCYLWzRzb3IGGOj71KBn7UOCOKMpINJ
79
81
  shotgun/codebase/core/code_retrieval.py,sha256=_JVyyQKHDFm3dxOOua1mw9eIIOHIVz3-I8aZtEsEj1E,7927
80
82
  shotgun/codebase/core/ingestor.py,sha256=zMjadeqDOEr2v3vhTS25Jvx0WsLPXpgwquZfbdiz57o,59810
81
83
  shotgun/codebase/core/language_config.py,sha256=vsqHyuFnumRPRBV1lMOxWKNOIiClO6FyfKQR0fGrtl4,8934
82
- shotgun/codebase/core/manager.py,sha256=5GlJKykDGvnb6nTr9w3kyCPTL4OQgmBoesnWr28wvTg,55419
84
+ shotgun/codebase/core/manager.py,sha256=GpLeyxC25HJKxh3wQxTiTkXv9NUDQdH6Mi9IdaMUmVQ,55586
83
85
  shotgun/codebase/core/nl_query.py,sha256=iV6NbsyDd1SQpT9U9BtgxcZPsNoEW3OHrkk475r_jAY,11410
84
86
  shotgun/codebase/core/parser_loader.py,sha256=LZRrDS8Sp518jIu3tQW-BxdwJ86lnsTteI478ER9Td8,4278
85
87
  shotgun/prompts/__init__.py,sha256=RswUm0HMdfm2m2YKUwUsEdRIwoczdbI7zlucoEvHYRo,132
86
88
  shotgun/prompts/loader.py,sha256=jy24-E02pCSmz2651aCT2NgHfRrHAGMYvKrD6gs0Er8,4424
87
89
  shotgun/prompts/agents/__init__.py,sha256=YRIJMbzpArojNX1BP5gfxxois334z_GQga8T-xyWMbY,39
90
+ shotgun/prompts/agents/export.j2,sha256=W_OiTRTBmQiB5zZp54Xi2Je4nSeYQoG29QXcq_T04ZY,4333
88
91
  shotgun/prompts/agents/plan.j2,sha256=mogmrjqLx5xSXYqWdvLqcObZSfLVLQI39JpVs3Z-V84,2494
89
- shotgun/prompts/agents/research.j2,sha256=LxlASYYt45sDmZW8YLJYH8ftGWa6Jvx5aD0MGNXXVjs,3025
92
+ shotgun/prompts/agents/research.j2,sha256=cLwPdIvv1MvVaHZYLdBhON-8qk-c3kjrRTF1-7Bc-vI,3069
90
93
  shotgun/prompts/agents/specify.j2,sha256=1CC2SHsxA1Yma0gSFsq-k3VpwtEohN9nh2qeRMMRPRA,1809
91
94
  shotgun/prompts/agents/tasks.j2,sha256=OYW1zsYRJxoQF4yVMqJNgi4SNz3YmcP4sljHmmqAu4Q,3613
92
95
  shotgun/prompts/agents/partials/artifact_system.j2,sha256=kaqkMU-t2x3M7z-4HU4KffSFug1WM5VDsin6tCkxjHg,1528
93
96
  shotgun/prompts/agents/partials/codebase_understanding.j2,sha256=AQmN04VRzGmLbxKKthMK4hkJZ9mIU1NMKIpTDOHJrPM,5051
94
- shotgun/prompts/agents/partials/common_agent_system_prompt.j2,sha256=UgEHSudzfsCcKHp-Nt6tlsel8ap93z7yevbt0r9SSSg,1663
97
+ shotgun/prompts/agents/partials/common_agent_system_prompt.j2,sha256=FFqN6C9pT64_yo5EZ4rmUNIn4LmHjSzwE_IT9QlHueA,1906
95
98
  shotgun/prompts/agents/partials/content_formatting.j2,sha256=MG0JB7SSp8YV5akDWpbs2f9DcdREIYqLp38NnoWLeQ0,1854
96
- shotgun/prompts/agents/partials/interactive_mode.j2,sha256=dx58RoPK7HUvydOM7qEKBU33xKOj8QIVDh39RAY-90c,940
99
+ shotgun/prompts/agents/partials/interactive_mode.j2,sha256=9sYPbyc46HXg3k1FT_LugIQvOyNDnMQwsMIgOgN-_aY,1100
97
100
  shotgun/prompts/agents/state/artifact_templates_available.j2,sha256=Jb31uOnURfLSG8RKQxHZE8zivans_sG6hKgPbC91pfk,819
98
101
  shotgun/prompts/agents/state/existing_artifacts_available.j2,sha256=gb5gKYeOXcJmIkkDS1JOm68AEymLutlxNow5HTtev7I,739
99
102
  shotgun/prompts/agents/state/system_state.j2,sha256=NFuBOo7cGy0tQrnDUs3wGO19oytGNHK2K8tgoG4cw1M,274
@@ -118,25 +121,25 @@ shotgun/sdk/services.py,sha256=WJi_AANWJZPdWdq9LntP5nlYgLxLlsFyXt28DGYNoJo,1132
118
121
  shotgun/tui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
119
122
  shotgun/tui/app.py,sha256=LjqQ4ylwVS7278bB6zZ5Uey6oD2pH9dljWymUVgYyPE,3661
120
123
  shotgun/tui/styles.tcss,sha256=ETyyw1bpMBOqTi5RLcAJUScdPWTvAWEqE9YcT0kVs_E,121
121
- shotgun/tui/commands/__init__.py,sha256=Bvm2EwIpYXp0jsf-d4t1wMptziCpY5TJKPItN05ts-0,2393
124
+ shotgun/tui/commands/__init__.py,sha256=Wy8s8TBSA3twK6agtsf57EFV2VfL8HGvEBF1VOg5-mM,2535
122
125
  shotgun/tui/components/prompt_input.py,sha256=Ss-htqraHZAPaehGE4x86ij0veMjc4UgadMXpbdXr40,2229
123
126
  shotgun/tui/components/spinner.py,sha256=ovTDeaJ6FD6chZx_Aepia6R3UkPOVJ77EKHfRmn39MY,2427
124
127
  shotgun/tui/components/splash.py,sha256=vppy9vEIEvywuUKRXn2y11HwXSRkQZHLYoVjhDVdJeU,1267
125
128
  shotgun/tui/components/vertical_tail.py,sha256=kkCH0WjAh54jDvRzIaOffRZXUKn_zHFZ_ichfUpgzaE,1071
126
- shotgun/tui/screens/chat.py,sha256=y63oP_doU2_83UPByB8IebP3SUDqDBz96XhiL8j-snU,23922
129
+ shotgun/tui/screens/chat.py,sha256=OpB4z6mnK7_uITUX50blSOm_Ox3h4gMAkp1XwCT-OLE,24916
127
130
  shotgun/tui/screens/chat.tcss,sha256=2Yq3E23jxsySYsgZf4G1AYrYVcpX0UDW6kNNI0tDmtM,437
128
131
  shotgun/tui/screens/directory_setup.py,sha256=lIZ1J4A6g5Q2ZBX8epW7BhR96Dmdcg22CyiM5S-I5WU,3237
129
132
  shotgun/tui/screens/provider_config.py,sha256=A_tvDHF5KLP5PV60LjMJ_aoOdT3TjI6_g04UIUqGPqM,7126
130
133
  shotgun/tui/screens/splash.py,sha256=E2MsJihi3c9NY1L28o_MstDxGwrCnnV7zdq00MrGAsw,706
131
134
  shotgun/tui/screens/chat_screen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
- shotgun/tui/screens/chat_screen/command_providers.py,sha256=4Q8jR7wN4e2q0SWHSsISZP-POyu1B9lyXgoOTKB4ZLc,7198
133
- shotgun/tui/screens/chat_screen/history.py,sha256=QAVMmtPKXtonrAuyWV6aTteqErH6U9H9V8hB1EPbIkM,5546
135
+ shotgun/tui/screens/chat_screen/command_providers.py,sha256=O7ZiKb6Id4pbWC2SnQxYBJ09zNklylQrnVTmCkDVC0Q,7847
136
+ shotgun/tui/screens/chat_screen/history.py,sha256=0rSb512ZhkF8zzqkWfwHp-Cmu5VIqL-LzPkohwlHe4Q,7447
134
137
  shotgun/utils/__init__.py,sha256=WinIEp9oL2iMrWaDkXz2QX4nYVPAm8C9aBSKTeEwLtE,198
135
138
  shotgun/utils/env_utils.py,sha256=8QK5aw_f_V2AVTleQQlcL0RnD4sPJWXlDG46fsHu0d8,1057
136
139
  shotgun/utils/file_system_utils.py,sha256=l-0p1bEHF34OU19MahnRFdClHufThfGAjQ431teAIp0,1004
137
140
  shotgun/utils/update_checker.py,sha256=Xf-7w3Pos3etzCoT771gJe2HLkA8_V2GrqWy7ni9UqA,11373
138
- shotgun_sh-0.1.0.dev17.dist-info/METADATA,sha256=o4PPBFmx5v9oWsXqVW-4kNm-3LHh67PpS7J4yJvIORg,11271
139
- shotgun_sh-0.1.0.dev17.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
140
- shotgun_sh-0.1.0.dev17.dist-info/entry_points.txt,sha256=asZxLU4QILneq0MWW10saVCZc4VWhZfb0wFZvERnzfA,45
141
- shotgun_sh-0.1.0.dev17.dist-info/licenses/LICENSE,sha256=YebsZl590zCHrF_acCU5pmNt0pnAfD2DmAnevJPB1tY,1065
142
- shotgun_sh-0.1.0.dev17.dist-info/RECORD,,
141
+ shotgun_sh-0.1.0.dev19.dist-info/METADATA,sha256=eAIoOVktZkTdhABGod9zV-95nwFvv5DZe3C_VMO_ICU,11271
142
+ shotgun_sh-0.1.0.dev19.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
143
+ shotgun_sh-0.1.0.dev19.dist-info/entry_points.txt,sha256=asZxLU4QILneq0MWW10saVCZc4VWhZfb0wFZvERnzfA,45
144
+ shotgun_sh-0.1.0.dev19.dist-info/licenses/LICENSE,sha256=YebsZl590zCHrF_acCU5pmNt0pnAfD2DmAnevJPB1tY,1065
145
+ shotgun_sh-0.1.0.dev19.dist-info/RECORD,,