shotgun-sh 0.2.6.dev1__py3-none-any.whl → 0.2.17__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.
- shotgun/agents/agent_manager.py +694 -73
- shotgun/agents/common.py +69 -70
- shotgun/agents/config/constants.py +0 -6
- shotgun/agents/config/manager.py +70 -35
- shotgun/agents/config/models.py +41 -1
- shotgun/agents/config/provider.py +33 -5
- shotgun/agents/context_analyzer/__init__.py +28 -0
- shotgun/agents/context_analyzer/analyzer.py +471 -0
- shotgun/agents/context_analyzer/constants.py +9 -0
- shotgun/agents/context_analyzer/formatter.py +115 -0
- shotgun/agents/context_analyzer/models.py +212 -0
- shotgun/agents/conversation_history.py +125 -2
- shotgun/agents/conversation_manager.py +57 -19
- shotgun/agents/export.py +6 -7
- shotgun/agents/history/compaction.py +9 -4
- shotgun/agents/history/context_extraction.py +93 -6
- shotgun/agents/history/history_processors.py +113 -5
- shotgun/agents/history/token_counting/anthropic.py +39 -3
- shotgun/agents/history/token_counting/base.py +14 -3
- shotgun/agents/history/token_counting/openai.py +11 -1
- shotgun/agents/history/token_counting/sentencepiece_counter.py +8 -0
- shotgun/agents/history/token_counting/tokenizer_cache.py +3 -1
- shotgun/agents/history/token_counting/utils.py +0 -3
- shotgun/agents/models.py +50 -2
- shotgun/agents/plan.py +6 -7
- shotgun/agents/research.py +7 -8
- shotgun/agents/specify.py +6 -7
- shotgun/agents/tasks.py +6 -7
- shotgun/agents/tools/__init__.py +0 -2
- shotgun/agents/tools/codebase/codebase_shell.py +6 -0
- shotgun/agents/tools/codebase/directory_lister.py +6 -0
- shotgun/agents/tools/codebase/file_read.py +11 -2
- shotgun/agents/tools/codebase/query_graph.py +6 -0
- shotgun/agents/tools/codebase/retrieve_code.py +6 -0
- shotgun/agents/tools/file_management.py +82 -16
- shotgun/agents/tools/registry.py +217 -0
- shotgun/agents/tools/web_search/__init__.py +8 -8
- shotgun/agents/tools/web_search/anthropic.py +8 -2
- shotgun/agents/tools/web_search/gemini.py +7 -1
- shotgun/agents/tools/web_search/openai.py +7 -1
- shotgun/agents/tools/web_search/utils.py +2 -2
- shotgun/agents/usage_manager.py +16 -11
- shotgun/api_endpoints.py +7 -3
- shotgun/build_constants.py +3 -3
- shotgun/cli/clear.py +53 -0
- shotgun/cli/compact.py +186 -0
- shotgun/cli/config.py +8 -5
- shotgun/cli/context.py +111 -0
- shotgun/cli/export.py +1 -1
- shotgun/cli/feedback.py +4 -2
- shotgun/cli/models.py +1 -0
- shotgun/cli/plan.py +1 -1
- shotgun/cli/research.py +1 -1
- shotgun/cli/specify.py +1 -1
- shotgun/cli/tasks.py +1 -1
- shotgun/cli/update.py +16 -2
- shotgun/codebase/core/change_detector.py +5 -3
- shotgun/codebase/core/code_retrieval.py +4 -2
- shotgun/codebase/core/ingestor.py +10 -8
- shotgun/codebase/core/manager.py +13 -4
- shotgun/codebase/core/nl_query.py +1 -1
- shotgun/exceptions.py +32 -0
- shotgun/logging_config.py +18 -27
- shotgun/main.py +73 -11
- shotgun/posthog_telemetry.py +37 -28
- shotgun/prompts/agents/export.j2 +18 -1
- shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +5 -1
- shotgun/prompts/agents/partials/interactive_mode.j2 +24 -7
- shotgun/prompts/agents/plan.j2 +1 -1
- shotgun/prompts/agents/research.j2 +1 -1
- shotgun/prompts/agents/specify.j2 +270 -3
- shotgun/prompts/agents/tasks.j2 +1 -1
- shotgun/sentry_telemetry.py +163 -16
- shotgun/settings.py +238 -0
- shotgun/telemetry.py +18 -33
- shotgun/tui/app.py +243 -43
- shotgun/tui/commands/__init__.py +1 -1
- shotgun/tui/components/context_indicator.py +179 -0
- shotgun/tui/components/mode_indicator.py +70 -0
- shotgun/tui/components/status_bar.py +48 -0
- shotgun/tui/containers.py +91 -0
- shotgun/tui/dependencies.py +39 -0
- shotgun/tui/protocols.py +45 -0
- shotgun/tui/screens/chat/__init__.py +5 -0
- shotgun/tui/screens/chat/chat.tcss +54 -0
- shotgun/tui/screens/chat/chat_screen.py +1254 -0
- shotgun/tui/screens/chat/codebase_index_prompt_screen.py +64 -0
- shotgun/tui/screens/chat/codebase_index_selection.py +12 -0
- shotgun/tui/screens/chat/help_text.py +40 -0
- shotgun/tui/screens/chat/prompt_history.py +48 -0
- shotgun/tui/screens/chat.tcss +11 -0
- shotgun/tui/screens/chat_screen/command_providers.py +78 -2
- shotgun/tui/screens/chat_screen/history/__init__.py +22 -0
- shotgun/tui/screens/chat_screen/history/agent_response.py +66 -0
- shotgun/tui/screens/chat_screen/history/chat_history.py +115 -0
- shotgun/tui/screens/chat_screen/history/formatters.py +115 -0
- shotgun/tui/screens/chat_screen/history/partial_response.py +43 -0
- shotgun/tui/screens/chat_screen/history/user_question.py +42 -0
- shotgun/tui/screens/confirmation_dialog.py +151 -0
- shotgun/tui/screens/feedback.py +4 -4
- shotgun/tui/screens/github_issue.py +102 -0
- shotgun/tui/screens/model_picker.py +49 -24
- shotgun/tui/screens/onboarding.py +431 -0
- shotgun/tui/screens/pipx_migration.py +153 -0
- shotgun/tui/screens/provider_config.py +50 -27
- shotgun/tui/screens/shotgun_auth.py +2 -2
- shotgun/tui/screens/welcome.py +23 -12
- shotgun/tui/services/__init__.py +5 -0
- shotgun/tui/services/conversation_service.py +184 -0
- shotgun/tui/state/__init__.py +7 -0
- shotgun/tui/state/processing_state.py +185 -0
- shotgun/tui/utils/mode_progress.py +14 -7
- shotgun/tui/widgets/__init__.py +5 -0
- shotgun/tui/widgets/widget_coordinator.py +263 -0
- shotgun/utils/file_system_utils.py +22 -2
- shotgun/utils/marketing.py +110 -0
- shotgun/utils/update_checker.py +69 -14
- shotgun_sh-0.2.17.dist-info/METADATA +465 -0
- shotgun_sh-0.2.17.dist-info/RECORD +194 -0
- {shotgun_sh-0.2.6.dev1.dist-info → shotgun_sh-0.2.17.dist-info}/entry_points.txt +1 -0
- {shotgun_sh-0.2.6.dev1.dist-info → shotgun_sh-0.2.17.dist-info}/licenses/LICENSE +1 -1
- shotgun/agents/tools/user_interaction.py +0 -37
- shotgun/tui/screens/chat.py +0 -804
- shotgun/tui/screens/chat_screen/history.py +0 -401
- shotgun_sh-0.2.6.dev1.dist-info/METADATA +0 -467
- shotgun_sh-0.2.6.dev1.dist-info/RECORD +0 -156
- {shotgun_sh-0.2.6.dev1.dist-info → shotgun_sh-0.2.17.dist-info}/WHEEL +0 -0
shotgun/logging_config.py
CHANGED
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
import logging.handlers
|
|
5
|
-
import os
|
|
6
5
|
import sys
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
+
from shotgun.settings import settings
|
|
9
10
|
from shotgun.utils.env_utils import is_truthy
|
|
10
11
|
|
|
12
|
+
# Generate a single timestamp for this run to be used across all loggers
|
|
13
|
+
_RUN_TIMESTAMP = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
|
|
14
|
+
|
|
11
15
|
|
|
12
16
|
def get_log_directory() -> Path:
|
|
13
17
|
"""Get the log directory path, creating it if necessary.
|
|
@@ -66,21 +70,16 @@ def setup_logger(
|
|
|
66
70
|
logger = logging.getLogger(name)
|
|
67
71
|
|
|
68
72
|
# Check if we already have a file handler
|
|
69
|
-
has_file_handler = any(
|
|
70
|
-
isinstance(h, logging.handlers.TimedRotatingFileHandler)
|
|
71
|
-
for h in logger.handlers
|
|
72
|
-
)
|
|
73
|
+
has_file_handler = any(isinstance(h, logging.FileHandler) for h in logger.handlers)
|
|
73
74
|
|
|
74
75
|
# If we already have a file handler, just return the logger
|
|
75
76
|
if has_file_handler:
|
|
76
77
|
return logger
|
|
77
78
|
|
|
78
|
-
# Get log level from
|
|
79
|
-
|
|
80
|
-
if env_level not in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
|
|
81
|
-
env_level = "INFO"
|
|
79
|
+
# Get log level from settings (already validated and uppercased)
|
|
80
|
+
log_level = settings.logging.log_level
|
|
82
81
|
|
|
83
|
-
logger.setLevel(getattr(logging,
|
|
82
|
+
logger.setLevel(getattr(logging, log_level))
|
|
84
83
|
|
|
85
84
|
# Default format string
|
|
86
85
|
if format_string is None:
|
|
@@ -102,13 +101,13 @@ def setup_logger(
|
|
|
102
101
|
# Check if console logging is enabled (default: off)
|
|
103
102
|
# Force console logging OFF if Logfire is enabled in dev build
|
|
104
103
|
console_logging_enabled = (
|
|
105
|
-
|
|
104
|
+
settings.logging.logging_to_console and not is_logfire_dev_build
|
|
106
105
|
)
|
|
107
106
|
|
|
108
107
|
if console_logging_enabled:
|
|
109
108
|
# Create console handler
|
|
110
109
|
console_handler = logging.StreamHandler(sys.stdout)
|
|
111
|
-
console_handler.setLevel(getattr(logging,
|
|
110
|
+
console_handler.setLevel(getattr(logging, log_level))
|
|
112
111
|
|
|
113
112
|
# Use colored formatter for console
|
|
114
113
|
console_formatter = ColoredFormatter(format_string, datefmt="%H:%M:%S")
|
|
@@ -118,26 +117,21 @@ def setup_logger(
|
|
|
118
117
|
logger.addHandler(console_handler)
|
|
119
118
|
|
|
120
119
|
# Check if file logging is enabled (default: on)
|
|
121
|
-
file_logging_enabled =
|
|
120
|
+
file_logging_enabled = settings.logging.logging_to_file
|
|
122
121
|
|
|
123
122
|
if file_logging_enabled:
|
|
124
123
|
try:
|
|
125
|
-
# Create file handler with
|
|
124
|
+
# Create file handler with ISO8601 timestamp for each run
|
|
126
125
|
log_dir = get_log_directory()
|
|
127
|
-
log_file = log_dir / "shotgun.log"
|
|
126
|
+
log_file = log_dir / f"shotgun-{_RUN_TIMESTAMP}.log"
|
|
128
127
|
|
|
129
|
-
# Use
|
|
130
|
-
file_handler = logging.
|
|
128
|
+
# Use regular FileHandler - each run gets its own isolated log file
|
|
129
|
+
file_handler = logging.FileHandler(
|
|
131
130
|
filename=log_file,
|
|
132
|
-
when="midnight", # Rotate at midnight
|
|
133
|
-
interval=1, # Every 1 day
|
|
134
|
-
backupCount=7, # Keep 7 days of logs
|
|
135
131
|
encoding="utf-8",
|
|
136
132
|
)
|
|
137
133
|
|
|
138
|
-
|
|
139
|
-
# Note: We'll use TimedRotatingFileHandler which handles both time and size
|
|
140
|
-
file_handler.setLevel(getattr(logging, env_level))
|
|
134
|
+
file_handler.setLevel(getattr(logging, log_level))
|
|
141
135
|
|
|
142
136
|
# Use standard formatter for file (no colors)
|
|
143
137
|
file_formatter = logging.Formatter(
|
|
@@ -191,10 +185,7 @@ def get_logger(name: str) -> logging.Logger:
|
|
|
191
185
|
logger = logging.getLogger(name)
|
|
192
186
|
|
|
193
187
|
# Check if we have a file handler already
|
|
194
|
-
has_file_handler = any(
|
|
195
|
-
isinstance(h, logging.handlers.TimedRotatingFileHandler)
|
|
196
|
-
for h in logger.handlers
|
|
197
|
-
)
|
|
188
|
+
has_file_handler = any(isinstance(h, logging.FileHandler) for h in logger.handlers)
|
|
198
189
|
|
|
199
190
|
# If no file handler, set up the logger (will add file handler)
|
|
200
191
|
if not has_file_handler:
|
shotgun/main.py
CHANGED
|
@@ -23,8 +23,11 @@ from dotenv import load_dotenv
|
|
|
23
23
|
from shotgun import __version__
|
|
24
24
|
from shotgun.agents.config import get_config_manager
|
|
25
25
|
from shotgun.cli import (
|
|
26
|
+
clear,
|
|
26
27
|
codebase,
|
|
28
|
+
compact,
|
|
27
29
|
config,
|
|
30
|
+
context,
|
|
28
31
|
export,
|
|
29
32
|
feedback,
|
|
30
33
|
plan,
|
|
@@ -53,8 +56,10 @@ logger.debug("Logfire observability enabled: %s", _logfire_enabled)
|
|
|
53
56
|
|
|
54
57
|
# Initialize configuration
|
|
55
58
|
try:
|
|
59
|
+
import asyncio
|
|
60
|
+
|
|
56
61
|
config_manager = get_config_manager()
|
|
57
|
-
config_manager.load() # Ensure config is loaded at startup
|
|
62
|
+
asyncio.run(config_manager.load()) # Ensure config is loaded at startup
|
|
58
63
|
except Exception as e:
|
|
59
64
|
logger.debug("Configuration initialization warning: %s", e)
|
|
60
65
|
|
|
@@ -78,6 +83,9 @@ app.add_typer(config.app, name="config", help="Manage Shotgun configuration")
|
|
|
78
83
|
app.add_typer(
|
|
79
84
|
codebase.app, name="codebase", help="Manage and query code knowledge graphs"
|
|
80
85
|
)
|
|
86
|
+
app.add_typer(context.app, name="context", help="Analyze conversation context usage")
|
|
87
|
+
app.add_typer(compact.app, name="compact", help="Compact conversation history")
|
|
88
|
+
app.add_typer(clear.app, name="clear", help="Clear conversation history")
|
|
81
89
|
app.add_typer(research.app, name="research", help="Perform research with agentic loops")
|
|
82
90
|
app.add_typer(plan.app, name="plan", help="Generate structured plans")
|
|
83
91
|
app.add_typer(specify.app, name="specify", help="Generate comprehensive specifications")
|
|
@@ -125,6 +133,41 @@ def main(
|
|
|
125
133
|
help="Continue previous TUI conversation",
|
|
126
134
|
),
|
|
127
135
|
] = False,
|
|
136
|
+
web: Annotated[
|
|
137
|
+
bool,
|
|
138
|
+
typer.Option(
|
|
139
|
+
"--web",
|
|
140
|
+
help="Serve TUI as web application",
|
|
141
|
+
),
|
|
142
|
+
] = False,
|
|
143
|
+
port: Annotated[
|
|
144
|
+
int,
|
|
145
|
+
typer.Option(
|
|
146
|
+
"--port",
|
|
147
|
+
help="Port for web server (only used with --web)",
|
|
148
|
+
),
|
|
149
|
+
] = 8000,
|
|
150
|
+
host: Annotated[
|
|
151
|
+
str,
|
|
152
|
+
typer.Option(
|
|
153
|
+
"--host",
|
|
154
|
+
help="Host address for web server (only used with --web)",
|
|
155
|
+
),
|
|
156
|
+
] = "localhost",
|
|
157
|
+
public_url: Annotated[
|
|
158
|
+
str | None,
|
|
159
|
+
typer.Option(
|
|
160
|
+
"--public-url",
|
|
161
|
+
help="Public URL if behind proxy (only used with --web)",
|
|
162
|
+
),
|
|
163
|
+
] = None,
|
|
164
|
+
force_reindex: Annotated[
|
|
165
|
+
bool,
|
|
166
|
+
typer.Option(
|
|
167
|
+
"--force-reindex",
|
|
168
|
+
help="Force re-indexing of codebase (ignores existing index)",
|
|
169
|
+
),
|
|
170
|
+
] = False,
|
|
128
171
|
) -> None:
|
|
129
172
|
"""Shotgun - AI-powered CLI tool."""
|
|
130
173
|
logger.debug("Starting shotgun CLI application")
|
|
@@ -134,16 +177,35 @@ def main(
|
|
|
134
177
|
perform_auto_update_async(no_update_check=no_update_check)
|
|
135
178
|
|
|
136
179
|
if ctx.invoked_subcommand is None and not ctx.resilient_parsing:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
180
|
+
if web:
|
|
181
|
+
logger.debug("Launching shotgun TUI as web application")
|
|
182
|
+
try:
|
|
183
|
+
tui_app.serve(
|
|
184
|
+
host=host,
|
|
185
|
+
port=port,
|
|
186
|
+
public_url=public_url,
|
|
187
|
+
no_update_check=no_update_check,
|
|
188
|
+
continue_session=continue_session,
|
|
189
|
+
force_reindex=force_reindex,
|
|
190
|
+
)
|
|
191
|
+
finally:
|
|
192
|
+
# Ensure PostHog is shut down cleanly even if server exits unexpectedly
|
|
193
|
+
from shotgun.posthog_telemetry import shutdown
|
|
194
|
+
|
|
195
|
+
shutdown()
|
|
196
|
+
else:
|
|
197
|
+
logger.debug("Launching shotgun TUI application")
|
|
198
|
+
try:
|
|
199
|
+
tui_app.run(
|
|
200
|
+
no_update_check=no_update_check,
|
|
201
|
+
continue_session=continue_session,
|
|
202
|
+
force_reindex=force_reindex,
|
|
203
|
+
)
|
|
204
|
+
finally:
|
|
205
|
+
# Ensure PostHog is shut down cleanly even if TUI exits unexpectedly
|
|
206
|
+
from shotgun.posthog_telemetry import shutdown
|
|
207
|
+
|
|
208
|
+
shutdown()
|
|
147
209
|
raise typer.Exit()
|
|
148
210
|
|
|
149
211
|
# For CLI commands, register PostHog shutdown handler
|
shotgun/posthog_telemetry.py
CHANGED
|
@@ -10,6 +10,7 @@ from shotgun import __version__
|
|
|
10
10
|
from shotgun.agents.config import get_config_manager
|
|
11
11
|
from shotgun.agents.conversation_manager import ConversationManager
|
|
12
12
|
from shotgun.logging_config import get_early_logger
|
|
13
|
+
from shotgun.settings import settings
|
|
13
14
|
|
|
14
15
|
# Use early logger to prevent automatic StreamHandler creation
|
|
15
16
|
logger = get_early_logger(__name__)
|
|
@@ -17,6 +18,9 @@ logger = get_early_logger(__name__)
|
|
|
17
18
|
# Global PostHog client instance
|
|
18
19
|
_posthog_client = None
|
|
19
20
|
|
|
21
|
+
# Cache the shotgun instance ID to avoid async calls during event tracking
|
|
22
|
+
_shotgun_instance_id: str | None = None
|
|
23
|
+
|
|
20
24
|
|
|
21
25
|
def setup_posthog_observability() -> bool:
|
|
22
26
|
"""Set up PostHog analytics for usage tracking.
|
|
@@ -24,7 +28,7 @@ def setup_posthog_observability() -> bool:
|
|
|
24
28
|
Returns:
|
|
25
29
|
True if PostHog was successfully set up, False otherwise
|
|
26
30
|
"""
|
|
27
|
-
global _posthog_client
|
|
31
|
+
global _posthog_client, _shotgun_instance_id
|
|
28
32
|
|
|
29
33
|
try:
|
|
30
34
|
# Check if PostHog is already initialized
|
|
@@ -32,10 +36,15 @@ def setup_posthog_observability() -> bool:
|
|
|
32
36
|
logger.debug("PostHog is already initialized, skipping")
|
|
33
37
|
return True
|
|
34
38
|
|
|
35
|
-
#
|
|
36
|
-
api_key =
|
|
39
|
+
# Get API key from settings (handles build constants + env vars automatically)
|
|
40
|
+
api_key = settings.telemetry.posthog_api_key
|
|
41
|
+
|
|
42
|
+
# If no API key is available, skip PostHog initialization
|
|
43
|
+
if not api_key:
|
|
44
|
+
logger.debug("No PostHog API key available, skipping initialization")
|
|
45
|
+
return False
|
|
37
46
|
|
|
38
|
-
logger.debug("Using
|
|
47
|
+
logger.debug("Using PostHog API key from settings")
|
|
39
48
|
|
|
40
49
|
# Determine environment based on version
|
|
41
50
|
# Dev versions contain "dev", "rc", "alpha", or "beta"
|
|
@@ -51,29 +60,20 @@ def setup_posthog_observability() -> bool:
|
|
|
51
60
|
# Store the client for later use
|
|
52
61
|
_posthog_client = posthog
|
|
53
62
|
|
|
54
|
-
#
|
|
63
|
+
# Cache the shotgun instance ID for later use (avoids async issues)
|
|
55
64
|
try:
|
|
56
|
-
|
|
57
|
-
shotgun_instance_id = config_manager.get_shotgun_instance_id()
|
|
58
|
-
|
|
59
|
-
# Identify the user in PostHog
|
|
60
|
-
posthog.identify( # type: ignore[attr-defined]
|
|
61
|
-
distinct_id=shotgun_instance_id,
|
|
62
|
-
properties={
|
|
63
|
-
"version": __version__,
|
|
64
|
-
"environment": environment,
|
|
65
|
-
},
|
|
66
|
-
)
|
|
65
|
+
import asyncio
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
posthog.personal_api_key = None # Not needed for event tracking
|
|
67
|
+
config_manager = get_config_manager()
|
|
68
|
+
_shotgun_instance_id = asyncio.run(config_manager.get_shotgun_instance_id())
|
|
71
69
|
|
|
72
70
|
logger.debug(
|
|
73
|
-
"PostHog
|
|
71
|
+
"PostHog initialized with shotgun instance ID: %s",
|
|
72
|
+
_shotgun_instance_id,
|
|
74
73
|
)
|
|
75
74
|
except Exception as e:
|
|
76
|
-
logger.warning("Failed to
|
|
75
|
+
logger.warning("Failed to load shotgun instance ID: %s", e)
|
|
76
|
+
# Continue anyway - we'll try to get it during event tracking
|
|
77
77
|
|
|
78
78
|
logger.debug(
|
|
79
79
|
"PostHog analytics configured successfully (environment: %s, version: %s)",
|
|
@@ -94,16 +94,19 @@ def track_event(event_name: str, properties: dict[str, Any] | None = None) -> No
|
|
|
94
94
|
event_name: Name of the event to track
|
|
95
95
|
properties: Optional properties to include with the event
|
|
96
96
|
"""
|
|
97
|
-
global _posthog_client
|
|
97
|
+
global _posthog_client, _shotgun_instance_id
|
|
98
98
|
|
|
99
99
|
if _posthog_client is None:
|
|
100
100
|
logger.debug("PostHog not initialized, skipping event: %s", event_name)
|
|
101
101
|
return
|
|
102
102
|
|
|
103
103
|
try:
|
|
104
|
-
#
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
# Use cached instance ID (loaded during setup)
|
|
105
|
+
if _shotgun_instance_id is None:
|
|
106
|
+
logger.warning(
|
|
107
|
+
"Shotgun instance ID not available, skipping event: %s", event_name
|
|
108
|
+
)
|
|
109
|
+
return
|
|
107
110
|
|
|
108
111
|
# Add version and environment to properties
|
|
109
112
|
if properties is None:
|
|
@@ -118,7 +121,7 @@ def track_event(event_name: str, properties: dict[str, Any] | None = None) -> No
|
|
|
118
121
|
|
|
119
122
|
# Track the event using PostHog's capture method
|
|
120
123
|
_posthog_client.capture(
|
|
121
|
-
distinct_id=
|
|
124
|
+
distinct_id=_shotgun_instance_id, event=event_name, properties=properties
|
|
122
125
|
)
|
|
123
126
|
logger.debug("Tracked PostHog event: %s", event_name)
|
|
124
127
|
except Exception as e:
|
|
@@ -162,10 +165,16 @@ def submit_feedback_survey(feedback: Feedback) -> None:
|
|
|
162
165
|
logger.debug("PostHog not initialized, skipping feedback survey")
|
|
163
166
|
return
|
|
164
167
|
|
|
168
|
+
import asyncio
|
|
169
|
+
|
|
165
170
|
config_manager = get_config_manager()
|
|
166
|
-
config = config_manager.load()
|
|
171
|
+
config = asyncio.run(config_manager.load())
|
|
167
172
|
conversation_manager = ConversationManager()
|
|
168
|
-
conversation =
|
|
173
|
+
conversation = None
|
|
174
|
+
try:
|
|
175
|
+
conversation = asyncio.run(conversation_manager.load())
|
|
176
|
+
except Exception as e:
|
|
177
|
+
logger.debug(f"Failed to load conversation history: {e}")
|
|
169
178
|
last_10_messages = []
|
|
170
179
|
if conversation is not None:
|
|
171
180
|
last_10_messages = conversation.get_agent_messages()[:10]
|
shotgun/prompts/agents/export.j2
CHANGED
|
@@ -124,6 +124,7 @@ content_tasks = read_file('tasks.md') # Read implementation details
|
|
|
124
124
|
- `plan.md` - Extract development approach and stages
|
|
125
125
|
- `tasks.md` - Understand implementation tasks and structure
|
|
126
126
|
2. **Map content to agents.md standard sections**:
|
|
127
|
+
- **Research, Specifications, and Planning**: ALWAYS include this section first. Check which pipeline files exist in `.shotgun/` (research.md, specification.md, plan.md, tasks.md) and list only the ones that exist. If none exist, omit this section.
|
|
127
128
|
- **Project Overview**: Brief description and key technologies from specification.md
|
|
128
129
|
- **Dev Environment Setup**: Installation, dependencies, dev server commands
|
|
129
130
|
- **Code Style Guidelines**: Coding conventions and patterns from research.md
|
|
@@ -170,6 +171,14 @@ For additional specialized exports (only if specifically requested):
|
|
|
170
171
|
<CORRECT_CONTENT_TEMPLATE>
|
|
171
172
|
# Agents.md - [Project Name]
|
|
172
173
|
|
|
174
|
+
## Research, Specifications, and Planning
|
|
175
|
+
|
|
176
|
+
The `.shotgun/` folder contains background research, specifications, and implementation planning files. Refer to these files for additional context:
|
|
177
|
+
- `research.md` - Codebase analysis and research findings
|
|
178
|
+
- `specification.md` - Project requirements and specifications
|
|
179
|
+
- `plan.md` - Development plan and implementation approach
|
|
180
|
+
- `tasks.md` - Task breakdown and implementation progress
|
|
181
|
+
|
|
173
182
|
## Project Overview
|
|
174
183
|
- Brief description of what the project does
|
|
175
184
|
- Key technologies and frameworks used
|
|
@@ -253,6 +262,14 @@ This project is about [making assumptions without reading files]...
|
|
|
253
262
|
<GOOD_CONTENT_EXAMPLE>
|
|
254
263
|
# Agents.md - E-commerce API Project
|
|
255
264
|
|
|
265
|
+
## Research, Specifications, and Planning
|
|
266
|
+
|
|
267
|
+
The `.shotgun/` folder contains background research, specifications, and implementation planning files. Refer to these files for additional context:
|
|
268
|
+
- `research.md` - Codebase analysis and research findings
|
|
269
|
+
- `specification.md` - Project requirements and specifications
|
|
270
|
+
- `plan.md` - Development plan and implementation approach
|
|
271
|
+
- `tasks.md` - Task breakdown and implementation progress
|
|
272
|
+
|
|
256
273
|
## Project Overview
|
|
257
274
|
- REST API for product catalog management with authentication
|
|
258
275
|
- Built with Python/FastAPI for high performance async operations
|
|
@@ -316,7 +333,7 @@ This project is about [making assumptions without reading files]...
|
|
|
316
333
|
USER INTERACTION - CLARIFY EXPORT REQUIREMENTS:
|
|
317
334
|
|
|
318
335
|
- ALWAYS ask clarifying questions when export requirements are unclear
|
|
319
|
-
- Use
|
|
336
|
+
- Use clarifying questions to gather specific details about:
|
|
320
337
|
- Target format and file type preferences
|
|
321
338
|
- Intended use case and audience for the export
|
|
322
339
|
- Specific content sections to include/exclude from files
|
|
@@ -7,7 +7,11 @@ Your extensive expertise spans, among other things:
|
|
|
7
7
|
## KEY RULES
|
|
8
8
|
|
|
9
9
|
{% if interactive_mode %}
|
|
10
|
-
0. Always ask CLARIFYING QUESTIONS
|
|
10
|
+
0. Always ask CLARIFYING QUESTIONS using structured output before doing work.
|
|
11
|
+
- Return your response with the clarifying_questions field populated
|
|
12
|
+
- Do not make assumptions about what the user wants, get a clear understanding first.
|
|
13
|
+
- Questions should be clear, specific, and answerable
|
|
14
|
+
- Do not ask too many questions that might overwhelm the user; prioritize the most important ones.
|
|
11
15
|
{% endif %}
|
|
12
16
|
1. Above all, prefer using tools to do the work and NEVER respond with text.
|
|
13
17
|
2. IMPORTANT: Always ask for review and go ahead to move forward after using write_file().
|
|
@@ -6,20 +6,37 @@
|
|
|
6
6
|
{% if interactive_mode -%}
|
|
7
7
|
IMPORTANT: USER INTERACTION IS ENABLED (interactive mode).
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
## Structured Output Format
|
|
10
|
+
|
|
11
|
+
You must return responses using this structured format:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"response": "Your main response text here",
|
|
16
|
+
"clarifying_questions": ["Question 1?", "Question 2?"] // Optional, only when needed
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## When to Use Clarifying Questions
|
|
21
|
+
|
|
22
|
+
- BEFORE GETTING TO WORK: If the user's request is ambiguous, use clarifying_questions to ask what they want
|
|
23
|
+
- DURING WORK: After using write_file(), you can suggest that the user review it and ask any clarifying questions with clarifying_questions
|
|
12
24
|
- Don't assume - ask for confirmation of your understanding
|
|
13
|
-
- When in doubt about any aspect of the goal,
|
|
25
|
+
- When in doubt about any aspect of the goal, include clarifying_questions
|
|
26
|
+
|
|
27
|
+
## Important Notes
|
|
28
|
+
|
|
29
|
+
- If you don't need to ask questions, set clarifying_questions to null or omit it
|
|
30
|
+
- Keep response field concise - a paragraph at most for user communication
|
|
31
|
+
- Questions should be clear, specific, and independently answerable
|
|
32
|
+
- Don't ask multiple questions in one string - use separate array items
|
|
14
33
|
|
|
15
34
|
{% else -%}
|
|
16
35
|
|
|
17
36
|
IMPORTANT: USER INTERACTION IS DISABLED (non-interactive mode).
|
|
18
|
-
- You cannot ask clarifying questions
|
|
37
|
+
- You cannot ask clarifying questions (clarifying_questions will be ignored)
|
|
19
38
|
- Make reasonable assumptions based on best practices
|
|
20
39
|
- Use sensible defaults when information is missing
|
|
21
|
-
- Make reasonable assumptions based on industry best practices
|
|
22
|
-
- Use sensible defaults when specific details are not provided
|
|
23
40
|
- When in doubt, make reasonable assumptions and proceed with best practices
|
|
24
41
|
{% endif %}
|
|
25
42
|
|
shotgun/prompts/agents/plan.j2
CHANGED
|
@@ -118,7 +118,7 @@ USER INTERACTION - REDUCE UNCERTAINTY:
|
|
|
118
118
|
- FIRST read `research.md` and `specification.md` before asking ANY questions
|
|
119
119
|
- ONLY ask clarifying questions AFTER reading the context files
|
|
120
120
|
- Questions should be about gaps not covered in research/specification
|
|
121
|
-
- Use
|
|
121
|
+
- Use clarifying questions to gather specific details about:
|
|
122
122
|
- Information not found in the context files
|
|
123
123
|
- Clarifications on ambiguous specifications
|
|
124
124
|
- Priorities when multiple options exist
|
|
@@ -39,7 +39,7 @@ For research tasks:
|
|
|
39
39
|
## RESEARCH PRINCIPLES
|
|
40
40
|
|
|
41
41
|
{% if interactive_mode -%}
|
|
42
|
-
- CRITICAL: BEFORE RUNNING ANY SEARCH TOOL, ASK THE USER FOR APPROVAL
|
|
42
|
+
- CRITICAL: BEFORE RUNNING ANY SEARCH TOOL, ASK THE USER FOR APPROVAL using clarifying questions. Include what you plan to search for and ask if they want you to proceed.
|
|
43
43
|
{% endif -%}
|
|
44
44
|
- Build upon existing research rather than starting from scratch
|
|
45
45
|
- Focus on practical, actionable information over theoretical concepts
|