shotgun-sh 0.1.0.dev1__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 +3 -0
- shotgun/agents/__init__.py +1 -0
- shotgun/agents/agent_manager.py +196 -0
- shotgun/agents/common.py +295 -0
- shotgun/agents/config/__init__.py +13 -0
- shotgun/agents/config/manager.py +215 -0
- shotgun/agents/config/models.py +120 -0
- shotgun/agents/config/provider.py +91 -0
- shotgun/agents/history/__init__.py +5 -0
- shotgun/agents/history/history_processors.py +213 -0
- shotgun/agents/models.py +94 -0
- shotgun/agents/plan.py +119 -0
- shotgun/agents/research.py +131 -0
- shotgun/agents/tasks.py +122 -0
- shotgun/agents/tools/__init__.py +26 -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 +130 -0
- shotgun/agents/tools/user_interaction.py +36 -0
- shotgun/agents/tools/web_search.py +69 -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 +261 -0
- shotgun/cli/models.py +10 -0
- shotgun/cli/plan.py +65 -0
- shotgun/cli/research.py +78 -0
- shotgun/cli/tasks.py +71 -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 +1554 -0
- shotgun/codebase/core/nl_query.py +327 -0
- shotgun/codebase/core/parser_loader.py +152 -0
- shotgun/codebase/models.py +107 -0
- shotgun/codebase/service.py +148 -0
- shotgun/logging_config.py +172 -0
- shotgun/main.py +73 -0
- shotgun/prompts/__init__.py +5 -0
- shotgun/prompts/agents/__init__.py +1 -0
- shotgun/prompts/agents/partials/codebase_understanding.j2 +79 -0
- shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +10 -0
- shotgun/prompts/agents/partials/interactive_mode.j2 +8 -0
- shotgun/prompts/agents/plan.j2 +57 -0
- shotgun/prompts/agents/research.j2 +38 -0
- shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +13 -0
- shotgun/prompts/agents/state/system_state.j2 +1 -0
- shotgun/prompts/agents/tasks.j2 +67 -0
- shotgun/prompts/codebase/__init__.py +1 -0
- shotgun/prompts/codebase/cypher_query_patterns.j2 +221 -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 +28 -0
- shotgun/prompts/codebase/partials/temporal_context.j2 +21 -0
- shotgun/prompts/history/__init__.py +1 -0
- shotgun/prompts/history/summarization.j2 +46 -0
- shotgun/prompts/loader.py +140 -0
- shotgun/prompts/user/research.j2 +5 -0
- shotgun/py.typed +0 -0
- shotgun/sdk/__init__.py +13 -0
- shotgun/sdk/codebase.py +195 -0
- shotgun/sdk/exceptions.py +17 -0
- shotgun/sdk/models.py +189 -0
- shotgun/sdk/services.py +23 -0
- shotgun/telemetry.py +68 -0
- shotgun/tui/__init__.py +0 -0
- shotgun/tui/app.py +49 -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 +28 -0
- shotgun/tui/screens/chat.py +415 -0
- shotgun/tui/screens/chat.tcss +28 -0
- shotgun/tui/screens/provider_config.py +221 -0
- shotgun/tui/screens/splash.py +31 -0
- shotgun/tui/styles.tcss +10 -0
- shotgun/utils/__init__.py +5 -0
- shotgun/utils/file_system_utils.py +31 -0
- shotgun_sh-0.1.0.dev1.dist-info/METADATA +318 -0
- shotgun_sh-0.1.0.dev1.dist-info/RECORD +94 -0
- shotgun_sh-0.1.0.dev1.dist-info/WHEEL +4 -0
- shotgun_sh-0.1.0.dev1.dist-info/entry_points.txt +3 -0
- shotgun_sh-0.1.0.dev1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
You are a task management assistant with access to research data and project plans.
|
|
2
|
+
{% include 'agents/partials/common_agent_system_prompt.j2' %}
|
|
3
|
+
|
|
4
|
+
Your job is to:
|
|
5
|
+
1. FIRST: Load previous research from research.md using read_file("research.md") if available
|
|
6
|
+
2. SECOND: Load existing plan from plan.md using read_file("plan.md") if available
|
|
7
|
+
3. THIRD: Load existing tasks from tasks.md using read_file("tasks.md") if it exists
|
|
8
|
+
4. ANALYZE: Understand current context and the user's task creation/update request
|
|
9
|
+
5. CREATE/UPDATE: Generate or modify actionable tasks based on research and plans
|
|
10
|
+
6. WRITE: Save the updated tasks to tasks.md using write_file("tasks.md", content)
|
|
11
|
+
|
|
12
|
+
TASK CREATION PRINCIPLES:
|
|
13
|
+
- Base tasks on available research findings and plan requirements
|
|
14
|
+
- Create specific, actionable tasks with clear acceptance criteria
|
|
15
|
+
- Include effort estimates and priority levels
|
|
16
|
+
- Organize tasks by categories or project phases
|
|
17
|
+
- Consider dependencies between tasks
|
|
18
|
+
- Make tasks testable and verifiable
|
|
19
|
+
- Align with goals and steps from the plan
|
|
20
|
+
- Include both development and testing/validation tasks
|
|
21
|
+
|
|
22
|
+
{% if interactive_mode %}
|
|
23
|
+
USER INTERACTION - ASK CLARIFYING QUESTIONS:
|
|
24
|
+
|
|
25
|
+
- ALWAYS ask clarifying questions when the request is vague or ambiguous
|
|
26
|
+
- Use ask_user tool to gather specific details about:
|
|
27
|
+
- Specific features or functionality to prioritize
|
|
28
|
+
- Technical constraints or preferences
|
|
29
|
+
- Timeline and resource constraints
|
|
30
|
+
- Definition of "done" for key deliverables
|
|
31
|
+
- Testing and quality requirements
|
|
32
|
+
- Team size and skill levels
|
|
33
|
+
- Integration requirements
|
|
34
|
+
- Ask follow-up questions to ensure tasks are properly scoped
|
|
35
|
+
- Confirm task priorities and dependencies with the user
|
|
36
|
+
- Better to ask 2-3 targeted questions than create generic tasks
|
|
37
|
+
{% else %}
|
|
38
|
+
NON-INTERACTIVE MODE - MAKE REASONABLE ASSUMPTIONS:
|
|
39
|
+
|
|
40
|
+
- Make reasonable assumptions based on industry best practices
|
|
41
|
+
- Use sensible defaults for technical constraints and timelines
|
|
42
|
+
- Create tasks with standard definitions of "done"
|
|
43
|
+
- Assume typical team sizes and skill levels
|
|
44
|
+
- Include common testing and quality assurance tasks
|
|
45
|
+
- Create tasks that follow standard project management practices
|
|
46
|
+
{% endif %}
|
|
47
|
+
|
|
48
|
+
INTEGRATION WITH RESEARCH & PLAN:
|
|
49
|
+
- Reference specific findings from research.md when creating tasks
|
|
50
|
+
- Align tasks with action steps outlined in plan.md
|
|
51
|
+
- Consider technical feasibility based on research
|
|
52
|
+
- Include tasks for addressing challenges identified in plan
|
|
53
|
+
- Create validation/testing tasks for success criteria from plan
|
|
54
|
+
- Break down high-level plan steps into granular, executable tasks
|
|
55
|
+
|
|
56
|
+
IMPORTANT RULES:
|
|
57
|
+
- Make at most 1 tasks file write per request
|
|
58
|
+
- Always base tasks on available research and plan when relevant
|
|
59
|
+
- Create specific, testable tasks rather than vague objectives
|
|
60
|
+
- Consider realistic timelines and team capabilities
|
|
61
|
+
- Include both implementation and validation/testing tasks
|
|
62
|
+
{% if interactive_mode %}
|
|
63
|
+
- When in doubt about any aspect of the requirements, ASK before proceeding
|
|
64
|
+
{% else %}
|
|
65
|
+
- When in doubt, make reasonable assumptions and proceed with best practices
|
|
66
|
+
{% endif %}
|
|
67
|
+
- Ensure tasks are properly prioritized and sequenced
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Codebase analysis prompt templates."""
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
**Pattern: Finding All Classes**
|
|
2
|
+
```cypher
|
|
3
|
+
// "Find all Python classes" or "list all classes" or "show me all classes"
|
|
4
|
+
MATCH (c:Class)
|
|
5
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
|
|
6
|
+
ORDER BY c.name
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
**Pattern: Finding Classes with Path Information**
|
|
10
|
+
```cypher
|
|
11
|
+
// "Find Python classes with their file paths" or "show classes and where they are defined"
|
|
12
|
+
MATCH (m:Module)-[:DEFINES]->(c:Class)
|
|
13
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, m.path AS module_path, 'Class' AS type
|
|
14
|
+
ORDER BY m.path, c.name
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Pattern: Finding Decorated Functions/Methods (e.g., Workflows, Tasks)**
|
|
18
|
+
```cypher
|
|
19
|
+
// "Find all prefect flows" or "what are the workflows?" or "show me the tasks"
|
|
20
|
+
// Use separate MATCH clauses since Kuzu doesn't support union types
|
|
21
|
+
MATCH (n:Function)
|
|
22
|
+
WHERE ANY(d IN n.decorators WHERE toLower(d) IN ['flow', 'task'])
|
|
23
|
+
RETURN n.name AS name, n.qualified_name AS qualified_name, 'Function' AS type
|
|
24
|
+
UNION ALL
|
|
25
|
+
MATCH (n:Method)
|
|
26
|
+
WHERE ANY(d IN n.decorators WHERE toLower(d) IN ['flow', 'task'])
|
|
27
|
+
RETURN n.name AS name, n.qualified_name AS qualified_name, 'Method' AS type
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Pattern: Finding Content by Path (Using UNION ALL for Different Types)**
|
|
31
|
+
```cypher
|
|
32
|
+
// "what is in the 'workflows/src' directory?" or "list files in workflows"
|
|
33
|
+
// Use separate queries with UNION ALL to handle different node types
|
|
34
|
+
MATCH (n:Module)
|
|
35
|
+
WHERE n.path STARTS WITH 'workflows'
|
|
36
|
+
RETURN n.name AS name, n.path AS path, 'Module' AS type
|
|
37
|
+
UNION ALL
|
|
38
|
+
MATCH (n:File)
|
|
39
|
+
WHERE n.path STARTS WITH 'workflows'
|
|
40
|
+
RETURN n.name AS name, n.path AS path, 'File' AS type
|
|
41
|
+
UNION ALL
|
|
42
|
+
MATCH (n:Folder)
|
|
43
|
+
WHERE n.path STARTS WITH 'workflows'
|
|
44
|
+
RETURN n.name AS name, n.path AS path, 'Folder' AS type
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Pattern: Keyword & Concept Search (Fallback for general terms)**
|
|
48
|
+
```cypher
|
|
49
|
+
// "find things related to 'database'"
|
|
50
|
+
MATCH (n)
|
|
51
|
+
WHERE toLower(n.name) CONTAINS 'database' OR (n.qualified_name IS NOT NULL AND toLower(n.qualified_name) CONTAINS 'database')
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Pattern: Time-based Queries (IMPORTANT: Use actual timestamps from user query)**
|
|
55
|
+
```cypher
|
|
56
|
+
// "What functions were added in the last 2 minutes?" when current timestamp is provided
|
|
57
|
+
MATCH (f:Function)
|
|
58
|
+
WHERE f.created_at > [current_timestamp - 120] // This is current_timestamp - 120
|
|
59
|
+
RETURN f.name AS name, f.qualified_name AS qualified_name, f.created_at AS created_timestamp
|
|
60
|
+
ORDER BY f.created_at DESC
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```cypher
|
|
64
|
+
// "What classes were modified today?" when current timestamp is provided
|
|
65
|
+
MATCH (c:Class)
|
|
66
|
+
WHERE c.updated_at >= [today's start timestamp] // This is today's start
|
|
67
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, c.updated_at AS updated_timestamp
|
|
68
|
+
ORDER BY c.updated_at DESC
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Pattern: Finding Files by Extension**
|
|
72
|
+
```cypher
|
|
73
|
+
// "Find all TypeScript files" or "show me .ts files"
|
|
74
|
+
// IMPORTANT: File extensions are stored WITH the dot (e.g., ".ts" not "ts")
|
|
75
|
+
MATCH (f:File)
|
|
76
|
+
WHERE f.extension = '.ts'
|
|
77
|
+
RETURN f.path AS path, f.name AS name, f.extension AS extension, 'File' AS type
|
|
78
|
+
ORDER BY f.path
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```cypher
|
|
82
|
+
// "Find JavaScript and TypeScript files"
|
|
83
|
+
MATCH (f:File)
|
|
84
|
+
WHERE f.extension IN ['.js', '.ts', '.jsx', '.tsx']
|
|
85
|
+
RETURN f.path AS path, f.name AS name, f.extension AS extension, 'File' AS type
|
|
86
|
+
ORDER BY f.path
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Pattern: Finding a Specific File**
|
|
90
|
+
```cypher
|
|
91
|
+
// "Find the main README.md"
|
|
92
|
+
MATCH (f:File) WHERE toLower(f.name) = 'readme.md' AND f.path = 'README.md'
|
|
93
|
+
RETURN f.path as path, f.name as name, 'File' as type
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Pattern: Finding Classes in a Specific Directory**
|
|
97
|
+
```cypher
|
|
98
|
+
// "Find classes in the server directory"
|
|
99
|
+
MATCH (m:Module)-[:DEFINES]->(c:Class)
|
|
100
|
+
WHERE m.path STARTS WITH 'server/'
|
|
101
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Pattern: Finding Modules with Most Classes**
|
|
105
|
+
```cypher
|
|
106
|
+
// "Find modules that define the most classes"
|
|
107
|
+
MATCH (m:Module)-[:DEFINES]->(c:Class)
|
|
108
|
+
WITH m, count(c) AS class_count
|
|
109
|
+
ORDER BY class_count DESC
|
|
110
|
+
LIMIT 10
|
|
111
|
+
RETURN m.name AS name, m.qualified_name AS qualified_name, m.path AS path, class_count
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Pattern: Finding Classes with Method Counts**
|
|
115
|
+
```cypher
|
|
116
|
+
// "Find classes with more than N methods" or "Show me classes that have at least X methods"
|
|
117
|
+
MATCH (c:Class)-[:DEFINES_METHOD]->(m:Method)
|
|
118
|
+
WITH c, count(m) AS method_count
|
|
119
|
+
WHERE method_count > 10 // Replace 10 with the actual number from query
|
|
120
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, method_count
|
|
121
|
+
ORDER BY method_count DESC
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Pattern: Finding Classes with Inheritance (Note: INHERITS relationships must exist)**
|
|
125
|
+
```cypher
|
|
126
|
+
// "Find classes with children/subclasses"
|
|
127
|
+
// This will return NO results if no inheritance relationships exist in the graph
|
|
128
|
+
MATCH (child:Class)-[:INHERITS]->(parent:Class)
|
|
129
|
+
WITH parent, count(child) AS child_count
|
|
130
|
+
ORDER BY child_count DESC
|
|
131
|
+
LIMIT 10
|
|
132
|
+
RETURN parent.name AS name, parent.qualified_name AS qualified_name, child_count
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Pattern: Finding Parent Classes of a Specific Class**
|
|
136
|
+
```cypher
|
|
137
|
+
// "What are the parent classes of DeputyAgent?" or "What does DeputyAgent inherit from?"
|
|
138
|
+
// Use name for short class names (when user doesn't provide full path)
|
|
139
|
+
MATCH (child:Class)-[:INHERITS]->(parent:Class)
|
|
140
|
+
WHERE toLower(child.name) = 'deputyagent'
|
|
141
|
+
RETURN parent.name AS name, parent.qualified_name AS qualified_name
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Pattern: Finding Methods of a Specific Class**
|
|
145
|
+
```cypher
|
|
146
|
+
// "What methods does WebSocketServer have?" or "List methods in WebSocketServer class"
|
|
147
|
+
// When user provides just the class name without full path
|
|
148
|
+
MATCH (c:Class)-[:DEFINES_METHOD]->(m:Method)
|
|
149
|
+
WHERE c.name = 'WebSocketServer'
|
|
150
|
+
RETURN m.name AS name, m.qualified_name AS qualified_name, 'Method' AS type
|
|
151
|
+
ORDER BY m.name
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Pattern: Finding a Specific Entity by Full Qualified Name**
|
|
155
|
+
```cypher
|
|
156
|
+
// "Find shotgun.server.WebSocketServer" or "Show me api.websocket.server.WebSocketServer"
|
|
157
|
+
// When user provides a dotted path, match against qualified_name
|
|
158
|
+
MATCH (c:Class)
|
|
159
|
+
WHERE c.qualified_name = 'shotgun2.server.src.shotgun.api.websocket.server.WebSocketServer'
|
|
160
|
+
RETURN c.name AS name, c.qualified_name AS qualified_name, 'Class' AS type
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Pattern: Finding Recently Added/Modified Code**
|
|
164
|
+
```cypher
|
|
165
|
+
// "Find functions added in the last 24 hours" or "What new functions were added today?"
|
|
166
|
+
// Note: In Kuzu, use Unix timestamps directly (seconds since epoch)
|
|
167
|
+
// Example: 1704067200 represents 2024-01-01 00:00:00 UTC
|
|
168
|
+
// For "today": use timestamp from start of current day
|
|
169
|
+
// For "last 24 hours": use current_timestamp - 86400
|
|
170
|
+
MATCH (f:Function)
|
|
171
|
+
WHERE f.created_at > [current_timestamp - 86400] // Replace with actual timestamp for "24 hours ago"
|
|
172
|
+
RETURN f.name AS name, f.qualified_name AS qualified_name, f.created_at AS created_timestamp
|
|
173
|
+
ORDER BY f.created_at DESC
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Pattern: Finding Files Modified Recently**
|
|
177
|
+
```cypher
|
|
178
|
+
// "Find files modified today" or "Which files changed in the last hour?"
|
|
179
|
+
// For "last hour": use current_timestamp - 3600
|
|
180
|
+
// For "today": use timestamp from start of current day
|
|
181
|
+
MATCH (fm:FileMetadata)
|
|
182
|
+
WHERE fm.mtime > [current_timestamp - 3600] // Replace with actual timestamp
|
|
183
|
+
RETURN fm.filepath AS path, fm.mtime AS last_modified
|
|
184
|
+
ORDER BY fm.mtime DESC
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Pattern: Queries About Deleted/Removed Entities**
|
|
188
|
+
```cypher
|
|
189
|
+
// "What functions were deleted/removed?" or "Show me classes that no longer exist"
|
|
190
|
+
// Query the DeletionLog table for tracking removed entities
|
|
191
|
+
MATCH (d:DeletionLog)
|
|
192
|
+
WHERE d.entity_type = 'Function' AND d.deleted_at > [current_timestamp - 86400] // Replace with timestamp for time range
|
|
193
|
+
RETURN d.entity_qualified_name AS name, d.deleted_from_file AS file, d.deleted_at AS deleted_at, d.deletion_reason AS reason
|
|
194
|
+
ORDER BY d.deleted_at DESC
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Pattern: Finding Where a Method/Function is Called**
|
|
198
|
+
```cypher
|
|
199
|
+
// "where is WebSocketServer.start called?" or "find callers of method X"
|
|
200
|
+
// For partial names like 'WebSocketServer.start', use ENDS WITH pattern
|
|
201
|
+
MATCH (caller:Method)-[:CALLS]->(target:Method)
|
|
202
|
+
WHERE target.qualified_name ENDS WITH '.WebSocketServer.start'
|
|
203
|
+
RETURN caller.name AS name, caller.qualified_name AS qualified_name, 'Method' AS caller_type
|
|
204
|
+
UNION ALL
|
|
205
|
+
MATCH (caller:Function)-[:CALLS]->(target:Method)
|
|
206
|
+
WHERE target.qualified_name ENDS WITH '.WebSocketServer.start'
|
|
207
|
+
RETURN caller.name AS name, caller.qualified_name AS qualified_name, 'Function' AS caller_type
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Pattern: Finding What a Method/Function Calls**
|
|
211
|
+
```cypher
|
|
212
|
+
// "what does WebSocketServer.start call?" or "what methods does X invoke?"
|
|
213
|
+
// Use ENDS WITH for partial names, UNION ALL to handle different target types
|
|
214
|
+
MATCH (source:Method)-[:CALLS]->(target:Method)
|
|
215
|
+
WHERE source.qualified_name ENDS WITH '.WebSocketServer.start'
|
|
216
|
+
RETURN target.name AS name, target.qualified_name AS qualified_name, 'Method' AS target_type
|
|
217
|
+
UNION ALL
|
|
218
|
+
MATCH (source:Method)-[:CALLS]->(target:Function)
|
|
219
|
+
WHERE source.qualified_name ENDS WITH '.WebSocketServer.start'
|
|
220
|
+
RETURN target.name AS name, target.qualified_name AS qualified_name, 'Function' AS target_type
|
|
221
|
+
```
|
|
@@ -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,28 @@
|
|
|
1
|
+
**1. Graph Schema Definition**
|
|
2
|
+
The database contains information about a codebase, structured with the following nodes and relationships.
|
|
3
|
+
|
|
4
|
+
Node Labels and Their Key Properties:
|
|
5
|
+
- Project: {name: string}
|
|
6
|
+
- Package: {qualified_name: string, name: string, path: string}
|
|
7
|
+
- Folder: {path: string, name: string}
|
|
8
|
+
- File: {path: string, name: string, extension: string} // Note: extension includes the dot (e.g., ".ts", ".py", ".js")
|
|
9
|
+
- FileMetadata: {filepath: string, mtime: int64, hash: string, last_updated: int64}
|
|
10
|
+
- Module: {qualified_name: string, name: string, path: string, created_at: int64, updated_at: int64}
|
|
11
|
+
- Class: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
|
|
12
|
+
- Function: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
|
|
13
|
+
- Method: {qualified_name: string, name: string, decorators: list[string], line_start: int, line_end: int, created_at: int64, updated_at: int64}
|
|
14
|
+
- ExternalPackage: {name: string, version_spec: string}
|
|
15
|
+
- DeletionLog: {id: string, entity_type: string, entity_qualified_name: string, deleted_from_file: string, deleted_at: int64, deletion_reason: string}
|
|
16
|
+
|
|
17
|
+
Relationships (source)-[REL_TYPE]->(target):
|
|
18
|
+
- (Project|Package|Folder) -[:CONTAINS_PACKAGE|CONTAINS_FOLDER|CONTAINS_FILE|CONTAINS_MODULE]-> (various)
|
|
19
|
+
- Module -[:DEFINES]-> (Class|Function)
|
|
20
|
+
- Class -[:DEFINES_METHOD]-> Method
|
|
21
|
+
- (Child Class) -[:INHERITS]-> (Parent Class)
|
|
22
|
+
- Method -[:OVERRIDES]-> Method
|
|
23
|
+
- Project -[:DEPENDS_ON_EXTERNAL]-> ExternalPackage
|
|
24
|
+
- (Function|Method) -[:CALLS]-> (Function|Method)
|
|
25
|
+
- FileMetadata -[:TRACKS_Module]-> Module
|
|
26
|
+
- FileMetadata -[:TRACKS_Class]-> Class
|
|
27
|
+
- FileMetadata -[:TRACKS_Function]-> Function
|
|
28
|
+
- 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,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
|
+
]
|