shotgun-sh 0.1.0__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.
- shotgun/__init__.py +5 -0
- shotgun/agents/__init__.py +1 -0
- shotgun/agents/agent_manager.py +651 -0
- shotgun/agents/common.py +549 -0
- shotgun/agents/config/__init__.py +13 -0
- shotgun/agents/config/constants.py +17 -0
- shotgun/agents/config/manager.py +294 -0
- shotgun/agents/config/models.py +185 -0
- shotgun/agents/config/provider.py +206 -0
- shotgun/agents/conversation_history.py +106 -0
- shotgun/agents/conversation_manager.py +105 -0
- shotgun/agents/export.py +96 -0
- shotgun/agents/history/__init__.py +5 -0
- shotgun/agents/history/compaction.py +85 -0
- shotgun/agents/history/constants.py +19 -0
- shotgun/agents/history/context_extraction.py +108 -0
- shotgun/agents/history/history_building.py +104 -0
- shotgun/agents/history/history_processors.py +426 -0
- shotgun/agents/history/message_utils.py +84 -0
- shotgun/agents/history/token_counting.py +429 -0
- shotgun/agents/history/token_estimation.py +138 -0
- shotgun/agents/messages.py +35 -0
- shotgun/agents/models.py +275 -0
- shotgun/agents/plan.py +98 -0
- shotgun/agents/research.py +108 -0
- shotgun/agents/specify.py +98 -0
- shotgun/agents/tasks.py +96 -0
- shotgun/agents/tools/__init__.py +34 -0
- shotgun/agents/tools/codebase/__init__.py +28 -0
- shotgun/agents/tools/codebase/codebase_shell.py +256 -0
- shotgun/agents/tools/codebase/directory_lister.py +141 -0
- shotgun/agents/tools/codebase/file_read.py +144 -0
- shotgun/agents/tools/codebase/models.py +252 -0
- shotgun/agents/tools/codebase/query_graph.py +67 -0
- shotgun/agents/tools/codebase/retrieve_code.py +81 -0
- shotgun/agents/tools/file_management.py +218 -0
- shotgun/agents/tools/user_interaction.py +37 -0
- shotgun/agents/tools/web_search/__init__.py +60 -0
- shotgun/agents/tools/web_search/anthropic.py +144 -0
- shotgun/agents/tools/web_search/gemini.py +85 -0
- shotgun/agents/tools/web_search/openai.py +98 -0
- shotgun/agents/tools/web_search/utils.py +20 -0
- shotgun/build_constants.py +20 -0
- shotgun/cli/__init__.py +1 -0
- shotgun/cli/codebase/__init__.py +5 -0
- shotgun/cli/codebase/commands.py +202 -0
- shotgun/cli/codebase/models.py +21 -0
- shotgun/cli/config.py +275 -0
- shotgun/cli/export.py +81 -0
- shotgun/cli/models.py +10 -0
- shotgun/cli/plan.py +73 -0
- shotgun/cli/research.py +85 -0
- shotgun/cli/specify.py +69 -0
- shotgun/cli/tasks.py +78 -0
- shotgun/cli/update.py +152 -0
- shotgun/cli/utils.py +25 -0
- shotgun/codebase/__init__.py +12 -0
- shotgun/codebase/core/__init__.py +46 -0
- shotgun/codebase/core/change_detector.py +358 -0
- shotgun/codebase/core/code_retrieval.py +243 -0
- shotgun/codebase/core/ingestor.py +1497 -0
- shotgun/codebase/core/language_config.py +297 -0
- shotgun/codebase/core/manager.py +1662 -0
- shotgun/codebase/core/nl_query.py +331 -0
- shotgun/codebase/core/parser_loader.py +128 -0
- shotgun/codebase/models.py +111 -0
- shotgun/codebase/service.py +206 -0
- shotgun/logging_config.py +227 -0
- shotgun/main.py +167 -0
- shotgun/posthog_telemetry.py +158 -0
- shotgun/prompts/__init__.py +5 -0
- shotgun/prompts/agents/__init__.py +1 -0
- shotgun/prompts/agents/export.j2 +350 -0
- shotgun/prompts/agents/partials/codebase_understanding.j2 +87 -0
- shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +37 -0
- shotgun/prompts/agents/partials/content_formatting.j2 +65 -0
- shotgun/prompts/agents/partials/interactive_mode.j2 +26 -0
- shotgun/prompts/agents/plan.j2 +144 -0
- shotgun/prompts/agents/research.j2 +69 -0
- shotgun/prompts/agents/specify.j2 +51 -0
- shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +19 -0
- shotgun/prompts/agents/state/system_state.j2 +31 -0
- shotgun/prompts/agents/tasks.j2 +143 -0
- shotgun/prompts/codebase/__init__.py +1 -0
- shotgun/prompts/codebase/cypher_query_patterns.j2 +223 -0
- shotgun/prompts/codebase/cypher_system.j2 +28 -0
- shotgun/prompts/codebase/enhanced_query_context.j2 +10 -0
- shotgun/prompts/codebase/partials/cypher_rules.j2 +24 -0
- shotgun/prompts/codebase/partials/graph_schema.j2 +30 -0
- shotgun/prompts/codebase/partials/temporal_context.j2 +21 -0
- shotgun/prompts/history/__init__.py +1 -0
- shotgun/prompts/history/incremental_summarization.j2 +53 -0
- shotgun/prompts/history/summarization.j2 +46 -0
- shotgun/prompts/loader.py +140 -0
- shotgun/py.typed +0 -0
- shotgun/sdk/__init__.py +13 -0
- shotgun/sdk/codebase.py +219 -0
- shotgun/sdk/exceptions.py +17 -0
- shotgun/sdk/models.py +189 -0
- shotgun/sdk/services.py +23 -0
- shotgun/sentry_telemetry.py +87 -0
- shotgun/telemetry.py +93 -0
- shotgun/tui/__init__.py +0 -0
- shotgun/tui/app.py +116 -0
- shotgun/tui/commands/__init__.py +76 -0
- shotgun/tui/components/prompt_input.py +69 -0
- shotgun/tui/components/spinner.py +86 -0
- shotgun/tui/components/splash.py +25 -0
- shotgun/tui/components/vertical_tail.py +13 -0
- shotgun/tui/screens/chat.py +782 -0
- shotgun/tui/screens/chat.tcss +43 -0
- shotgun/tui/screens/chat_screen/__init__.py +0 -0
- shotgun/tui/screens/chat_screen/command_providers.py +219 -0
- shotgun/tui/screens/chat_screen/hint_message.py +40 -0
- shotgun/tui/screens/chat_screen/history.py +221 -0
- shotgun/tui/screens/directory_setup.py +113 -0
- shotgun/tui/screens/provider_config.py +221 -0
- shotgun/tui/screens/splash.py +31 -0
- shotgun/tui/styles.tcss +10 -0
- shotgun/tui/utils/__init__.py +5 -0
- shotgun/tui/utils/mode_progress.py +257 -0
- shotgun/utils/__init__.py +5 -0
- shotgun/utils/env_utils.py +35 -0
- shotgun/utils/file_system_utils.py +36 -0
- shotgun/utils/update_checker.py +375 -0
- shotgun_sh-0.1.0.dist-info/METADATA +466 -0
- shotgun_sh-0.1.0.dist-info/RECORD +130 -0
- shotgun_sh-0.1.0.dist-info/WHEEL +4 -0
- shotgun_sh-0.1.0.dist-info/entry_points.txt +2 -0
- shotgun_sh-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# FOLLOW THESE PATTERNS TO GENERATE THE CORRECT CYPHER QUERY:
|
|
2
|
+
|
|
3
|
+
**Pattern: Finding All Classes**
|
|
4
|
+
```cypher
|
|
5
|
+
// "Find all Python classes" or "list all classes" or "show me all classes"
|
|
6
|
+
MATCH (c:Class)
|
|
7
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
|
|
8
|
+
ORDER BY c.name
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**Pattern: Finding Classes with Path Information**
|
|
12
|
+
```cypher
|
|
13
|
+
// "Find Python classes with their file paths" or "show classes and where they are defined"
|
|
14
|
+
MATCH (m:Module)-[:DEFINES]->(c:Class)
|
|
15
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, m.path AS module_path, 'Class' AS type
|
|
16
|
+
ORDER BY m.path, c.name
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Pattern: Finding Decorated Functions/Methods (e.g., Workflows, Tasks)**
|
|
20
|
+
```cypher
|
|
21
|
+
// "Find all prefect flows" or "what are the workflows?" or "show me the tasks"
|
|
22
|
+
// Use separate MATCH clauses since Kuzu doesn't support union types
|
|
23
|
+
MATCH (n:Function)
|
|
24
|
+
WHERE ANY(d IN n.decorators WHERE toLower(d) IN ['flow', 'task'])
|
|
25
|
+
RETURN n.name AS name, n.qualified_name AS qualified_name, 'Function' AS type
|
|
26
|
+
UNION ALL
|
|
27
|
+
MATCH (n:Method)
|
|
28
|
+
WHERE ANY(d IN n.decorators WHERE toLower(d) IN ['flow', 'task'])
|
|
29
|
+
RETURN n.name AS name, n.qualified_name AS qualified_name, 'Method' AS type
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Pattern: Finding Content by Path (Using UNION ALL for Different Types)**
|
|
33
|
+
```cypher
|
|
34
|
+
// "what is in the 'workflows/src' directory?" or "list files in workflows"
|
|
35
|
+
// Use separate queries with UNION ALL to handle different node types
|
|
36
|
+
MATCH (n:Module)
|
|
37
|
+
WHERE n.path STARTS WITH 'workflows'
|
|
38
|
+
RETURN n.name AS name, n.path AS path, 'Module' AS type
|
|
39
|
+
UNION ALL
|
|
40
|
+
MATCH (n:File)
|
|
41
|
+
WHERE n.path STARTS WITH 'workflows'
|
|
42
|
+
RETURN n.name AS name, n.path AS path, 'File' AS type
|
|
43
|
+
UNION ALL
|
|
44
|
+
MATCH (n:Folder)
|
|
45
|
+
WHERE n.path STARTS WITH 'workflows'
|
|
46
|
+
RETURN n.name AS name, n.path AS path, 'Folder' AS type
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Pattern: Keyword & Concept Search (Fallback for general terms)**
|
|
50
|
+
```cypher
|
|
51
|
+
// "find things related to 'database'"
|
|
52
|
+
MATCH (n)
|
|
53
|
+
WHERE toLower(n.name) CONTAINS 'database' OR (n.qualified_name IS NOT NULL AND toLower(n.qualified_name) CONTAINS 'database')
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Pattern: Time-based Queries (IMPORTANT: Use actual timestamps from user query)**
|
|
57
|
+
```cypher
|
|
58
|
+
// "What functions were added in the last 2 minutes?" when current timestamp is provided
|
|
59
|
+
MATCH (f:Function)
|
|
60
|
+
WHERE f.created_at > [current_timestamp - 120] // This is current_timestamp - 120
|
|
61
|
+
RETURN f.name AS name, f.qualified_name AS qualified_name, f.created_at AS created_timestamp
|
|
62
|
+
ORDER BY f.created_at DESC
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```cypher
|
|
66
|
+
// "What classes were modified today?" when current timestamp is provided
|
|
67
|
+
MATCH (c:Class)
|
|
68
|
+
WHERE c.updated_at >= [today's start timestamp] // This is today's start
|
|
69
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, c.updated_at AS updated_timestamp
|
|
70
|
+
ORDER BY c.updated_at DESC
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Pattern: Finding Files by Extension**
|
|
74
|
+
```cypher
|
|
75
|
+
// "Find all TypeScript files" or "show me .ts files"
|
|
76
|
+
// IMPORTANT: File extensions are stored WITH the dot (e.g., ".ts" not "ts")
|
|
77
|
+
MATCH (f:File)
|
|
78
|
+
WHERE f.extension = '.ts'
|
|
79
|
+
RETURN f.path AS path, f.name AS name, f.extension AS extension, 'File' AS type
|
|
80
|
+
ORDER BY f.path
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```cypher
|
|
84
|
+
// "Find JavaScript and TypeScript files"
|
|
85
|
+
MATCH (f:File)
|
|
86
|
+
WHERE f.extension IN ['.js', '.ts', '.jsx', '.tsx']
|
|
87
|
+
RETURN f.path AS path, f.name AS name, f.extension AS extension, 'File' AS type
|
|
88
|
+
ORDER BY f.path
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Pattern: Finding a Specific File**
|
|
92
|
+
```cypher
|
|
93
|
+
// "Find the main README.md"
|
|
94
|
+
MATCH (f:File) WHERE toLower(f.name) = 'readme.md' AND f.path = 'README.md'
|
|
95
|
+
RETURN f.path as path, f.name as name, 'File' as type
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Pattern: Finding Classes in a Specific Directory**
|
|
99
|
+
```cypher
|
|
100
|
+
// "Find classes in the server directory"
|
|
101
|
+
MATCH (m:Module)-[:DEFINES]->(c:Class)
|
|
102
|
+
WHERE m.path STARTS WITH 'server/'
|
|
103
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Pattern: Finding Modules with Most Classes**
|
|
107
|
+
```cypher
|
|
108
|
+
// "Find modules that define the most classes"
|
|
109
|
+
MATCH (m:Module)-[:DEFINES]->(c:Class)
|
|
110
|
+
WITH m, count(c) AS class_count
|
|
111
|
+
ORDER BY class_count DESC
|
|
112
|
+
LIMIT 10
|
|
113
|
+
RETURN m.name AS name, m.qualified_name AS qualified_name, m.path AS path, class_count
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Pattern: Finding Classes with Method Counts**
|
|
117
|
+
```cypher
|
|
118
|
+
// "Find classes with more than N methods" or "Show me classes that have at least X methods"
|
|
119
|
+
MATCH (c:Class)-[:DEFINES_METHOD]->(m:Method)
|
|
120
|
+
WITH c, count(m) AS method_count
|
|
121
|
+
WHERE method_count > 10 // Replace 10 with the actual number from query
|
|
122
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, method_count
|
|
123
|
+
ORDER BY method_count DESC
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Pattern: Finding Classes with Inheritance (Note: INHERITS relationships must exist)**
|
|
127
|
+
```cypher
|
|
128
|
+
// "Find classes with children/subclasses"
|
|
129
|
+
// This will return NO results if no inheritance relationships exist in the graph
|
|
130
|
+
MATCH (child:Class)-[:INHERITS]->(parent:Class)
|
|
131
|
+
WITH parent, count(child) AS child_count
|
|
132
|
+
ORDER BY child_count DESC
|
|
133
|
+
LIMIT 10
|
|
134
|
+
RETURN parent.name AS name, parent.qualified_name AS qualified_name, child_count
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Pattern: Finding Parent Classes of a Specific Class**
|
|
138
|
+
```cypher
|
|
139
|
+
// "What are the parent classes of DeputyAgent?" or "What does DeputyAgent inherit from?"
|
|
140
|
+
// Use name for short class names (when user doesn't provide full path)
|
|
141
|
+
MATCH (child:Class)-[:INHERITS]->(parent:Class)
|
|
142
|
+
WHERE toLower(child.name) = 'deputyagent'
|
|
143
|
+
RETURN parent.name AS name, parent.qualified_name AS qualified_name
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Pattern: Finding Methods of a Specific Class**
|
|
147
|
+
```cypher
|
|
148
|
+
// "What methods does WebSocketServer have?" or "List methods in WebSocketServer class"
|
|
149
|
+
// When user provides just the class name without full path
|
|
150
|
+
MATCH (c:Class)-[:DEFINES_METHOD]->(m:Method)
|
|
151
|
+
WHERE c.name = 'WebSocketServer'
|
|
152
|
+
RETURN m.name AS name, m.qualified_name AS qualified_name, 'Method' AS type
|
|
153
|
+
ORDER BY m.name
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Pattern: Finding a Specific Entity by Full Qualified Name**
|
|
157
|
+
```cypher
|
|
158
|
+
// "Find shotgun.server.WebSocketServer" or "Show me api.websocket.server.WebSocketServer"
|
|
159
|
+
// When user provides a dotted path, match against qualified_name
|
|
160
|
+
MATCH (c:Class)
|
|
161
|
+
WHERE c.qualified_name = 'shotgun2.server.src.shotgun.api.websocket.server.WebSocketServer'
|
|
162
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Pattern: Finding Recently Added/Modified Code**
|
|
166
|
+
```cypher
|
|
167
|
+
// "Find functions added in the last 24 hours" or "What new functions were added today?"
|
|
168
|
+
// Note: In Kuzu, use Unix timestamps directly (seconds since epoch)
|
|
169
|
+
// Example: 1704067200 represents 2024-01-01 00:00:00 UTC
|
|
170
|
+
// For "today": use timestamp from start of current day
|
|
171
|
+
// For "last 24 hours": use current_timestamp - 86400
|
|
172
|
+
MATCH (f:Function)
|
|
173
|
+
WHERE f.created_at > [current_timestamp - 86400] // Replace with actual timestamp for "24 hours ago"
|
|
174
|
+
RETURN f.name AS name, f.qualified_name AS qualified_name, f.created_at AS created_timestamp
|
|
175
|
+
ORDER BY f.created_at DESC
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Pattern: Finding Files Modified Recently**
|
|
179
|
+
```cypher
|
|
180
|
+
// "Find files modified today" or "Which files changed in the last hour?"
|
|
181
|
+
// For "last hour": use current_timestamp - 3600
|
|
182
|
+
// For "today": use timestamp from start of current day
|
|
183
|
+
MATCH (fm:FileMetadata)
|
|
184
|
+
WHERE fm.mtime > [current_timestamp - 3600] // Replace with actual timestamp
|
|
185
|
+
RETURN fm.filepath AS path, fm.mtime AS last_modified
|
|
186
|
+
ORDER BY fm.mtime DESC
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Pattern: Queries About Deleted/Removed Entities**
|
|
190
|
+
```cypher
|
|
191
|
+
// "What functions were deleted/removed?" or "Show me classes that no longer exist"
|
|
192
|
+
// Query the DeletionLog table for tracking removed entities
|
|
193
|
+
MATCH (d:DeletionLog)
|
|
194
|
+
WHERE d.entity_type = 'Function' AND d.deleted_at > [current_timestamp - 86400] // Replace with timestamp for time range
|
|
195
|
+
RETURN d.entity_qualified_name AS name, d.deleted_from_file AS file, d.deleted_at AS deleted_at, d.deletion_reason AS reason
|
|
196
|
+
ORDER BY d.deleted_at DESC
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Pattern: Finding Where a Method/Function is Called**
|
|
200
|
+
```cypher
|
|
201
|
+
// "where is WebSocketServer.start called?" or "find callers of method X"
|
|
202
|
+
// For partial names like 'WebSocketServer.start', use ENDS WITH pattern
|
|
203
|
+
MATCH (caller:Method)-[:CALLS]->(target:Method)
|
|
204
|
+
WHERE target.qualified_name ENDS WITH '.WebSocketServer.start'
|
|
205
|
+
RETURN caller.name AS name, caller.qualified_name AS qualified_name, 'Method' AS caller_type
|
|
206
|
+
UNION ALL
|
|
207
|
+
MATCH (caller:Function)-[:CALLS]->(target:Method)
|
|
208
|
+
WHERE target.qualified_name ENDS WITH '.WebSocketServer.start'
|
|
209
|
+
RETURN caller.name AS name, caller.qualified_name AS qualified_name, 'Function' AS caller_type
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Pattern: Finding What a Method/Function Calls**
|
|
213
|
+
```cypher
|
|
214
|
+
// "what does WebSocketServer.start call?" or "what methods does X invoke?"
|
|
215
|
+
// Use ENDS WITH for partial names, UNION ALL to handle different target types
|
|
216
|
+
MATCH (source:Method)-[:CALLS]->(target:Method)
|
|
217
|
+
WHERE source.qualified_name ENDS WITH '.WebSocketServer.start'
|
|
218
|
+
RETURN target.name AS name, target.qualified_name AS qualified_name, 'Method' AS target_type
|
|
219
|
+
UNION ALL
|
|
220
|
+
MATCH (source:Method)-[:CALLS]->(target:Function)
|
|
221
|
+
WHERE source.qualified_name ENDS WITH '.WebSocketServer.start'
|
|
222
|
+
RETURN target.name AS name, target.qualified_name AS qualified_name, 'Function' AS target_type
|
|
223
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
You are an expert translator that converts natural language questions about code structure into precise Neo4j Cypher queries.
|
|
2
|
+
|
|
3
|
+
{% include 'codebase/partials/graph_schema.j2' %}
|
|
4
|
+
|
|
5
|
+
{% include 'codebase/partials/cypher_rules.j2' %}
|
|
6
|
+
|
|
7
|
+
**3. Query Patterns & Examples**
|
|
8
|
+
Your goal is to return appropriate properties for each node type. Common properties:
|
|
9
|
+
- All nodes have: `name`
|
|
10
|
+
- Nodes with paths: Module, Package, File, Folder (have `path` property)
|
|
11
|
+
- Code entities: Class, Function, Method (have `qualified_name` but NO `path` - get path via Module relationship)
|
|
12
|
+
- Always include a type indicator (either as a string literal or via CASE statement)
|
|
13
|
+
- Do NOT include comments (// or /*) in your queries.
|
|
14
|
+
|
|
15
|
+
**IMPORTANT: Handling Entity Names**
|
|
16
|
+
- `name` property: Contains only the simple/short name (e.g., 'WebSocketServer', 'start')
|
|
17
|
+
- `qualified_name` property: Contains the full qualified path (e.g., 'shotgun2.server.src.shotgun.api.websocket.server.WebSocketServer')
|
|
18
|
+
- When users mention a specific class/function/method by name:
|
|
19
|
+
- If it looks like a short name, use: `WHERE c.name = 'WebSocketServer'`
|
|
20
|
+
- If it contains dots or looks like a full path, use: `WHERE c.qualified_name = 'full.path.to.Class'`
|
|
21
|
+
- For partial paths, use: `WHERE c.qualified_name CONTAINS 'partial.path'` or `WHERE c.qualified_name ENDS WITH '.WebSocketServer'`
|
|
22
|
+
|
|
23
|
+
{% include 'codebase/cypher_query_patterns.j2' %}
|
|
24
|
+
|
|
25
|
+
{% include 'codebase/partials/temporal_context.j2' %}
|
|
26
|
+
|
|
27
|
+
**6. Output Format**
|
|
28
|
+
Provide only the Cypher query.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Current datetime: {{ current_datetime }} (Unix timestamp: {{ current_timestamp }})
|
|
2
|
+
|
|
3
|
+
User query: {{ natural_language_query }}
|
|
4
|
+
|
|
5
|
+
IMPORTANT: All timestamps in the database are stored as Unix timestamps (INT64). When generating time-based queries:
|
|
6
|
+
- For "2 minutes ago": use {{ current_timestamp - 120 }}
|
|
7
|
+
- For "1 hour ago": use {{ current_timestamp - 3600 }}
|
|
8
|
+
- For "today": use timestamps >= {{ current_timestamp - (current_timestamp % 86400) }}
|
|
9
|
+
- For "yesterday": use timestamps between {{ current_timestamp - 86400 - (current_timestamp % 86400) }} and {{ current_timestamp - (current_timestamp % 86400) }}
|
|
10
|
+
- NEVER use placeholder values like 1704067200, always calculate based on the current timestamp: {{ current_timestamp }}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
**2. Critical Cypher Query Rules**
|
|
2
|
+
|
|
3
|
+
- **ALWAYS Return Specific Properties with Aliases**: Do NOT return whole nodes (e.g., `RETURN n`). You MUST return specific properties with clear aliases (e.g., `RETURN n.name AS name`).
|
|
4
|
+
- **File Extensions Include Dots**: File extensions are stored WITH the leading dot (e.g., `.ts`, `.py`, `.js`). When querying for files by extension, ALWAYS include the dot: `WHERE f.extension = '.ts'` NOT `WHERE f.extension = 'ts'`.
|
|
5
|
+
- **Use `STARTS WITH` for Paths**: When matching paths, always use `STARTS WITH` for robustness (e.g., `WHERE n.path STARTS WITH 'workflows/src'`). Do not use `=`.
|
|
6
|
+
- **Use `toLower()` for Searches**: For case-insensitive searching on string properties, use `toLower()`.
|
|
7
|
+
- **Querying Lists**: To check if a list property (like `decorators`) contains an item, use the `ANY` or `IN` clause (e.g., `WHERE 'flow' IN n.decorators`).
|
|
8
|
+
- **No Union Types in Patterns**: Kuzu does NOT support union types like `(n:Function|Method)`. Use separate MATCH clauses or OPTIONAL MATCH instead.
|
|
9
|
+
- **Timestamps in Kuzu**: Timestamps are stored as INT64 Unix timestamps (seconds since epoch). Do NOT use `timestamp()` function. For time-based queries, use numeric comparisons with Unix timestamp values that are calculated from the current timestamp provided in the user query. NEVER use hardcoded timestamps like 1704067200.
|
|
10
|
+
- **No labels() Function**: Kuzu does NOT support the `labels()` function. Do not use `labels(n)` in queries. If you need to indicate the type, use a string literal like 'Class' or 'Function'.
|
|
11
|
+
- **CASE Statements**: Kuzu has limited support for CASE statements. AVOID using CASE WHEN in RETURN clauses. Instead, use string literals for type indication or UNION ALL for handling multiple node types.
|
|
12
|
+
- **UNION ALL Column Matching**: When using UNION ALL, EVERY part MUST return the EXACT SAME columns with the SAME names in the SAME order.
|
|
13
|
+
CORRECT usage:
|
|
14
|
+
```
|
|
15
|
+
MATCH (f:Function) WHERE ... RETURN f.name AS name, f.qualified_name AS qname, 'Function' AS type
|
|
16
|
+
UNION ALL
|
|
17
|
+
MATCH (m:Method) WHERE ... RETURN m.name AS name, m.qualified_name AS qname, 'Method' AS type
|
|
18
|
+
```
|
|
19
|
+
INCORRECT usage (different column counts or names):
|
|
20
|
+
```
|
|
21
|
+
MATCH (f:Function) RETURN f.name AS name, f.qualified_name AS qname
|
|
22
|
+
UNION ALL
|
|
23
|
+
MATCH (m:Method) RETURN m.name AS name, m.qualified_name AS qname, m.path AS path // ERROR: Extra column!
|
|
24
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
# Codebase Graph Schema Definition
|
|
3
|
+
The database contains information about a codebase, structured with the following nodes and relationships.
|
|
4
|
+
|
|
5
|
+
THE ONLY PROPERTIES THAT ARE AVAILABLE ARE THE ONES LISTED BELOW. DO NOT MAKE UP ANY OTHER PROPERTIES.
|
|
6
|
+
PAY ATTENTION TO THE PROPERTY TYPES.
|
|
7
|
+
- Project: {name: string}
|
|
8
|
+
- Package: {qualified_name: string, name: string, path: string}
|
|
9
|
+
- Folder: {path: string, name: string}
|
|
10
|
+
- File: {path: string, name: string, extension: string} // Note: extension includes the dot (e.g., ".ts", ".py", ".js")
|
|
11
|
+
- FileMetadata: {filepath: string, mtime: int64, hash: string, last_updated: int64}
|
|
12
|
+
- Module: {qualified_name: string, name: string, path: string, created_at: int64, updated_at: int64}
|
|
13
|
+
- Class: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
|
|
14
|
+
- Function: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
|
|
15
|
+
- Method: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
|
|
16
|
+
- ExternalPackage: {name: string, version_spec: string}
|
|
17
|
+
- DeletionLog: {id: string, entity_type: string, entity_qualified_name: string, deleted_from_file: string, deleted_at: int64, deletion_reason: string}
|
|
18
|
+
|
|
19
|
+
Relationships (source)-[REL_TYPE]->(target):
|
|
20
|
+
- (Project|Package|Folder) -[:CONTAINS_PACKAGE|CONTAINS_FOLDER|CONTAINS_FILE|CONTAINS_MODULE]-> (various)
|
|
21
|
+
- Module -[:DEFINES]-> (Class|Function)
|
|
22
|
+
- Class -[:DEFINES_METHOD]-> Method
|
|
23
|
+
- (Child Class) -[:INHERITS]-> (Parent Class)
|
|
24
|
+
- Method -[:OVERRIDES]-> Method
|
|
25
|
+
- Project -[:DEPENDS_ON_EXTERNAL]-> ExternalPackage
|
|
26
|
+
- (Function|Method) -[:CALLS]-> (Function|Method)
|
|
27
|
+
- FileMetadata -[:TRACKS_Module]-> Module
|
|
28
|
+
- FileMetadata -[:TRACKS_Class]-> Class
|
|
29
|
+
- FileMetadata -[:TRACKS_Function]-> Function
|
|
30
|
+
- FileMetadata -[:TRACKS_Method]-> Method
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
**4. Handling Time-based Queries**
|
|
2
|
+
When users ask about "today", "yesterday", "last hour", "last week", etc., convert these to Unix timestamp comparisons:
|
|
3
|
+
- "today" → Use a timestamp representing start of current day (e.g., WHERE f.created_at > [today's start timestamp])
|
|
4
|
+
- "yesterday" → Use timestamps for yesterday's range
|
|
5
|
+
- "last hour" → Current time minus 3600 seconds
|
|
6
|
+
- "last 24 hours" → Current time minus 86400 seconds
|
|
7
|
+
- "last week" → Current time minus 604800 seconds
|
|
8
|
+
|
|
9
|
+
Since you cannot calculate the current time, use reasonable example timestamps that would work for the query.
|
|
10
|
+
The actual timestamp calculation will be handled by the calling application.
|
|
11
|
+
|
|
12
|
+
**5. Handling Queries About Deleted/Removed Entities**
|
|
13
|
+
When users ask about "removed", "deleted", or "no longer exist" entities:
|
|
14
|
+
- Query the DeletionLog table which tracks all deletions
|
|
15
|
+
- Filter by entity_type (Function, Method, Class, Module) based on what they're asking about
|
|
16
|
+
- Use timestamp comparisons for time-based deletion queries
|
|
17
|
+
- The deletion_reason field indicates why it was deleted (e.g., "removed_from_file", "file_deleted")
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
- "What functions were removed today?" → Query DeletionLog WHERE entity_type = 'Function' AND deleted_at > [today's timestamp]
|
|
21
|
+
- "Show deleted classes from auth module" → Query DeletionLog WHERE entity_type = 'Class' AND entity_qualified_name CONTAINS 'auth'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""History processing prompt templates."""
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
You are extending an existing conversation summary with new messages.
|
|
2
|
+
|
|
3
|
+
Your task is to merge the new information into the existing summary while maintaining the same structured format and preserving all important information.
|
|
4
|
+
|
|
5
|
+
<EXISTING_SUMMARY>
|
|
6
|
+
{{ existing_summary }}
|
|
7
|
+
</EXISTING_SUMMARY>
|
|
8
|
+
|
|
9
|
+
<NEW_MESSAGES>
|
|
10
|
+
{{ new_messages }}
|
|
11
|
+
</NEW_MESSAGES>
|
|
12
|
+
|
|
13
|
+
Instructions:
|
|
14
|
+
1. Update the existing summary sections with new information from the NEW_MESSAGES
|
|
15
|
+
2. Maintain the same structure and format as the existing summary
|
|
16
|
+
3. Preserve all important information from both existing and new content
|
|
17
|
+
4. Do not repeat information already covered in the existing summary unless it's been updated or expanded
|
|
18
|
+
5. Focus on integrating new developments, decisions, or progress into the appropriate sections
|
|
19
|
+
|
|
20
|
+
<OUTPUT_FORMAT>
|
|
21
|
+
Provide the complete updated summary following the exact same format as the existing summary:
|
|
22
|
+
|
|
23
|
+
# Context
|
|
24
|
+
|
|
25
|
+
Updated summary of the discussion, incorporating new topics or tasks. Present it as clear bullet points. Be brief but do not lose information that might be important for the current state, task or objectives.
|
|
26
|
+
|
|
27
|
+
# Key elements, learnings and entities
|
|
28
|
+
|
|
29
|
+
Present the updated important elements of context, learnings and entities from the entire discussion. Be very detailed.
|
|
30
|
+
|
|
31
|
+
Present it as clear bullet points. Be brief but do not lose information that might be important for the current state, task or objectives.
|
|
32
|
+
|
|
33
|
+
If new tool results were obtained, preserve them verbatim if short, summarize if long focusing on preserving all important facts.
|
|
34
|
+
|
|
35
|
+
If new user messages exist, preserve them verbatim if short to medium length, summarize if long focusing on preserving all important facts.
|
|
36
|
+
|
|
37
|
+
If there are any new links, IDs, filenames, etc. - preserve them verbatim.
|
|
38
|
+
|
|
39
|
+
# Timeline
|
|
40
|
+
|
|
41
|
+
Update the timeline with new important tasks and content:
|
|
42
|
+
- User: asked to handle a complex task X: <summary of the task>
|
|
43
|
+
- Assistant: we handle it by doing A, B, C...
|
|
44
|
+
- Tools used and output summary
|
|
45
|
+
|
|
46
|
+
[Include any new timeline entries from the new messages]
|
|
47
|
+
|
|
48
|
+
# Current status, task and objectives
|
|
49
|
+
|
|
50
|
+
Based on the complete conversation including new messages, update the current status, task and objectives.
|
|
51
|
+
|
|
52
|
+
CRITICAL: This section should reflect the most current state based on all messages including the new ones. This is not about summarizing but about the status, task and objectives currently active in the conversation to keep as much context as possible.
|
|
53
|
+
</OUTPUT_FORMAT>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Summarize the following conversation. Focus on key information and maintain context.
|
|
2
|
+
Provide the output as specified in <OUTPUT_FORMAT>.
|
|
3
|
+
Remove noisy information or irrelevant messages.
|
|
4
|
+
|
|
5
|
+
<OUTPUT_FORMAT>
|
|
6
|
+
# Context
|
|
7
|
+
|
|
8
|
+
Short summary of the discussion, grouped by topics or tasks if any.
|
|
9
|
+
Present it as clear bullet points. Be brief but do not lose information that might be important for the current state, task or objectives.
|
|
10
|
+
|
|
11
|
+
# Key elements, learnings and entities
|
|
12
|
+
|
|
13
|
+
Present the important elements of context, learnings and entities from the discussion. Be very detailed.
|
|
14
|
+
|
|
15
|
+
Present it as clear bullet points. Be brief but do not lose information that might be important for the current state, task or objectives.
|
|
16
|
+
|
|
17
|
+
If the agent obtained information via tools, preserve it verbatim if it was short, summarize it if it was long focusing on preserving all of the most important facts and information.
|
|
18
|
+
|
|
19
|
+
If the agent has acknowledged the user's request, make sure to include the summary of the work done in the output so it doesn't acknowledge the user again.
|
|
20
|
+
|
|
21
|
+
If agent listed files, code or retrieved parts of the code, preserve it verbatim unless it's very long, then summarize it. ALWAYS IN THE CONTEXT OF WHAT THE AGENT NEEDS.
|
|
22
|
+
|
|
23
|
+
Keep user's messages verbatim if they are short to medium length, summarize them if they are long focusing on preserving all of the most important facts and information.
|
|
24
|
+
|
|
25
|
+
If there are any links mentioned, IDs, filenames, etc. - preserve them verbatim.
|
|
26
|
+
|
|
27
|
+
# Timeline
|
|
28
|
+
|
|
29
|
+
For important tasks and content, provide
|
|
30
|
+
- User: asked to handle a complex task X: <summary of the task>
|
|
31
|
+
- Assistant: we handle it by doing A, B, C...
|
|
32
|
+
- Tools used and output summary
|
|
33
|
+
|
|
34
|
+
...
|
|
35
|
+
- User: asked to handle a complex task Y: <summary of the task>
|
|
36
|
+
- Assistant: we handle it by doing A, B, C...
|
|
37
|
+
- Tools used and output summary
|
|
38
|
+
|
|
39
|
+
Do not hesitate to merge original messages, remove noise. We want to be as concise and brief as possible.
|
|
40
|
+
|
|
41
|
+
# Current status, task and objectives
|
|
42
|
+
|
|
43
|
+
Based on the conversation, include here the current status, task and objectives.
|
|
44
|
+
|
|
45
|
+
CRITICAL: This is not about summarizing or compacting. We are talking about the status, task and objectives currently active in the convertion to keep as much context as possible regarding the last messages.
|
|
46
|
+
</OUTPUT_FORMAT>
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Template loader utility for managing Jinja2 prompt templates."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from jinja2 import Environment, FileSystemLoader, Template, select_autoescape
|
|
9
|
+
|
|
10
|
+
from shotgun.logging_config import setup_logger
|
|
11
|
+
|
|
12
|
+
logger = setup_logger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PromptLoader:
|
|
16
|
+
"""Manages loading and rendering of Jinja2 prompt templates."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, templates_dir: str | Path | None = None) -> None:
|
|
19
|
+
"""Initialize the prompt loader.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
templates_dir: Directory containing templates. Defaults to prompts directory.
|
|
23
|
+
"""
|
|
24
|
+
if templates_dir is None:
|
|
25
|
+
templates_dir = Path(__file__).parent
|
|
26
|
+
else:
|
|
27
|
+
templates_dir = Path(templates_dir)
|
|
28
|
+
|
|
29
|
+
if not templates_dir.exists():
|
|
30
|
+
raise ValueError(f"Templates directory does not exist: {templates_dir}")
|
|
31
|
+
|
|
32
|
+
self.templates_dir = templates_dir
|
|
33
|
+
self.env = Environment(
|
|
34
|
+
loader=FileSystemLoader(str(templates_dir)),
|
|
35
|
+
autoescape=select_autoescape(["j2"]),
|
|
36
|
+
trim_blocks=True,
|
|
37
|
+
lstrip_blocks=True,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Add common global functions and variables
|
|
41
|
+
self.env.globals.update(
|
|
42
|
+
{
|
|
43
|
+
"now": datetime.now,
|
|
44
|
+
"timestamp": time.time,
|
|
45
|
+
"current_timestamp": lambda: int(time.time()),
|
|
46
|
+
"timestamp_minus": lambda seconds: int(time.time()) - seconds,
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
logger.debug("Initialized PromptLoader with templates_dir: %s", templates_dir)
|
|
51
|
+
|
|
52
|
+
def load_template(self, template_path: str) -> Template:
|
|
53
|
+
"""Load a template from the templates directory.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
template_path: Path to template relative to templates directory
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Loaded Jinja2 template
|
|
60
|
+
"""
|
|
61
|
+
try:
|
|
62
|
+
template = self.env.get_template(template_path)
|
|
63
|
+
logger.debug("Loaded template: %s", template_path)
|
|
64
|
+
return template
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.error("Failed to load template %s: %s", template_path, str(e))
|
|
67
|
+
raise
|
|
68
|
+
|
|
69
|
+
def render(self, template_path: str, **context: Any) -> str:
|
|
70
|
+
"""Render a template with the given context.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
template_path: Path to template relative to templates directory
|
|
74
|
+
**context: Variables to pass to the template
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Rendered template content
|
|
78
|
+
"""
|
|
79
|
+
template = self.load_template(template_path)
|
|
80
|
+
try:
|
|
81
|
+
result = template.render(**context)
|
|
82
|
+
logger.debug(
|
|
83
|
+
"Rendered template %s with %d context variables",
|
|
84
|
+
template_path,
|
|
85
|
+
len(context),
|
|
86
|
+
)
|
|
87
|
+
return result
|
|
88
|
+
except Exception as e:
|
|
89
|
+
logger.error("Failed to render template %s: %s", template_path, str(e))
|
|
90
|
+
raise
|
|
91
|
+
|
|
92
|
+
def render_string(self, template_string: str, **context: Any) -> str:
|
|
93
|
+
"""Render a template from a string.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
template_string: Template content as string
|
|
97
|
+
**context: Variables to pass to the template
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Rendered template content
|
|
101
|
+
"""
|
|
102
|
+
try:
|
|
103
|
+
template = self.env.from_string(template_string)
|
|
104
|
+
result = template.render(**context)
|
|
105
|
+
logger.debug(
|
|
106
|
+
"Rendered string template with %d context variables", len(context)
|
|
107
|
+
)
|
|
108
|
+
return result
|
|
109
|
+
except Exception as e:
|
|
110
|
+
logger.error("Failed to render string template: %s", str(e))
|
|
111
|
+
raise
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# Global instance for the default templates directory
|
|
115
|
+
_default_loader: PromptLoader | None = None
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def get_prompt_loader() -> PromptLoader:
|
|
119
|
+
"""Get the default prompt loader instance.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Default PromptLoader instance
|
|
123
|
+
"""
|
|
124
|
+
global _default_loader
|
|
125
|
+
if _default_loader is None:
|
|
126
|
+
_default_loader = PromptLoader()
|
|
127
|
+
return _default_loader
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def render_prompt(template_path: str, **context: Any) -> str:
|
|
131
|
+
"""Convenience function to render a template using the default loader.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
template_path: Path to template relative to templates directory
|
|
135
|
+
**context: Variables to pass to the template
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Rendered template content
|
|
139
|
+
"""
|
|
140
|
+
return get_prompt_loader().render(template_path, **context)
|
shotgun/py.typed
ADDED
|
File without changes
|
shotgun/sdk/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Shotgun SDK - Framework-agnostic business logic for CLI and TUI."""
|
|
2
|
+
|
|
3
|
+
from .codebase import CodebaseSDK
|
|
4
|
+
from .exceptions import CodebaseNotFoundError, CodebaseOperationError, ShotgunSDKError
|
|
5
|
+
from .services import get_codebase_service
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"CodebaseSDK",
|
|
9
|
+
"ShotgunSDKError",
|
|
10
|
+
"CodebaseNotFoundError",
|
|
11
|
+
"CodebaseOperationError",
|
|
12
|
+
"get_codebase_service",
|
|
13
|
+
]
|