devpilot-agentic-cli 1.0.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.
- agent/__init__.py +1 -0
- agent/a2a_client.py +94 -0
- agent/a2a_server.py +148 -0
- agent/cli.py +233 -0
- agent/config.py +232 -0
- agent/context.py +182 -0
- agent/history.py +172 -0
- agent/loop.py +102 -0
- agent/mcp_client.py +104 -0
- agent/providers/__init__.py +4 -0
- agent/providers/anthropic_provider.py +169 -0
- agent/providers/base.py +148 -0
- agent/providers/factory.py +35 -0
- agent/providers/openai_provider.py +194 -0
- agent/providers/system_prompt.py +132 -0
- agent/setup_wizard.py +309 -0
- agent/tools/__init__.py +15 -0
- agent/tools/a2a.py +56 -0
- agent/tools/base.py +52 -0
- agent/tools/diagram.py +131 -0
- agent/tools/doc_gen.py +163 -0
- agent/tools/fs.py +411 -0
- agent/tools/git_ops.py +145 -0
- agent/tools/registry.py +219 -0
- agent/tools/search_code.py +120 -0
- agent/tools/shell.py +118 -0
- agent/tools/web_search.py +105 -0
- agent/tui/__init__.py +3 -0
- agent/tui/app.py +557 -0
- agent/ui.py +263 -0
- devpilot_agentic_cli-1.0.0.dist-info/METADATA +288 -0
- devpilot_agentic_cli-1.0.0.dist-info/RECORD +35 -0
- devpilot_agentic_cli-1.0.0.dist-info/WHEEL +5 -0
- devpilot_agentic_cli-1.0.0.dist-info/entry_points.txt +2 -0
- devpilot_agentic_cli-1.0.0.dist-info/top_level.txt +1 -0
agent/ui.py
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agent/ui.py
|
|
3
|
+
───────────
|
|
4
|
+
Rich-based user interface for DevPilot terminal output.
|
|
5
|
+
Handles rendering markdown, tool traces, diffs, and errors.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.markdown import Markdown
|
|
12
|
+
from rich.panel import Panel
|
|
13
|
+
from rich.syntax import Syntax
|
|
14
|
+
from rich.theme import Theme
|
|
15
|
+
import typing
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
if typing.TYPE_CHECKING:
|
|
19
|
+
from textual.message import Message as _TextualMessage
|
|
20
|
+
else:
|
|
21
|
+
try:
|
|
22
|
+
from textual.message import Message as _TextualMessage
|
|
23
|
+
except ImportError:
|
|
24
|
+
_TextualMessage = object
|
|
25
|
+
|
|
26
|
+
class UIEvent(_TextualMessage):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
class AssistantMessageEvent(UIEvent):
|
|
30
|
+
def __init__(self, text: str) -> None:
|
|
31
|
+
self.text = text
|
|
32
|
+
super().__init__()
|
|
33
|
+
|
|
34
|
+
class StreamTokenEvent(UIEvent):
|
|
35
|
+
def __init__(self, token: str) -> None:
|
|
36
|
+
self.token = token
|
|
37
|
+
super().__init__()
|
|
38
|
+
|
|
39
|
+
class ToolCallEvent(UIEvent):
|
|
40
|
+
def __init__(self, tool_name: str, tool_input: dict) -> None:
|
|
41
|
+
self.tool_name = tool_name
|
|
42
|
+
self.tool_input = tool_input
|
|
43
|
+
super().__init__()
|
|
44
|
+
|
|
45
|
+
class ToolResultEvent(UIEvent):
|
|
46
|
+
def __init__(self, tool_name: str, content: str, is_error: bool) -> None:
|
|
47
|
+
self.tool_name = tool_name
|
|
48
|
+
self.content = content
|
|
49
|
+
self.is_error = is_error
|
|
50
|
+
super().__init__()
|
|
51
|
+
|
|
52
|
+
class ErrorEvent(UIEvent):
|
|
53
|
+
def __init__(self, msg: str) -> None:
|
|
54
|
+
self.msg = msg
|
|
55
|
+
super().__init__()
|
|
56
|
+
|
|
57
|
+
class InfoEvent(UIEvent):
|
|
58
|
+
def __init__(self, msg: str) -> None:
|
|
59
|
+
self.msg = msg
|
|
60
|
+
super().__init__()
|
|
61
|
+
|
|
62
|
+
class SuccessEvent(UIEvent):
|
|
63
|
+
def __init__(self, msg: str) -> None:
|
|
64
|
+
self.msg = msg
|
|
65
|
+
super().__init__()
|
|
66
|
+
|
|
67
|
+
class DiffEvent(UIEvent):
|
|
68
|
+
def __init__(self, path: str, diff: str, is_new: bool) -> None:
|
|
69
|
+
self.path = path
|
|
70
|
+
self.diff = diff
|
|
71
|
+
self.is_new = is_new
|
|
72
|
+
super().__init__()
|
|
73
|
+
|
|
74
|
+
class ThinkingEvent(UIEvent):
|
|
75
|
+
def __init__(self, thinking_text: str) -> None:
|
|
76
|
+
self.thinking_text = thinking_text
|
|
77
|
+
super().__init__()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# ── Rich Terminal Theme (Fallback / CI mode) ──────────────────────────────────
|
|
81
|
+
|
|
82
|
+
_custom_theme = Theme({
|
|
83
|
+
"info": "dim cyan",
|
|
84
|
+
"warning": "magenta",
|
|
85
|
+
"danger": "bold red",
|
|
86
|
+
"tool.name": "bold blue",
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
console = Console(theme=_custom_theme)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class UI:
|
|
93
|
+
"""Namespace for UI rendering functions."""
|
|
94
|
+
|
|
95
|
+
_tui_app: Any = None
|
|
96
|
+
|
|
97
|
+
@classmethod
|
|
98
|
+
def set_tui_app(cls, app: Any) -> None:
|
|
99
|
+
cls._tui_app = app
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def print_stream_token(token: str) -> None:
|
|
103
|
+
"""Render a single stream token."""
|
|
104
|
+
if UI._tui_app:
|
|
105
|
+
UI._tui_app.post_message(StreamTokenEvent(token))
|
|
106
|
+
return
|
|
107
|
+
console.print(token, end="", highlight=False)
|
|
108
|
+
|
|
109
|
+
@staticmethod
|
|
110
|
+
def print_assistant_message(text: str) -> None:
|
|
111
|
+
"""Render normal markdown text from the assistant."""
|
|
112
|
+
if not text.strip():
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
if UI._tui_app:
|
|
116
|
+
UI._tui_app.post_message(AssistantMessageEvent(text))
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
console.print()
|
|
120
|
+
console.print(Markdown(text))
|
|
121
|
+
console.print()
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def print_tool_call(tool_name: str, tool_input: dict) -> None:
|
|
125
|
+
"""Render a trace of a tool invocation."""
|
|
126
|
+
if UI._tui_app:
|
|
127
|
+
UI._tui_app.post_message(ToolCallEvent(tool_name, tool_input))
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
# We can format the tool input nicely
|
|
131
|
+
import json
|
|
132
|
+
try:
|
|
133
|
+
input_str = json.dumps(tool_input, indent=2)
|
|
134
|
+
except Exception:
|
|
135
|
+
input_str = str(tool_input)
|
|
136
|
+
|
|
137
|
+
panel = Panel(
|
|
138
|
+
Syntax(input_str, "json", theme="monokai", background_color="default"),
|
|
139
|
+
title=f"[tool.name]🔧 Tool Call: {tool_name}[/tool.name]",
|
|
140
|
+
border_style="blue",
|
|
141
|
+
expand=False,
|
|
142
|
+
)
|
|
143
|
+
console.print(panel)
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
def print_tool_result(tool_name: str, content: str, is_error: bool = False) -> None:
|
|
147
|
+
"""Render the result of a tool execution."""
|
|
148
|
+
if UI._tui_app:
|
|
149
|
+
UI._tui_app.post_message(ToolResultEvent(tool_name, content, is_error))
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
# Truncate output if it's too long
|
|
153
|
+
lines = content.splitlines()
|
|
154
|
+
if len(lines) > 20:
|
|
155
|
+
content = "\n".join(lines[:20]) + f"\n... (truncated {len(lines) - 20} lines)"
|
|
156
|
+
|
|
157
|
+
border_color = "red" if is_error else "green"
|
|
158
|
+
title = f"[bold {border_color}]Result: {tool_name}[/bold {border_color}]"
|
|
159
|
+
|
|
160
|
+
panel = Panel(
|
|
161
|
+
content,
|
|
162
|
+
title=title,
|
|
163
|
+
border_style=border_color,
|
|
164
|
+
expand=False,
|
|
165
|
+
)
|
|
166
|
+
console.print(panel)
|
|
167
|
+
|
|
168
|
+
@staticmethod
|
|
169
|
+
def print_error(msg: str) -> None:
|
|
170
|
+
"""Render a system or application error."""
|
|
171
|
+
if UI._tui_app:
|
|
172
|
+
UI._tui_app.post_message(ErrorEvent(msg))
|
|
173
|
+
return
|
|
174
|
+
console.print(f"[danger]❌ {msg}[/danger]")
|
|
175
|
+
|
|
176
|
+
@staticmethod
|
|
177
|
+
def print_info(msg: str) -> None:
|
|
178
|
+
"""Render a system info message."""
|
|
179
|
+
if UI._tui_app:
|
|
180
|
+
UI._tui_app.post_message(InfoEvent(msg))
|
|
181
|
+
return
|
|
182
|
+
console.print(f"[info]ℹ️ {msg}[/info]")
|
|
183
|
+
|
|
184
|
+
@staticmethod
|
|
185
|
+
def print_success(msg: str) -> None:
|
|
186
|
+
"""Render a success message."""
|
|
187
|
+
if UI._tui_app:
|
|
188
|
+
UI._tui_app.post_message(SuccessEvent(msg))
|
|
189
|
+
return
|
|
190
|
+
console.print(f"[bold green]✓ {msg}[/bold green]")
|
|
191
|
+
|
|
192
|
+
@staticmethod
|
|
193
|
+
def print_thinking_block(thinking_text: str) -> None:
|
|
194
|
+
"""Render the model's extended thinking in a muted panel."""
|
|
195
|
+
if not thinking_text or not thinking_text.strip():
|
|
196
|
+
return
|
|
197
|
+
|
|
198
|
+
if UI._tui_app:
|
|
199
|
+
UI._tui_app.post_message(ThinkingEvent(thinking_text))
|
|
200
|
+
return
|
|
201
|
+
|
|
202
|
+
lines = thinking_text.splitlines()
|
|
203
|
+
if len(lines) > 30:
|
|
204
|
+
display = "\n".join(lines[:30]) + f"\n... [{len(lines) - 30} more lines hidden]"
|
|
205
|
+
else:
|
|
206
|
+
display = thinking_text
|
|
207
|
+
panel = Panel(
|
|
208
|
+
f"[dim]{display}[/dim]",
|
|
209
|
+
title="[dim]🧠 Extended Thinking[/dim]",
|
|
210
|
+
border_style="dim",
|
|
211
|
+
expand=False,
|
|
212
|
+
)
|
|
213
|
+
console.print(panel)
|
|
214
|
+
|
|
215
|
+
@staticmethod
|
|
216
|
+
def print_diff(path: str, diff: str, is_new: bool = False) -> None:
|
|
217
|
+
"""Render a syntax-highlighted unified diff before a file write."""
|
|
218
|
+
if UI._tui_app:
|
|
219
|
+
UI._tui_app.post_message(DiffEvent(path, diff, is_new))
|
|
220
|
+
return
|
|
221
|
+
|
|
222
|
+
label = "New file" if is_new else "Changes"
|
|
223
|
+
panel = Panel(
|
|
224
|
+
Syntax(diff, "diff", theme="monokai", background_color="default"),
|
|
225
|
+
title=f"[bold yellow]📝 {label}: {path}[/bold yellow]",
|
|
226
|
+
border_style="yellow",
|
|
227
|
+
expand=False,
|
|
228
|
+
)
|
|
229
|
+
console.print(panel)
|
|
230
|
+
|
|
231
|
+
@staticmethod
|
|
232
|
+
async def ask_permission(tool_name: str, preview_lines: list[str]) -> str:
|
|
233
|
+
"""
|
|
234
|
+
Request permission. If in TUI mode, pushes an async modal.
|
|
235
|
+
Otherwise, blocks on input() in an executor so the async loop doesn't stall.
|
|
236
|
+
"""
|
|
237
|
+
if UI._tui_app:
|
|
238
|
+
from agent.tui.app import PermissionModal
|
|
239
|
+
# app.push_screen_wait is async and pauses the worker safely!
|
|
240
|
+
choice = await UI._tui_app.push_screen_wait(PermissionModal(tool_name, preview_lines))
|
|
241
|
+
return str(choice)
|
|
242
|
+
|
|
243
|
+
body = "\n".join(preview_lines)
|
|
244
|
+
panel = Panel(
|
|
245
|
+
f"[bold]{body}[/bold]",
|
|
246
|
+
title=f"[bold yellow]⚠ Permission required: {tool_name}[/bold yellow]",
|
|
247
|
+
border_style="yellow",
|
|
248
|
+
expand=False,
|
|
249
|
+
)
|
|
250
|
+
console.print(panel)
|
|
251
|
+
|
|
252
|
+
import asyncio
|
|
253
|
+
loop = asyncio.get_event_loop()
|
|
254
|
+
def _get_input():
|
|
255
|
+
try:
|
|
256
|
+
return input(" [y] allow once [a] allow all [n] deny: ").strip().lower()
|
|
257
|
+
except (KeyboardInterrupt, EOFError):
|
|
258
|
+
return "n"
|
|
259
|
+
|
|
260
|
+
while True:
|
|
261
|
+
choice = await loop.run_in_executor(None, _get_input)
|
|
262
|
+
if choice in ("y", "yes", "", "a", "all", "n", "no"):
|
|
263
|
+
return choice
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: devpilot-agentic-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Autonomous AI coding agent for your terminal — Claude, GPT-4o, Groq, Ollama, and more
|
|
5
|
+
Author: Thijesh Praveen V
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Thijeshpraveen-V/DevPilot
|
|
8
|
+
Project-URL: Repository, https://github.com/Thijeshpraveen-V/DevPilot
|
|
9
|
+
Project-URL: Issues, https://github.com/Thijeshpraveen-V/DevPilot/issues
|
|
10
|
+
Keywords: ai,coding-agent,cli,llm,anthropic,openai,groq,ollama,claude,gpt4,terminal,agent,mcp,textual,tui
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Topic :: Software Development
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: anthropic>=0.40.0
|
|
22
|
+
Requires-Dist: openai>=1.50.0
|
|
23
|
+
Requires-Dist: rich>=13.7.0
|
|
24
|
+
Requires-Dist: textual>=0.52.0
|
|
25
|
+
Requires-Dist: fastapi>=0.111.0
|
|
26
|
+
Requires-Dist: uvicorn[standard]>=0.30.0
|
|
27
|
+
Requires-Dist: sse-starlette>=2.1.0
|
|
28
|
+
Requires-Dist: httpx>=0.27.0
|
|
29
|
+
Requires-Dist: anyio>=4.4.0
|
|
30
|
+
Requires-Dist: mcp>=1.0.0
|
|
31
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
32
|
+
Requires-Dist: pydantic>=2.7.0
|
|
33
|
+
Requires-Dist: tavily-python>=0.3.0
|
|
34
|
+
Requires-Dist: GitPython>=3.1.40
|
|
35
|
+
Requires-Dist: markdown-it-py>=3.0.0
|
|
36
|
+
Requires-Dist: pypdf>=4.0.0
|
|
37
|
+
Provides-Extra: pdf
|
|
38
|
+
Requires-Dist: pdfkit>=1.0.0; extra == "pdf"
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: pytest>=8.2.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-asyncio>=0.23.7; extra == "dev"
|
|
42
|
+
|
|
43
|
+
# DevPilot 🚀
|
|
44
|
+
|
|
45
|
+
[](https://pypi.org/project/devpilot-agentic-cli/)
|
|
46
|
+
[](https://pypi.org/project/devpilot-agentic-cli/)
|
|
47
|
+
[](https://opensource.org/licenses/MIT)
|
|
48
|
+
|
|
49
|
+
**An autonomous AI coding agent for your terminal.** DevPilot gives Claude, GPT-4o, Groq, Mistral, or any local model a full suite of tools — file read/write, bash execution, code search, git, MCP, and more — orchestrated into a self-healing agentic loop inside a rich Textual TUI.
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
┌─ DevPilot ──────────────────────────────────────────────────────┐
|
|
53
|
+
│ ✦ claude-opus-4-5 │ agent/tools/fs.py │ iteration 2/50 │
|
|
54
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
55
|
+
│ You › Add input validation to the write_file tool │
|
|
56
|
+
│ │
|
|
57
|
+
│ ● Calling read_file agent/tools/fs.py │
|
|
58
|
+
│ ● Calling edit_file agent/tools/fs.py │
|
|
59
|
+
│ ✓ Edited agent/tools/fs.py successfully. │
|
|
60
|
+
│ │
|
|
61
|
+
│ Done — added a size cap and path-escape guard. The diff is │
|
|
62
|
+
│ above. Want me to run the tests? │
|
|
63
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Features
|
|
69
|
+
|
|
70
|
+
| Category | Capability |
|
|
71
|
+
|---|---|
|
|
72
|
+
| **File ops** | `read_file`, `write_file`, `edit_file` (surgical replace), `list_files` |
|
|
73
|
+
| **Shell** | `run_bash` with timeout, blocked-command guard, and auto-heal loop |
|
|
74
|
+
| **Code search** | Regex `search_code` |
|
|
75
|
+
| **Pre-flight linting** | Syntax-checks Python (`ast.parse`) and JS/TS (`node --check`) before writing |
|
|
76
|
+
| **Git** | `git_status`, `git_commit` with surgical file staging |
|
|
77
|
+
| **Documentation** | `doc_gen` (markdown), `diagram` (Mermaid) |
|
|
78
|
+
| **Web search** | `web_search` via Tavily (optional) |
|
|
79
|
+
|
|
80
|
+
| **MCP** | Connect any MCP server via `mcp_servers.json` |
|
|
81
|
+
| **A2A** | Agent-to-agent task delegation over HTTP |
|
|
82
|
+
| **Providers** | Anthropic, OpenAI, Groq, Together AI, Mistral, Ollama, any OpenAI-compatible endpoint |
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Quickstart
|
|
87
|
+
|
|
88
|
+
**Requires Python ≥ 3.11.**
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install devpilot-agentic-cli
|
|
92
|
+
devpilot
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
That's it. On first run DevPilot launches a setup wizard — pick your provider, enter your API key, choose a model. It saves everything to a `.env` file and opens the TUI. Every subsequent run starts immediately.
|
|
96
|
+
|
|
97
|
+
### Optional Features
|
|
98
|
+
|
|
99
|
+
**PDF Documentation Generation**
|
|
100
|
+
Enable the `generate_docs` tool to export PDFs:
|
|
101
|
+
```bash
|
|
102
|
+
pip install devpilot-agentic-cli[pdf]
|
|
103
|
+
```
|
|
104
|
+
*Note: You also need to install the [wkhtmltopdf](https://wkhtmltopdf.org/downloads.html) system binary.*
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Providers
|
|
109
|
+
|
|
110
|
+
DevPilot works with any of these out of the box — the setup wizard walks you through each one:
|
|
111
|
+
|
|
112
|
+
| Provider | Models | Get API key |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| **Anthropic** | claude-opus-4-5, claude-sonnet-4-5, claude-haiku-4-5 | [console.anthropic.com](https://console.anthropic.com/) |
|
|
115
|
+
| **OpenAI** | gpt-4o, gpt-4o-mini, o3, o4-mini | [platform.openai.com](https://platform.openai.com/api-keys) |
|
|
116
|
+
| **Groq** | llama-3.3-70b, mixtral-8x7b, gemma2-9b | [console.groq.com](https://console.groq.com/keys) |
|
|
117
|
+
| **Together AI** | Llama 3, Mixtral, and more | [api.together.xyz](https://api.together.xyz/settings/api-keys) |
|
|
118
|
+
| **Mistral AI** | mistral-large, codestral | [console.mistral.ai](https://console.mistral.ai/api-keys/) |
|
|
119
|
+
| **Ollama** | Any local model — no API key needed | [ollama.com](https://ollama.com/library) |
|
|
120
|
+
| **Other** | Any OpenAI-compatible endpoint | — |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Configuration
|
|
125
|
+
|
|
126
|
+
All settings live in a `.env` file in your project directory. The setup wizard creates this on first run. You can edit it manually anytime — or re-run the wizard with `devpilot --setup`.
|
|
127
|
+
|
|
128
|
+
### Full settings reference
|
|
129
|
+
|
|
130
|
+
| Variable | Default | Description |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `ANTHROPIC_API_KEY` | — | API key for Anthropic provider |
|
|
133
|
+
| `OPENAI_API_KEY` | — | API key for OpenAI / Groq / Together / Mistral / Ollama |
|
|
134
|
+
| `DEVPILOT_PROVIDER` | `anthropic` | `anthropic` or `openai` |
|
|
135
|
+
| `DEVPILOT_MODEL` | `claude-opus-4-5` | Model name |
|
|
136
|
+
| `DEVPILOT_BASE_URL` | — | Custom endpoint, e.g. `http://localhost:11434/v1` for Ollama |
|
|
137
|
+
| `DEVPILOT_NO_CONFIRM` | `false` | Skip confirmation prompts (useful for CI) |
|
|
138
|
+
| `DEVPILOT_MAX_ITERATIONS` | `50` | Max tool-use iterations before loop aborts |
|
|
139
|
+
| `DEVPILOT_WORKDIR` | `cwd` | Root directory for file operations |
|
|
140
|
+
| `DEVPILOT_SESSIONS_DIR` | `.devpilot_sessions` | Where session JSON files are saved |
|
|
141
|
+
| `DEVPILOT_THINKING` | `false` | Enable extended thinking (Claude only) |
|
|
142
|
+
| `DEVPILOT_THINKING_BUDGET` | `10000` | Token budget for extended thinking |
|
|
143
|
+
|
|
144
|
+
### Override priority
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
CLI flags → env vars → .env file → defaults
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Per-run override example:
|
|
151
|
+
```bash
|
|
152
|
+
DEVPILOT_MODEL=claude-haiku-4-5-20251101 devpilot --task "fix typos"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## CLI Reference
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
devpilot [OPTIONS]
|
|
161
|
+
|
|
162
|
+
Options:
|
|
163
|
+
--provider {anthropic,openai} Model provider
|
|
164
|
+
--model MODEL Model name
|
|
165
|
+
--base-url URL OpenAI-compatible base URL (e.g. Ollama)
|
|
166
|
+
--no-confirm Skip confirmation prompts
|
|
167
|
+
--thinking Enable extended thinking (Claude only)
|
|
168
|
+
--thinking-budget N Token budget for extended thinking (default: 10000)
|
|
169
|
+
--workdir PATH Working directory for file operations
|
|
170
|
+
--task TASK Run a single task and exit (CI mode)
|
|
171
|
+
--resume SESSION_ID Resume a previous session
|
|
172
|
+
--a2a-port PORT A2A server port (default: 8000)
|
|
173
|
+
--no-a2a Disable A2A server
|
|
174
|
+
--no-web-search Disable Tavily web search
|
|
175
|
+
|
|
176
|
+
--setup Re-run the setup wizard
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### CI / single-task mode
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
devpilot --task "Run the test suite and fix any failures" --no-confirm
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Using Ollama (Local Models)
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Pull and serve a model
|
|
191
|
+
ollama pull qwen2.5-coder:7b
|
|
192
|
+
ollama serve
|
|
193
|
+
|
|
194
|
+
# Run devpilot and pick Ollama in the setup wizard
|
|
195
|
+
devpilot --setup
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Or set env vars directly:
|
|
199
|
+
```bash
|
|
200
|
+
DEVPILOT_PROVIDER=openai \
|
|
201
|
+
DEVPILOT_BASE_URL=http://localhost:11434/v1 \
|
|
202
|
+
DEVPILOT_MODEL=qwen2.5-coder:7b \
|
|
203
|
+
devpilot
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## MCP Integration
|
|
209
|
+
|
|
210
|
+
DevPilot connects to any [Model Context Protocol](https://modelcontextprotocol.io/) server. Edit `mcp_servers.json` in your project root:
|
|
211
|
+
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"mcpServers": {
|
|
215
|
+
"filesystem": {
|
|
216
|
+
"command": "npx",
|
|
217
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Tools from connected MCP servers are automatically available to the agent on startup.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Architecture
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
agent/
|
|
231
|
+
├── cli.py Entry point — args, setup wizard, wires everything
|
|
232
|
+
├── setup_wizard.py First-run interactive configuration wizard
|
|
233
|
+
├── loop.py Core agentic loop (plan → act → verify → heal)
|
|
234
|
+
├── config.py Config dataclass — all settings from env vars
|
|
235
|
+
├── context.py RepoContext — file awareness, AST map
|
|
236
|
+
├── history.py Conversation history + smart context pruning
|
|
237
|
+
├── providers/
|
|
238
|
+
│ ├── anthropic_provider.py
|
|
239
|
+
│ ├── openai_provider.py
|
|
240
|
+
│ ├── system_prompt.py PLAN→ACT→VERIFY prompt, platform-aware shell rules
|
|
241
|
+
│ └── factory.py
|
|
242
|
+
├── tools/
|
|
243
|
+
│ ├── fs.py read_file, write_file (pre-flight lint), edit_file, list_files
|
|
244
|
+
│ ├── shell.py run_bash
|
|
245
|
+
│ ├── search_code.py regex search
|
|
246
|
+
│ ├── git_ops.py git_status, git_commit
|
|
247
|
+
│ ├── doc_gen.py doc_gen
|
|
248
|
+
│ ├── diagram.py diagram (Mermaid)
|
|
249
|
+
│ ├── web_search.py web_search (Tavily)
|
|
250
|
+
|
|
251
|
+
│ ├── a2a.py A2A delegation
|
|
252
|
+
│ └── registry.py ToolRegistry + PermissionGuard
|
|
253
|
+
└── tui/
|
|
254
|
+
└── app.py Textual TUI — chat log, project map, tool drawer
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Running Tests
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
pip install devpilot-agentic-cli[dev]
|
|
263
|
+
pytest
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
48 tests — unit tests for every tool plus end-to-end integration tests with a mocked provider.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Development / Contributing
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
git clone https://github.com/Thijeshpraveen-V/DevPilot
|
|
274
|
+
cd DevPilot
|
|
275
|
+
pip install -e ".[dev]"
|
|
276
|
+
devpilot --setup
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
PR checklist:
|
|
280
|
+
- `pytest` passes (48 tests, 0 failures)
|
|
281
|
+
- No new hard dependencies without discussion
|
|
282
|
+
- New tools follow the `BaseTool` pattern in `agent/tools/base.py`
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## License
|
|
287
|
+
|
|
288
|
+
MIT © Thijesh Praveen V
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
agent/__init__.py,sha256=lfJPQT9NbRRWfa9YABD9u8apcLjs3tzDVZvrOb69GBQ,25
|
|
2
|
+
agent/a2a_client.py,sha256=vY4qZahkWP-DVU2smIeTz1xLj61kkDjE9Tmt_-9PKUU,3416
|
|
3
|
+
agent/a2a_server.py,sha256=3rkDy8dm49_5qCa6fKYkLdmHTnHs5ocHBuZ8j32-p48,5230
|
|
4
|
+
agent/cli.py,sha256=qhhBnJUKfzL7wlQOm9IP_S_0JdmpwESU4JMXDVZVGoU,8208
|
|
5
|
+
agent/config.py,sha256=GWS719hDNvvzgJAq9MF2FAGEVwM1AKA_B4WSDDzKEAg,10580
|
|
6
|
+
agent/context.py,sha256=a--jOYLX5jM-8RDLV0tAvZHOx9H5M6SNxSJipzEUZe4,7323
|
|
7
|
+
agent/history.py,sha256=IMY3IO5TN9Sh7tJPAWE9VZYC0pkAwgPj2a_F1yA4OmE,6730
|
|
8
|
+
agent/loop.py,sha256=8lTvCSAljPdmyyJ1uf0Q9qulUFNE3d4v3ZNzRae4c1w,3514
|
|
9
|
+
agent/mcp_client.py,sha256=vR09S4q5UrI4Ps3Uz7ZKdK4QN0UBJ3ouCtUrdJQZIIo,4416
|
|
10
|
+
agent/setup_wizard.py,sha256=jCXpp1vY9HRqJLO9eC6M9T6JlHXP7LsausmhkciB0d8,12774
|
|
11
|
+
agent/ui.py,sha256=pOavPs73WIT-fdROsN_h4KAcyr6qQxNhBfjoSwOos6o,8276
|
|
12
|
+
agent/providers/__init__.py,sha256=6xBg26vCBV2e3hybMT2JCHEZoRNpImkVOK-FytBW4xY,166
|
|
13
|
+
agent/providers/anthropic_provider.py,sha256=i257T8T7fYuUEVvsy-3_eudbjSlxZqbn3zi7DFvukRE,6067
|
|
14
|
+
agent/providers/base.py,sha256=2ppPB5ko9FrtS-U20E5rcKUQ1KAp6adnqmIRHdYONh4,5174
|
|
15
|
+
agent/providers/factory.py,sha256=dHVJlr6ZCBlPqcXw9VJVptj-3QZ4R0c3GzdGTxYmfPs,1197
|
|
16
|
+
agent/providers/openai_provider.py,sha256=CfbDIpUg0ca5E1yO6uP-VFLBn7ars8exJEIRlmyl90s,7550
|
|
17
|
+
agent/providers/system_prompt.py,sha256=WSn8XFnwEvrzAsCR_qPkLO1joUygI_y5fH_ZhpB3wts,6916
|
|
18
|
+
agent/tools/__init__.py,sha256=Rue1GAye0JI8ivLk-Duvvo1zFkHV-LrECSspP8l4tzE,315
|
|
19
|
+
agent/tools/a2a.py,sha256=CsB-0s5bcW4ms8YSfE7ngkobb3bFUGpMPxldem10jhI,1927
|
|
20
|
+
agent/tools/base.py,sha256=vYwZ9c7M7fh2ph9mw1fiLRHldDxjSmpppV5vWsMZd5c,1472
|
|
21
|
+
agent/tools/diagram.py,sha256=FpQRWud6GMi34ysjbEkqnvy5aaHOJwIvpmDELsyIqPE,4884
|
|
22
|
+
agent/tools/doc_gen.py,sha256=TaLw5JJ1hSgfViGyfYRMfUafjRTfxa0JYtZw0ycluR8,6064
|
|
23
|
+
agent/tools/fs.py,sha256=nBrGzq-yIzFcRzhPguBxJ9H23lhsUjGPzQXhwfrcQY0,16121
|
|
24
|
+
agent/tools/git_ops.py,sha256=CbulyzzSuFUQdAqu-6eMkg7CpB45h7nFP_5fxTecHeE,5505
|
|
25
|
+
agent/tools/registry.py,sha256=R6PsHIVqWyJwuFdC2EIm3GLdtTCr4j2S5BGWOTPanNA,8404
|
|
26
|
+
agent/tools/search_code.py,sha256=DwxT6D10OpWvIX7KR3-cRW1Z1MkLW2_WcJ47H_jfuHM,4490
|
|
27
|
+
agent/tools/shell.py,sha256=i9nar3gyS28p6wjfAljNREUll-7RiD_LhQQ_CDkz-CM,3923
|
|
28
|
+
agent/tools/web_search.py,sha256=7a533lYcRG0rwYle00xsIncfPRL1zCiS-wsL_qVxlyI,3736
|
|
29
|
+
agent/tui/__init__.py,sha256=FB4u1BY9RSmYVfCM2yMeCyMmzjnb9T0bhmPp9hHH8Ys,37
|
|
30
|
+
agent/tui/app.py,sha256=ZClXMLgXvohtLlYogKMpQISjEiFTHzNP6XPSeM6y4xU,18598
|
|
31
|
+
devpilot_agentic_cli-1.0.0.dist-info/METADATA,sha256=2deUrhlyQc90YKHuHF4wpfAo8Ry6mP8x0uA2ijt-pyU,11105
|
|
32
|
+
devpilot_agentic_cli-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
33
|
+
devpilot_agentic_cli-1.0.0.dist-info/entry_points.txt,sha256=Zi0zH4sqSQptehekvn5CBhU452GQ23Vyja4l8C58IuY,44
|
|
34
|
+
devpilot_agentic_cli-1.0.0.dist-info/top_level.txt,sha256=0gvCG7PHc22NA63j3bTGi2Zc37ym9t8Pf90ZLzf1kGA,6
|
|
35
|
+
devpilot_agentic_cli-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
agent
|