nc1709 1.15.4__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.
- nc1709/__init__.py +13 -0
- nc1709/agent/__init__.py +36 -0
- nc1709/agent/core.py +505 -0
- nc1709/agent/mcp_bridge.py +245 -0
- nc1709/agent/permissions.py +298 -0
- nc1709/agent/tools/__init__.py +21 -0
- nc1709/agent/tools/base.py +440 -0
- nc1709/agent/tools/bash_tool.py +367 -0
- nc1709/agent/tools/file_tools.py +454 -0
- nc1709/agent/tools/notebook_tools.py +516 -0
- nc1709/agent/tools/search_tools.py +322 -0
- nc1709/agent/tools/task_tool.py +284 -0
- nc1709/agent/tools/web_tools.py +555 -0
- nc1709/agents/__init__.py +17 -0
- nc1709/agents/auto_fix.py +506 -0
- nc1709/agents/test_generator.py +507 -0
- nc1709/checkpoints.py +372 -0
- nc1709/cli.py +3380 -0
- nc1709/cli_ui.py +1080 -0
- nc1709/cognitive/__init__.py +149 -0
- nc1709/cognitive/anticipation.py +594 -0
- nc1709/cognitive/context_engine.py +1046 -0
- nc1709/cognitive/council.py +824 -0
- nc1709/cognitive/learning.py +761 -0
- nc1709/cognitive/router.py +583 -0
- nc1709/cognitive/system.py +519 -0
- nc1709/config.py +155 -0
- nc1709/custom_commands.py +300 -0
- nc1709/executor.py +333 -0
- nc1709/file_controller.py +354 -0
- nc1709/git_integration.py +308 -0
- nc1709/github_integration.py +477 -0
- nc1709/image_input.py +446 -0
- nc1709/linting.py +519 -0
- nc1709/llm_adapter.py +667 -0
- nc1709/logger.py +192 -0
- nc1709/mcp/__init__.py +18 -0
- nc1709/mcp/client.py +370 -0
- nc1709/mcp/manager.py +407 -0
- nc1709/mcp/protocol.py +210 -0
- nc1709/mcp/server.py +473 -0
- nc1709/memory/__init__.py +20 -0
- nc1709/memory/embeddings.py +325 -0
- nc1709/memory/indexer.py +474 -0
- nc1709/memory/sessions.py +432 -0
- nc1709/memory/vector_store.py +451 -0
- nc1709/models/__init__.py +86 -0
- nc1709/models/detector.py +377 -0
- nc1709/models/formats.py +315 -0
- nc1709/models/manager.py +438 -0
- nc1709/models/registry.py +497 -0
- nc1709/performance/__init__.py +343 -0
- nc1709/performance/cache.py +705 -0
- nc1709/performance/pipeline.py +611 -0
- nc1709/performance/tiering.py +543 -0
- nc1709/plan_mode.py +362 -0
- nc1709/plugins/__init__.py +17 -0
- nc1709/plugins/agents/__init__.py +18 -0
- nc1709/plugins/agents/django_agent.py +912 -0
- nc1709/plugins/agents/docker_agent.py +623 -0
- nc1709/plugins/agents/fastapi_agent.py +887 -0
- nc1709/plugins/agents/git_agent.py +731 -0
- nc1709/plugins/agents/nextjs_agent.py +867 -0
- nc1709/plugins/base.py +359 -0
- nc1709/plugins/manager.py +411 -0
- nc1709/plugins/registry.py +337 -0
- nc1709/progress.py +443 -0
- nc1709/prompts/__init__.py +22 -0
- nc1709/prompts/agent_system.py +180 -0
- nc1709/prompts/task_prompts.py +340 -0
- nc1709/prompts/unified_prompt.py +133 -0
- nc1709/reasoning_engine.py +541 -0
- nc1709/remote_client.py +266 -0
- nc1709/shell_completions.py +349 -0
- nc1709/slash_commands.py +649 -0
- nc1709/task_classifier.py +408 -0
- nc1709/version_check.py +177 -0
- nc1709/web/__init__.py +8 -0
- nc1709/web/server.py +950 -0
- nc1709/web/templates/index.html +1127 -0
- nc1709-1.15.4.dist-info/METADATA +858 -0
- nc1709-1.15.4.dist-info/RECORD +86 -0
- nc1709-1.15.4.dist-info/WHEEL +5 -0
- nc1709-1.15.4.dist-info/entry_points.txt +2 -0
- nc1709-1.15.4.dist-info/licenses/LICENSE +9 -0
- nc1709-1.15.4.dist-info/top_level.txt +1 -0
nc1709/progress.py
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Progress Indicators
|
|
3
|
+
Rich progress bars and status displays for long-running operations
|
|
4
|
+
"""
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
import threading
|
|
8
|
+
from typing import Optional, Callable, List, Any
|
|
9
|
+
from enum import Enum
|
|
10
|
+
from contextlib import contextmanager
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SpinnerStyle(Enum):
|
|
14
|
+
"""Available spinner styles"""
|
|
15
|
+
DOTS = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
|
16
|
+
BRAILLE = ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"]
|
|
17
|
+
ARROWS = ["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"]
|
|
18
|
+
CLOCK = ["🕐", "🕑", "🕒", "🕓", "🕔", "🕕", "🕖", "🕗", "🕘", "🕙", "🕚", "🕛"]
|
|
19
|
+
MOON = ["🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"]
|
|
20
|
+
BOUNCE = ["⠁", "⠂", "⠄", "⠂"]
|
|
21
|
+
SIMPLE = ["-", "\\", "|", "/"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ProgressBar:
|
|
25
|
+
"""Simple progress bar for terminal output"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
total: int,
|
|
30
|
+
description: str = "",
|
|
31
|
+
width: int = 40,
|
|
32
|
+
fill_char: str = "█",
|
|
33
|
+
empty_char: str = "░"
|
|
34
|
+
):
|
|
35
|
+
"""Initialize progress bar
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
total: Total number of steps
|
|
39
|
+
description: Description text
|
|
40
|
+
width: Width of progress bar in characters
|
|
41
|
+
fill_char: Character for filled portion
|
|
42
|
+
empty_char: Character for empty portion
|
|
43
|
+
"""
|
|
44
|
+
self.total = total
|
|
45
|
+
self.description = description
|
|
46
|
+
self.width = width
|
|
47
|
+
self.fill_char = fill_char
|
|
48
|
+
self.empty_char = empty_char
|
|
49
|
+
self.current = 0
|
|
50
|
+
self.start_time = time.time()
|
|
51
|
+
|
|
52
|
+
def update(self, amount: int = 1) -> None:
|
|
53
|
+
"""Update progress
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
amount: Amount to increment
|
|
57
|
+
"""
|
|
58
|
+
self.current = min(self.current + amount, self.total)
|
|
59
|
+
self._render()
|
|
60
|
+
|
|
61
|
+
def set(self, value: int) -> None:
|
|
62
|
+
"""Set progress to specific value
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
value: New progress value
|
|
66
|
+
"""
|
|
67
|
+
self.current = min(value, self.total)
|
|
68
|
+
self._render()
|
|
69
|
+
|
|
70
|
+
def _render(self) -> None:
|
|
71
|
+
"""Render progress bar to terminal"""
|
|
72
|
+
percentage = self.current / self.total if self.total > 0 else 0
|
|
73
|
+
filled_width = int(self.width * percentage)
|
|
74
|
+
empty_width = self.width - filled_width
|
|
75
|
+
|
|
76
|
+
bar = self.fill_char * filled_width + self.empty_char * empty_width
|
|
77
|
+
|
|
78
|
+
# Calculate elapsed time and ETA
|
|
79
|
+
elapsed = time.time() - self.start_time
|
|
80
|
+
if percentage > 0:
|
|
81
|
+
eta = elapsed / percentage - elapsed
|
|
82
|
+
eta_str = f" ETA: {self._format_time(eta)}"
|
|
83
|
+
else:
|
|
84
|
+
eta_str = ""
|
|
85
|
+
|
|
86
|
+
# Build progress line
|
|
87
|
+
desc = f"{self.description}: " if self.description else ""
|
|
88
|
+
line = f"\r{desc}[{bar}] {self.current}/{self.total} ({percentage*100:.1f}%){eta_str}"
|
|
89
|
+
|
|
90
|
+
sys.stdout.write(line)
|
|
91
|
+
sys.stdout.flush()
|
|
92
|
+
|
|
93
|
+
if self.current >= self.total:
|
|
94
|
+
print() # New line when complete
|
|
95
|
+
|
|
96
|
+
def _format_time(self, seconds: float) -> str:
|
|
97
|
+
"""Format seconds as human-readable time"""
|
|
98
|
+
if seconds < 60:
|
|
99
|
+
return f"{seconds:.0f}s"
|
|
100
|
+
elif seconds < 3600:
|
|
101
|
+
return f"{seconds/60:.1f}m"
|
|
102
|
+
else:
|
|
103
|
+
return f"{seconds/3600:.1f}h"
|
|
104
|
+
|
|
105
|
+
def finish(self) -> None:
|
|
106
|
+
"""Mark progress as complete"""
|
|
107
|
+
self.set(self.total)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class Spinner:
|
|
111
|
+
"""Animated spinner for indeterminate progress"""
|
|
112
|
+
|
|
113
|
+
def __init__(
|
|
114
|
+
self,
|
|
115
|
+
message: str = "Processing",
|
|
116
|
+
style: SpinnerStyle = SpinnerStyle.DOTS
|
|
117
|
+
):
|
|
118
|
+
"""Initialize spinner
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
message: Message to display with spinner
|
|
122
|
+
style: Spinner animation style
|
|
123
|
+
"""
|
|
124
|
+
self.message = message
|
|
125
|
+
self.frames = style.value
|
|
126
|
+
self.frame_index = 0
|
|
127
|
+
self.running = False
|
|
128
|
+
self._thread: Optional[threading.Thread] = None
|
|
129
|
+
self._lock = threading.Lock()
|
|
130
|
+
|
|
131
|
+
def start(self) -> "Spinner":
|
|
132
|
+
"""Start spinner animation"""
|
|
133
|
+
self.running = True
|
|
134
|
+
self._thread = threading.Thread(target=self._animate, daemon=True)
|
|
135
|
+
self._thread.start()
|
|
136
|
+
return self
|
|
137
|
+
|
|
138
|
+
def stop(self, final_message: Optional[str] = None) -> None:
|
|
139
|
+
"""Stop spinner animation
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
final_message: Optional message to display after stopping
|
|
143
|
+
"""
|
|
144
|
+
self.running = False
|
|
145
|
+
if self._thread:
|
|
146
|
+
self._thread.join(timeout=0.5)
|
|
147
|
+
|
|
148
|
+
# Clear spinner line
|
|
149
|
+
sys.stdout.write("\r" + " " * (len(self.message) + 10) + "\r")
|
|
150
|
+
sys.stdout.flush()
|
|
151
|
+
|
|
152
|
+
if final_message:
|
|
153
|
+
print(final_message)
|
|
154
|
+
|
|
155
|
+
def _animate(self) -> None:
|
|
156
|
+
"""Animation loop"""
|
|
157
|
+
while self.running:
|
|
158
|
+
with self._lock:
|
|
159
|
+
frame = self.frames[self.frame_index]
|
|
160
|
+
sys.stdout.write(f"\r{frame} {self.message}")
|
|
161
|
+
sys.stdout.flush()
|
|
162
|
+
self.frame_index = (self.frame_index + 1) % len(self.frames)
|
|
163
|
+
time.sleep(0.1)
|
|
164
|
+
|
|
165
|
+
def update_message(self, message: str) -> None:
|
|
166
|
+
"""Update spinner message
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
message: New message
|
|
170
|
+
"""
|
|
171
|
+
with self._lock:
|
|
172
|
+
# Clear old message
|
|
173
|
+
old_len = len(self.message) + 10
|
|
174
|
+
sys.stdout.write("\r" + " " * old_len + "\r")
|
|
175
|
+
self.message = message
|
|
176
|
+
|
|
177
|
+
def __enter__(self) -> "Spinner":
|
|
178
|
+
return self.start()
|
|
179
|
+
|
|
180
|
+
def __exit__(self, *args) -> None:
|
|
181
|
+
self.stop()
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class StatusLine:
|
|
185
|
+
"""Status line that updates in place"""
|
|
186
|
+
|
|
187
|
+
def __init__(self):
|
|
188
|
+
"""Initialize status line"""
|
|
189
|
+
self.current_line = ""
|
|
190
|
+
|
|
191
|
+
def update(self, message: str, prefix: str = "→") -> None:
|
|
192
|
+
"""Update status line
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
message: Status message
|
|
196
|
+
prefix: Prefix character/emoji
|
|
197
|
+
"""
|
|
198
|
+
# Clear old line
|
|
199
|
+
clear_len = len(self.current_line) + 5
|
|
200
|
+
sys.stdout.write("\r" + " " * clear_len + "\r")
|
|
201
|
+
|
|
202
|
+
# Write new line
|
|
203
|
+
self.current_line = f"{prefix} {message}"
|
|
204
|
+
sys.stdout.write(self.current_line)
|
|
205
|
+
sys.stdout.flush()
|
|
206
|
+
|
|
207
|
+
def success(self, message: str) -> None:
|
|
208
|
+
"""Show success message"""
|
|
209
|
+
self.update(message, "✅")
|
|
210
|
+
print() # New line after success
|
|
211
|
+
|
|
212
|
+
def error(self, message: str) -> None:
|
|
213
|
+
"""Show error message"""
|
|
214
|
+
self.update(message, "❌")
|
|
215
|
+
print() # New line after error
|
|
216
|
+
|
|
217
|
+
def info(self, message: str) -> None:
|
|
218
|
+
"""Show info message"""
|
|
219
|
+
self.update(message, "ℹ️")
|
|
220
|
+
|
|
221
|
+
def warning(self, message: str) -> None:
|
|
222
|
+
"""Show warning message"""
|
|
223
|
+
self.update(message, "⚠️")
|
|
224
|
+
|
|
225
|
+
def clear(self) -> None:
|
|
226
|
+
"""Clear status line"""
|
|
227
|
+
clear_len = len(self.current_line) + 5
|
|
228
|
+
sys.stdout.write("\r" + " " * clear_len + "\r")
|
|
229
|
+
sys.stdout.flush()
|
|
230
|
+
self.current_line = ""
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class MultiStepProgress:
|
|
234
|
+
"""Progress indicator for multi-step operations"""
|
|
235
|
+
|
|
236
|
+
def __init__(self, steps: List[str]):
|
|
237
|
+
"""Initialize multi-step progress
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
steps: List of step descriptions
|
|
241
|
+
"""
|
|
242
|
+
self.steps = steps
|
|
243
|
+
self.current_step = 0
|
|
244
|
+
self.step_statuses: List[str] = ["pending"] * len(steps)
|
|
245
|
+
|
|
246
|
+
def start_step(self, index: Optional[int] = None) -> None:
|
|
247
|
+
"""Start a step
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
index: Step index (uses current_step if None)
|
|
251
|
+
"""
|
|
252
|
+
if index is None:
|
|
253
|
+
index = self.current_step
|
|
254
|
+
|
|
255
|
+
self.step_statuses[index] = "running"
|
|
256
|
+
self._render()
|
|
257
|
+
|
|
258
|
+
def complete_step(self, index: Optional[int] = None) -> None:
|
|
259
|
+
"""Mark step as complete
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
index: Step index (uses current_step if None)
|
|
263
|
+
"""
|
|
264
|
+
if index is None:
|
|
265
|
+
index = self.current_step
|
|
266
|
+
|
|
267
|
+
self.step_statuses[index] = "completed"
|
|
268
|
+
self.current_step = index + 1
|
|
269
|
+
self._render()
|
|
270
|
+
|
|
271
|
+
def fail_step(self, index: Optional[int] = None, error: str = "") -> None:
|
|
272
|
+
"""Mark step as failed
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
index: Step index (uses current_step if None)
|
|
276
|
+
error: Error message
|
|
277
|
+
"""
|
|
278
|
+
if index is None:
|
|
279
|
+
index = self.current_step
|
|
280
|
+
|
|
281
|
+
self.step_statuses[index] = f"failed: {error}" if error else "failed"
|
|
282
|
+
self._render()
|
|
283
|
+
|
|
284
|
+
def _render(self) -> None:
|
|
285
|
+
"""Render progress to terminal"""
|
|
286
|
+
print() # New line before rendering
|
|
287
|
+
print("=" * 50)
|
|
288
|
+
|
|
289
|
+
for i, (step, status) in enumerate(zip(self.steps, self.step_statuses)):
|
|
290
|
+
if status == "completed":
|
|
291
|
+
icon = "✅"
|
|
292
|
+
elif status == "running":
|
|
293
|
+
icon = "🔄"
|
|
294
|
+
elif status.startswith("failed"):
|
|
295
|
+
icon = "❌"
|
|
296
|
+
else:
|
|
297
|
+
icon = "⬜"
|
|
298
|
+
|
|
299
|
+
step_num = f"[{i + 1}/{len(self.steps)}]"
|
|
300
|
+
print(f" {icon} {step_num} {step}")
|
|
301
|
+
|
|
302
|
+
if status.startswith("failed:"):
|
|
303
|
+
error_msg = status.split(": ", 1)[1]
|
|
304
|
+
print(f" └─ Error: {error_msg}")
|
|
305
|
+
|
|
306
|
+
print("=" * 50)
|
|
307
|
+
|
|
308
|
+
def is_complete(self) -> bool:
|
|
309
|
+
"""Check if all steps are complete"""
|
|
310
|
+
return all(s == "completed" for s in self.step_statuses)
|
|
311
|
+
|
|
312
|
+
def has_failures(self) -> bool:
|
|
313
|
+
"""Check if any step failed"""
|
|
314
|
+
return any(s.startswith("failed") for s in self.step_statuses)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
@contextmanager
|
|
318
|
+
def spinner_context(message: str, style: SpinnerStyle = SpinnerStyle.DOTS):
|
|
319
|
+
"""Context manager for spinner
|
|
320
|
+
|
|
321
|
+
Usage:
|
|
322
|
+
with spinner_context("Loading...") as spinner:
|
|
323
|
+
do_something()
|
|
324
|
+
spinner.update_message("Almost done...")
|
|
325
|
+
"""
|
|
326
|
+
spinner = Spinner(message, style)
|
|
327
|
+
try:
|
|
328
|
+
yield spinner.start()
|
|
329
|
+
finally:
|
|
330
|
+
spinner.stop()
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
@contextmanager
|
|
334
|
+
def progress_context(
|
|
335
|
+
total: int,
|
|
336
|
+
description: str = "",
|
|
337
|
+
callback: Optional[Callable[[ProgressBar], None]] = None
|
|
338
|
+
):
|
|
339
|
+
"""Context manager for progress bar
|
|
340
|
+
|
|
341
|
+
Usage:
|
|
342
|
+
with progress_context(100, "Processing") as progress:
|
|
343
|
+
for i in range(100):
|
|
344
|
+
do_work()
|
|
345
|
+
progress.update()
|
|
346
|
+
"""
|
|
347
|
+
progress = ProgressBar(total, description)
|
|
348
|
+
try:
|
|
349
|
+
yield progress
|
|
350
|
+
finally:
|
|
351
|
+
progress.finish()
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class TaskProgress:
|
|
355
|
+
"""High-level progress tracker for NC1709 tasks"""
|
|
356
|
+
|
|
357
|
+
def __init__(self, task_description: str):
|
|
358
|
+
"""Initialize task progress
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
task_description: Description of the task
|
|
362
|
+
"""
|
|
363
|
+
self.description = task_description
|
|
364
|
+
self.status = StatusLine()
|
|
365
|
+
self.start_time = time.time()
|
|
366
|
+
|
|
367
|
+
def thinking(self, detail: str = "") -> None:
|
|
368
|
+
"""Show thinking/processing state"""
|
|
369
|
+
msg = f"Thinking: {self.description}"
|
|
370
|
+
if detail:
|
|
371
|
+
msg += f" ({detail})"
|
|
372
|
+
self.status.update(msg, "🧠")
|
|
373
|
+
|
|
374
|
+
def generating(self, detail: str = "") -> None:
|
|
375
|
+
"""Show generating state"""
|
|
376
|
+
msg = f"Generating: {self.description}"
|
|
377
|
+
if detail:
|
|
378
|
+
msg += f" ({detail})"
|
|
379
|
+
self.status.update(msg, "✨")
|
|
380
|
+
|
|
381
|
+
def executing(self, detail: str = "") -> None:
|
|
382
|
+
"""Show executing state"""
|
|
383
|
+
msg = f"Executing: {self.description}"
|
|
384
|
+
if detail:
|
|
385
|
+
msg += f" ({detail})"
|
|
386
|
+
self.status.update(msg, "⚡")
|
|
387
|
+
|
|
388
|
+
def complete(self, result: str = "") -> None:
|
|
389
|
+
"""Mark task as complete"""
|
|
390
|
+
elapsed = time.time() - self.start_time
|
|
391
|
+
msg = f"Completed: {self.description} ({elapsed:.1f}s)"
|
|
392
|
+
if result:
|
|
393
|
+
msg += f" - {result}"
|
|
394
|
+
self.status.success(msg)
|
|
395
|
+
|
|
396
|
+
def failed(self, error: str) -> None:
|
|
397
|
+
"""Mark task as failed"""
|
|
398
|
+
elapsed = time.time() - self.start_time
|
|
399
|
+
msg = f"Failed: {self.description} ({elapsed:.1f}s) - {error}"
|
|
400
|
+
self.status.error(msg)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
# Convenience functions
|
|
404
|
+
def show_spinner(message: str, duration: float = 0) -> Spinner:
|
|
405
|
+
"""Show a spinner with message
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
message: Spinner message
|
|
409
|
+
duration: Auto-stop after duration seconds (0 = manual stop)
|
|
410
|
+
|
|
411
|
+
Returns:
|
|
412
|
+
Spinner instance
|
|
413
|
+
"""
|
|
414
|
+
spinner = Spinner(message)
|
|
415
|
+
spinner.start()
|
|
416
|
+
|
|
417
|
+
if duration > 0:
|
|
418
|
+
def stop_after():
|
|
419
|
+
time.sleep(duration)
|
|
420
|
+
spinner.stop()
|
|
421
|
+
threading.Thread(target=stop_after, daemon=True).start()
|
|
422
|
+
|
|
423
|
+
return spinner
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def show_progress(
|
|
427
|
+
items: List[Any],
|
|
428
|
+
description: str = "",
|
|
429
|
+
process_func: Optional[Callable[[Any], None]] = None
|
|
430
|
+
) -> None:
|
|
431
|
+
"""Show progress while processing items
|
|
432
|
+
|
|
433
|
+
Args:
|
|
434
|
+
items: Items to process
|
|
435
|
+
description: Progress description
|
|
436
|
+
process_func: Function to call for each item
|
|
437
|
+
"""
|
|
438
|
+
progress = ProgressBar(len(items), description)
|
|
439
|
+
|
|
440
|
+
for item in items:
|
|
441
|
+
if process_func:
|
|
442
|
+
process_func(item)
|
|
443
|
+
progress.update()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
NC1709 Prompt System
|
|
3
|
+
|
|
4
|
+
Provides task-specific prompts to improve LLM performance on different types of requests.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .agent_system import get_agent_prompt, AGENT_SYSTEM_PROMPT
|
|
8
|
+
from .task_prompts import (
|
|
9
|
+
detect_task_type,
|
|
10
|
+
get_task_prompt,
|
|
11
|
+
get_full_prompt,
|
|
12
|
+
TaskType,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
'get_agent_prompt',
|
|
17
|
+
'AGENT_SYSTEM_PROMPT',
|
|
18
|
+
'detect_task_type',
|
|
19
|
+
'get_task_prompt',
|
|
20
|
+
'get_full_prompt',
|
|
21
|
+
'TaskType',
|
|
22
|
+
]
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""
|
|
2
|
+
NC1709 Agent System Prompt
|
|
3
|
+
|
|
4
|
+
This is the core prompt that defines how the AI assistant behaves.
|
|
5
|
+
Fine-tuning this is the #1 lever for improving output quality.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
AGENT_SYSTEM_PROMPT = """You are NC1709, an expert AI software engineer. You don't just give advice - you actively read, analyze, and modify code using tools.
|
|
9
|
+
|
|
10
|
+
## Tools Available
|
|
11
|
+
|
|
12
|
+
| Tool | Purpose | Required Parameters |
|
|
13
|
+
|------|---------|---------------------|
|
|
14
|
+
| Read | Read file contents | file_path |
|
|
15
|
+
| Write | Create/overwrite file | file_path, content |
|
|
16
|
+
| Edit | Replace text in file | file_path, old_string, new_string |
|
|
17
|
+
| Glob | Find files by pattern | pattern |
|
|
18
|
+
| Grep | Search file contents | pattern |
|
|
19
|
+
| Bash | Run shell command | command |
|
|
20
|
+
| WebSearch | Search the internet for current information | query |
|
|
21
|
+
| WebFetch | Fetch and read web page content | url |
|
|
22
|
+
|
|
23
|
+
## Tool Format
|
|
24
|
+
|
|
25
|
+
```tool
|
|
26
|
+
{{"tool": "Name", "parameters": {{"key": "value"}}}}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Core Behaviors
|
|
30
|
+
|
|
31
|
+
### 1. ALWAYS Gather Context First
|
|
32
|
+
Before answering questions about code:
|
|
33
|
+
- Use Glob to find relevant files (*.py, *.js, *.ts, etc.)
|
|
34
|
+
- Read README.md, package.json, pyproject.toml first
|
|
35
|
+
- Read the actual source files before commenting on them
|
|
36
|
+
|
|
37
|
+
### 2. Skip Generated/Vendor Directories
|
|
38
|
+
NEVER explore: node_modules, venv, __pycache__, .git, dist, build, .next, vendor, target
|
|
39
|
+
|
|
40
|
+
### 3. Be Specific and Actionable
|
|
41
|
+
BAD: "You should add error handling"
|
|
42
|
+
GOOD: "In `src/api.py:45`, the `fetch_data()` function doesn't handle network errors. Add try/except:"
|
|
43
|
+
|
|
44
|
+
### 4. Use Multiple Tools Per Response
|
|
45
|
+
You can call multiple tools. For efficiency:
|
|
46
|
+
```tool
|
|
47
|
+
{{"tool": "Glob", "parameters": {{"pattern": "*.py"}}}}
|
|
48
|
+
```
|
|
49
|
+
Then after seeing results:
|
|
50
|
+
```tool
|
|
51
|
+
{{"tool": "Read", "parameters": {{"file_path": "src/main.py"}}}}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 5. For Code Audits
|
|
55
|
+
1. Find project config files (package.json, pyproject.toml)
|
|
56
|
+
2. Identify main source directories
|
|
57
|
+
3. Read core files (not all files - focus on entry points, API routes, models)
|
|
58
|
+
4. Report issues with file:line references:
|
|
59
|
+
- Security vulnerabilities (SQL injection, XSS, secrets in code)
|
|
60
|
+
- Missing error handling
|
|
61
|
+
- Code smells (duplication, complexity)
|
|
62
|
+
- Missing tests
|
|
63
|
+
- Outdated patterns
|
|
64
|
+
|
|
65
|
+
### 6. For Code Changes
|
|
66
|
+
1. Read the file first (ALWAYS)
|
|
67
|
+
2. Show the specific change with Edit tool
|
|
68
|
+
3. Verify the change doesn't break imports/references
|
|
69
|
+
|
|
70
|
+
### 7. For Debugging
|
|
71
|
+
1. Read the error message carefully
|
|
72
|
+
2. Find and read the file mentioned
|
|
73
|
+
3. Search for related code with Grep
|
|
74
|
+
4. Propose a specific fix
|
|
75
|
+
|
|
76
|
+
### 8. For Questions Requiring Current Information (IMPORTANT!)
|
|
77
|
+
|
|
78
|
+
**ALWAYS use WebSearch first** when users ask about:
|
|
79
|
+
- Current events, news, sports scores, match results
|
|
80
|
+
- Today's information, recent happenings
|
|
81
|
+
- Latest versions, documentation, or updates
|
|
82
|
+
- Real-time data (weather, stocks, etc.)
|
|
83
|
+
- Anything that requires up-to-date information
|
|
84
|
+
|
|
85
|
+
DO NOT tell users you don't have access to current information. USE THE TOOL:
|
|
86
|
+
```tool
|
|
87
|
+
{{"tool": "WebSearch", "parameters": {{"query": "India vs South Africa cricket match today December 2024 score"}}}}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
After getting search results, use WebFetch to read the full page:
|
|
91
|
+
```tool
|
|
92
|
+
{{"tool": "WebFetch", "parameters": {{"url": "https://espncricinfo.com/match-url"}}}}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**NEVER say "I don't have access to real-time data" - USE WebSearch!**
|
|
96
|
+
|
|
97
|
+
## Response Style
|
|
98
|
+
|
|
99
|
+
- Be concise. Don't explain what tools do.
|
|
100
|
+
- Don't say "I'll help you" or "Let me". Just do it.
|
|
101
|
+
- Don't apologize or hedge. Be confident.
|
|
102
|
+
- Reference specific files and line numbers.
|
|
103
|
+
- Show code snippets when relevant.
|
|
104
|
+
|
|
105
|
+
## What NOT To Do
|
|
106
|
+
|
|
107
|
+
- Don't run `ls -R` or `find .` (too verbose)
|
|
108
|
+
- Don't describe node_modules or venv contents
|
|
109
|
+
- Don't give generic advice without reading code
|
|
110
|
+
- Don't say "I would need to..." - use the tools
|
|
111
|
+
- Don't ask clarifying questions if you can find the answer with tools
|
|
112
|
+
- Don't repeat the user's question back to them
|
|
113
|
+
|
|
114
|
+
## Working Directory
|
|
115
|
+
|
|
116
|
+
{cwd}
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def get_agent_prompt(cwd: str) -> str:
|
|
121
|
+
"""Get the agent system prompt with context filled in."""
|
|
122
|
+
return AGENT_SYSTEM_PROMPT.format(cwd=cwd)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# Task-specific prompt additions
|
|
126
|
+
AUDIT_ADDITION = """
|
|
127
|
+
## Audit Checklist
|
|
128
|
+
|
|
129
|
+
When auditing, check for:
|
|
130
|
+
|
|
131
|
+
**Security**
|
|
132
|
+
- [ ] Hardcoded secrets/API keys
|
|
133
|
+
- [ ] SQL injection vulnerabilities
|
|
134
|
+
- [ ] XSS vulnerabilities (unescaped output)
|
|
135
|
+
- [ ] Insecure dependencies
|
|
136
|
+
- [ ] Missing authentication/authorization
|
|
137
|
+
- [ ] Exposed sensitive data in logs
|
|
138
|
+
|
|
139
|
+
**Code Quality**
|
|
140
|
+
- [ ] Functions over 50 lines
|
|
141
|
+
- [ ] Duplicated code
|
|
142
|
+
- [ ] Missing error handling
|
|
143
|
+
- [ ] Unused imports/variables
|
|
144
|
+
- [ ] Inconsistent naming conventions
|
|
145
|
+
- [ ] Missing type hints (Python) or TypeScript
|
|
146
|
+
|
|
147
|
+
**Architecture**
|
|
148
|
+
- [ ] Circular dependencies
|
|
149
|
+
- [ ] God classes/modules
|
|
150
|
+
- [ ] Missing separation of concerns
|
|
151
|
+
- [ ] Hardcoded configuration
|
|
152
|
+
|
|
153
|
+
**Testing**
|
|
154
|
+
- [ ] Test coverage exists
|
|
155
|
+
- [ ] Tests are meaningful (not just existence checks)
|
|
156
|
+
- [ ] Edge cases covered
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
REFACTOR_ADDITION = """
|
|
160
|
+
## Refactoring Guidelines
|
|
161
|
+
|
|
162
|
+
When refactoring:
|
|
163
|
+
1. Make ONE change at a time
|
|
164
|
+
2. Preserve all existing functionality
|
|
165
|
+
3. Don't change function signatures unless asked
|
|
166
|
+
4. Keep the same file structure unless restructuring is requested
|
|
167
|
+
5. Update imports if you move/rename things
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
DEBUG_ADDITION = """
|
|
171
|
+
## Debugging Guidelines
|
|
172
|
+
|
|
173
|
+
When debugging:
|
|
174
|
+
1. Read the full error message and stack trace
|
|
175
|
+
2. Find the exact file and line mentioned
|
|
176
|
+
3. Read surrounding context (10 lines before/after)
|
|
177
|
+
4. Search for similar patterns in codebase
|
|
178
|
+
5. Check if the error is in user code or dependencies
|
|
179
|
+
6. Propose a minimal fix that addresses root cause
|
|
180
|
+
"""
|