ollama-coding-agent 0.5.2__tar.gz → 0.5.4__tar.gz
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.
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/PKG-INFO +149 -149
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/agent.py +4 -1
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/cli.py +28 -4
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/config.py +1 -1
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/ollama_client.py +108 -73
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/ui.py +9 -1
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/ollama_coding_agent.egg-info/PKG-INFO +149 -149
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/pyproject.toml +35 -35
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/setup.cfg +4 -4
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/LICENSE +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/PYPI_README.md +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/README.md +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/__init__.py +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/__main__.py +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/intent.py +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/mcp_client.py +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/mcp_server.py +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/session_store.py +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/coding_agent/tools.py +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/ollama_coding_agent.egg-info/SOURCES.txt +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/ollama_coding_agent.egg-info/dependency_links.txt +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/ollama_coding_agent.egg-info/entry_points.txt +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/ollama_coding_agent.egg-info/requires.txt +0 -0
- {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/ollama_coding_agent.egg-info/top_level.txt +0 -0
|
@@ -1,149 +1,149 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: ollama-coding-agent
|
|
3
|
-
Version: 0.5.
|
|
4
|
-
Summary: AI coding agent driving Qwen Coder (or any Ollama-compatible model) through a scoped toolset via MCP
|
|
5
|
-
License-Expression: MIT
|
|
6
|
-
Project-URL: Homepage, https://github.com/HarryChen1995/coding_agent
|
|
7
|
-
Project-URL: Repository, https://github.com/HarryChen1995/coding_agent
|
|
8
|
-
Project-URL: Issues, https://github.com/HarryChen1995/coding_agent/issues
|
|
9
|
-
Classifier: Environment :: Console
|
|
10
|
-
Classifier: Intended Audience :: Developers
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Topic :: Software Development :: Build Tools
|
|
13
|
-
Requires-Python: >=3.10
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
License-File: LICENSE
|
|
16
|
-
Requires-Dist: httpx>=0.28
|
|
17
|
-
Requires-Dist: rich>=15.0
|
|
18
|
-
Requires-Dist: typer>=0.27
|
|
19
|
-
Requires-Dist: mcp>=1.27
|
|
20
|
-
Requires-Dist: prompt_toolkit>=3.0
|
|
21
|
-
Dynamic: license-file
|
|
22
|
-
|
|
23
|
-
# Ollama Coding Agent
|
|
24
|
-
|
|
25
|
-
An AI coding agent that plans, edits, and tests code by driving Qwen Coder
|
|
26
|
-
(or any Ollama-compatible model) through a scoped set of file and shell
|
|
27
|
-
tools, with human approval on every write, edit, or shell command.
|
|
28
|
-
|
|
29
|
-
## Install
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
pip install ollama-coding-agent
|
|
33
|
-
ollama pull qwen3-coder:30b
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Usage
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
coding-agent "Add type hints to utils.py, then run the test suite" \
|
|
40
|
-
--project-root ./myrepo
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Equivalent: `python -m coding_agent "..." --project-root ./myrepo`.
|
|
44
|
-
|
|
45
|
-
Omit the task string to enter an interactive session instead:
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
coding-agent --project-root ./myrepo
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Run `coding-agent --help` for the full option list.
|
|
52
|
-
|
|
53
|
-
## Features
|
|
54
|
-
|
|
55
|
-
- **Structured intent parsing** — the raw task is classified (bug fix,
|
|
56
|
-
feature, refactor, risk level, target files) before any action is taken,
|
|
57
|
-
and high-risk tasks force human approval even under `--auto-approve`.
|
|
58
|
-
- **Session persistence** — every message is saved to SQLite as the run
|
|
59
|
-
happens. Resume a previous run by id or a name you gave it
|
|
60
|
-
(`--resume`), browse saved sessions (`--list-sessions`), or delete one
|
|
61
|
-
(`--delete-session`).
|
|
62
|
-
- **Interactive mode** — drop into a REPL that keeps the model connection
|
|
63
|
-
and tool session alive across turns.
|
|
64
|
-
- **Human-in-the-loop approval** — every write, edit, or shell command
|
|
65
|
-
shows a diff or command preview before you confirm, unless explicitly
|
|
66
|
-
marked safe or run with `--auto-approve`.
|
|
67
|
-
- **Retry and recovery** — transient model failures retry with backoff;
|
|
68
|
-
malformed tool-call output is caught and reported back to the model
|
|
69
|
-
instead of crashing the run.
|
|
70
|
-
- **Codebase exploration tools** — regex content search with glob
|
|
71
|
-
filtering, pattern-based file discovery, directory listing, and git diff,
|
|
72
|
-
all skipping noise directories (`.git`, `node_modules`, build output).
|
|
73
|
-
- **Extensible via custom MCP servers** — point at any MCP server, local
|
|
74
|
-
(stdio) or remote (SSE / Streamable HTTP), and its tools merge into the
|
|
75
|
-
model's toolset automatically, no code changes required. Register one
|
|
76
|
-
permanently (`--add-mcp-server`, available on every future run) or add
|
|
77
|
-
one per run (`--mcp-server`/`--mcp-config`).
|
|
78
|
-
|
|
79
|
-
## Architecture
|
|
80
|
-
|
|
81
|
-
Tools are served over the Model Context Protocol (MCP), not called
|
|
82
|
-
in-process — the agent is an MCP *client* that talks to a tool server over
|
|
83
|
-
stdio:
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
+-----------------------------+
|
|
87
|
-
| CLI / REPL |
|
|
88
|
-
+-----------------------------+
|
|
89
|
-
|
|
|
90
|
-
v
|
|
91
|
-
+-----------------------------+
|
|
92
|
-
| Agent loop |
|
|
93
|
-
| parse intent, call model, |
|
|
94
|
-
| approve, execute, persist |
|
|
95
|
-
+-----------------------------+
|
|
96
|
-
|
|
|
97
|
-
v
|
|
98
|
-
+-----------------------------+
|
|
99
|
-
| MCP client |
|
|
100
|
-
| built-in + custom servers |
|
|
101
|
-
| merged into one tool list |
|
|
102
|
-
+-----------------------------+
|
|
103
|
-
|
|
|
104
|
-
stdio / SSE / streamable-http
|
|
105
|
-
v
|
|
106
|
-
+-----------------------------+
|
|
107
|
-
| MCP server(s) |
|
|
108
|
-
+-----------------------------+
|
|
109
|
-
|
|
|
110
|
-
v
|
|
111
|
-
+-----------------------------+
|
|
112
|
-
| Tools |
|
|
113
|
-
| read / write / edit / |
|
|
114
|
-
| search / shell |
|
|
115
|
-
+-----------------------------+
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Because tools are exposed over MCP, any MCP-compatible client — Claude
|
|
119
|
-
Desktop, another agent framework, a different model entirely — can reach
|
|
120
|
-
the exact same toolset, approval-preview logic, and path scoping. The
|
|
121
|
-
reverse also holds: any additional MCP server — local (stdio) or remote
|
|
122
|
-
(SSE / Streamable HTTP) — can be plugged into this agent, and its tools
|
|
123
|
-
merge into the same list the model already sees —
|
|
124
|
-
```bash
|
|
125
|
-
coding-agent --add-mcp-server "weather=python -m weather_mcp_server" # local, stdio
|
|
126
|
-
coding-agent --add-mcp-server "weather=https://example.com/mcp/sse" # remote, SSE
|
|
127
|
-
coding-agent "what's the forecast?" # picked up automatically, every run from here on
|
|
128
|
-
```
|
|
129
|
-
A value after `name=` starting with `http://`/`https://` is treated as a
|
|
130
|
-
remote server (SSE by default, append `,streamable_http` for that transport
|
|
131
|
-
instead); anything else is a local command spawned over stdio — it doesn't
|
|
132
|
-
need to be `-m`-invokable, a standalone script's absolute path works too
|
|
133
|
-
(e.g. `"myserver=python C:/absolute/path/to/mcp_server.py"`).
|
|
134
|
-
|
|
135
|
-
## Configuration
|
|
136
|
-
|
|
137
|
-
Point at any Ollama-compatible host with `--ollama-host` or the
|
|
138
|
-
`OLLAMA_HOST` env var. If it sits behind an authenticated proxy, set
|
|
139
|
-
`OLLAMA_API_KEY` as an environment variable rather than a CLI flag so the
|
|
140
|
-
key doesn't end up in shell history.
|
|
141
|
-
|
|
142
|
-
## Links
|
|
143
|
-
|
|
144
|
-
Source, full documentation, and issue tracker:
|
|
145
|
-
https://github.com/HarryChen1995/coding_agent
|
|
146
|
-
|
|
147
|
-
## License
|
|
148
|
-
|
|
149
|
-
MIT
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ollama-coding-agent
|
|
3
|
+
Version: 0.5.4
|
|
4
|
+
Summary: AI coding agent driving Qwen Coder (or any Ollama-compatible model) through a scoped toolset via MCP
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/HarryChen1995/coding_agent
|
|
7
|
+
Project-URL: Repository, https://github.com/HarryChen1995/coding_agent
|
|
8
|
+
Project-URL: Issues, https://github.com/HarryChen1995/coding_agent/issues
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: httpx>=0.28
|
|
17
|
+
Requires-Dist: rich>=15.0
|
|
18
|
+
Requires-Dist: typer>=0.27
|
|
19
|
+
Requires-Dist: mcp>=1.27
|
|
20
|
+
Requires-Dist: prompt_toolkit>=3.0
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# Ollama Coding Agent
|
|
24
|
+
|
|
25
|
+
An AI coding agent that plans, edits, and tests code by driving Qwen Coder
|
|
26
|
+
(or any Ollama-compatible model) through a scoped set of file and shell
|
|
27
|
+
tools, with human approval on every write, edit, or shell command.
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install ollama-coding-agent
|
|
33
|
+
ollama pull qwen3-coder:30b
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
coding-agent "Add type hints to utils.py, then run the test suite" \
|
|
40
|
+
--project-root ./myrepo
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Equivalent: `python -m coding_agent "..." --project-root ./myrepo`.
|
|
44
|
+
|
|
45
|
+
Omit the task string to enter an interactive session instead:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
coding-agent --project-root ./myrepo
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Run `coding-agent --help` for the full option list.
|
|
52
|
+
|
|
53
|
+
## Features
|
|
54
|
+
|
|
55
|
+
- **Structured intent parsing** — the raw task is classified (bug fix,
|
|
56
|
+
feature, refactor, risk level, target files) before any action is taken,
|
|
57
|
+
and high-risk tasks force human approval even under `--auto-approve`.
|
|
58
|
+
- **Session persistence** — every message is saved to SQLite as the run
|
|
59
|
+
happens. Resume a previous run by id or a name you gave it
|
|
60
|
+
(`--resume`), browse saved sessions (`--list-sessions`), or delete one
|
|
61
|
+
(`--delete-session`).
|
|
62
|
+
- **Interactive mode** — drop into a REPL that keeps the model connection
|
|
63
|
+
and tool session alive across turns.
|
|
64
|
+
- **Human-in-the-loop approval** — every write, edit, or shell command
|
|
65
|
+
shows a diff or command preview before you confirm, unless explicitly
|
|
66
|
+
marked safe or run with `--auto-approve`.
|
|
67
|
+
- **Retry and recovery** — transient model failures retry with backoff;
|
|
68
|
+
malformed tool-call output is caught and reported back to the model
|
|
69
|
+
instead of crashing the run.
|
|
70
|
+
- **Codebase exploration tools** — regex content search with glob
|
|
71
|
+
filtering, pattern-based file discovery, directory listing, and git diff,
|
|
72
|
+
all skipping noise directories (`.git`, `node_modules`, build output).
|
|
73
|
+
- **Extensible via custom MCP servers** — point at any MCP server, local
|
|
74
|
+
(stdio) or remote (SSE / Streamable HTTP), and its tools merge into the
|
|
75
|
+
model's toolset automatically, no code changes required. Register one
|
|
76
|
+
permanently (`--add-mcp-server`, available on every future run) or add
|
|
77
|
+
one per run (`--mcp-server`/`--mcp-config`).
|
|
78
|
+
|
|
79
|
+
## Architecture
|
|
80
|
+
|
|
81
|
+
Tools are served over the Model Context Protocol (MCP), not called
|
|
82
|
+
in-process — the agent is an MCP *client* that talks to a tool server over
|
|
83
|
+
stdio:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
+-----------------------------+
|
|
87
|
+
| CLI / REPL |
|
|
88
|
+
+-----------------------------+
|
|
89
|
+
|
|
|
90
|
+
v
|
|
91
|
+
+-----------------------------+
|
|
92
|
+
| Agent loop |
|
|
93
|
+
| parse intent, call model, |
|
|
94
|
+
| approve, execute, persist |
|
|
95
|
+
+-----------------------------+
|
|
96
|
+
|
|
|
97
|
+
v
|
|
98
|
+
+-----------------------------+
|
|
99
|
+
| MCP client |
|
|
100
|
+
| built-in + custom servers |
|
|
101
|
+
| merged into one tool list |
|
|
102
|
+
+-----------------------------+
|
|
103
|
+
|
|
|
104
|
+
stdio / SSE / streamable-http
|
|
105
|
+
v
|
|
106
|
+
+-----------------------------+
|
|
107
|
+
| MCP server(s) |
|
|
108
|
+
+-----------------------------+
|
|
109
|
+
|
|
|
110
|
+
v
|
|
111
|
+
+-----------------------------+
|
|
112
|
+
| Tools |
|
|
113
|
+
| read / write / edit / |
|
|
114
|
+
| search / shell |
|
|
115
|
+
+-----------------------------+
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Because tools are exposed over MCP, any MCP-compatible client — Claude
|
|
119
|
+
Desktop, another agent framework, a different model entirely — can reach
|
|
120
|
+
the exact same toolset, approval-preview logic, and path scoping. The
|
|
121
|
+
reverse also holds: any additional MCP server — local (stdio) or remote
|
|
122
|
+
(SSE / Streamable HTTP) — can be plugged into this agent, and its tools
|
|
123
|
+
merge into the same list the model already sees —
|
|
124
|
+
```bash
|
|
125
|
+
coding-agent --add-mcp-server "weather=python -m weather_mcp_server" # local, stdio
|
|
126
|
+
coding-agent --add-mcp-server "weather=https://example.com/mcp/sse" # remote, SSE
|
|
127
|
+
coding-agent "what's the forecast?" # picked up automatically, every run from here on
|
|
128
|
+
```
|
|
129
|
+
A value after `name=` starting with `http://`/`https://` is treated as a
|
|
130
|
+
remote server (SSE by default, append `,streamable_http` for that transport
|
|
131
|
+
instead); anything else is a local command spawned over stdio — it doesn't
|
|
132
|
+
need to be `-m`-invokable, a standalone script's absolute path works too
|
|
133
|
+
(e.g. `"myserver=python C:/absolute/path/to/mcp_server.py"`).
|
|
134
|
+
|
|
135
|
+
## Configuration
|
|
136
|
+
|
|
137
|
+
Point at any Ollama-compatible host with `--ollama-host` or the
|
|
138
|
+
`OLLAMA_HOST` env var. If it sits behind an authenticated proxy, set
|
|
139
|
+
`OLLAMA_API_KEY` as an environment variable rather than a CLI flag so the
|
|
140
|
+
key doesn't end up in shell history.
|
|
141
|
+
|
|
142
|
+
## Links
|
|
143
|
+
|
|
144
|
+
Source, full documentation, and issue tracker:
|
|
145
|
+
https://github.com/HarryChen1995/coding_agent
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
MIT
|
|
@@ -114,7 +114,10 @@ def _recover_text_tool_calls(content: str, tool_names: set) -> list:
|
|
|
114
114
|
calls.append({
|
|
115
115
|
"id": f"fallback_{len(calls)}",
|
|
116
116
|
"type": "function",
|
|
117
|
-
"function": {
|
|
117
|
+
"function": {
|
|
118
|
+
"name": name,
|
|
119
|
+
"arguments": json.dumps(args, ensure_ascii=False),
|
|
120
|
+
},
|
|
118
121
|
})
|
|
119
122
|
return calls
|
|
120
123
|
|
|
@@ -32,6 +32,7 @@ Examples:
|
|
|
32
32
|
|
|
33
33
|
import asyncio
|
|
34
34
|
import os
|
|
35
|
+
import signal
|
|
35
36
|
from contextlib import nullcontext
|
|
36
37
|
from typing import List, Optional
|
|
37
38
|
|
|
@@ -65,7 +66,7 @@ def main(
|
|
|
65
66
|
"(defaults to $OLLAMA_API_KEY — prefer the env var over this flag "
|
|
66
67
|
"so the key doesn't end up in your shell history).",
|
|
67
68
|
),
|
|
68
|
-
max_steps: int = typer.Option(
|
|
69
|
+
max_steps: int = typer.Option(100, "--max-steps", help="Hard cap on agent loop iterations"),
|
|
69
70
|
auto_approve: bool = typer.Option(
|
|
70
71
|
False, "--auto-approve",
|
|
71
72
|
help="Skip human approval for write/edit/shell tools. Only use in an "
|
|
@@ -243,7 +244,8 @@ async def _interactive(cfg: AgentConfig, resume: Optional[str], session_name: Op
|
|
|
243
244
|
# literal garbage like "?[32m" on the screen.
|
|
244
245
|
stdout_cm = patch_stdout(raw=True)
|
|
245
246
|
except ImportError:
|
|
246
|
-
typer.echo(f"Interactive mode (model: {cfg.model}). Type a task, /sessions to list, /exit to quit
|
|
247
|
+
typer.echo(f"Interactive mode (model: {cfg.model}). Type a task, /sessions to list, /exit to quit. "
|
|
248
|
+
"Ctrl+C interrupts the current turn without leaving the session.\n")
|
|
247
249
|
prompt_session = None
|
|
248
250
|
stdout_cm = nullcontext()
|
|
249
251
|
|
|
@@ -278,12 +280,34 @@ async def _interactive(cfg: AgentConfig, resume: Optional[str], session_name: Op
|
|
|
278
280
|
typer.echo(f"No session found with id or name {target!r}.", err=True)
|
|
279
281
|
continue
|
|
280
282
|
|
|
283
|
+
# Run the turn as a Task so Ctrl+C can cancel just this turn
|
|
284
|
+
# (via the SIGINT handler below) instead of killing the whole
|
|
285
|
+
# REPL — a raw KeyboardInterrupt raised inside asyncio's own
|
|
286
|
+
# blocking wait can otherwise escape uncaught past this loop
|
|
287
|
+
# entirely. task.cancel() injects CancelledError at the
|
|
288
|
+
# coroutine's next await point (model call, tool call, etc.),
|
|
289
|
+
# unwinding just that turn; the MCP client and session history
|
|
290
|
+
# already written to disk are untouched, so the REPL keeps going.
|
|
291
|
+
run_task = asyncio.ensure_future(
|
|
292
|
+
agent.run(task, resume_session_id=session_id, client=client,
|
|
293
|
+
session_name=session_name, show_banner=False)
|
|
294
|
+
)
|
|
295
|
+
previous_sigint = signal.signal(signal.SIGINT, lambda *_: run_task.cancel())
|
|
281
296
|
try:
|
|
282
|
-
result = await
|
|
283
|
-
|
|
297
|
+
result = await run_task
|
|
298
|
+
except asyncio.CancelledError:
|
|
299
|
+
session_id = agent.session_id or session_id
|
|
300
|
+
try:
|
|
301
|
+
from . import ui
|
|
302
|
+
ui.interrupted()
|
|
303
|
+
except ImportError:
|
|
304
|
+
typer.echo("\n[Interrupted — back to prompt. You can keep chatting in this session.]")
|
|
305
|
+
continue
|
|
284
306
|
except ValueError as e:
|
|
285
307
|
typer.echo(f"Error: {e}", err=True)
|
|
286
308
|
continue
|
|
309
|
+
finally:
|
|
310
|
+
signal.signal(signal.SIGINT, previous_sigint)
|
|
287
311
|
|
|
288
312
|
session_id = agent.session_id
|
|
289
313
|
|
|
@@ -23,7 +23,7 @@ class AgentConfig:
|
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
auto_approve: bool = False # True = never prompt (use in CI with care)
|
|
26
|
-
max_steps: int =
|
|
26
|
+
max_steps: int = 100 # hard cap on agent loop iterations
|
|
27
27
|
|
|
28
28
|
# Parse the freeform task into structured intent (task_type, target_files,
|
|
29
29
|
# constraints, risk_level) before the agent starts acting.
|
|
@@ -1,73 +1,108 @@
|
|
|
1
|
-
"""Talks to Ollama directly over HTTP (/api/chat) — no `ollama` python
|
|
2
|
-
package required, just httpx. Mirrors the message shape the rest of the
|
|
3
|
-
agent already expects: chat() returns the `message` dict with
|
|
4
|
-
role/content/tool_calls, same as the ollama library did.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
message
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
1
|
+
"""Talks to Ollama directly over HTTP (/api/chat) — no `ollama` python
|
|
2
|
+
package required, just httpx. Mirrors the message shape the rest of the
|
|
3
|
+
agent already expects: chat() returns the `message` dict with
|
|
4
|
+
role/content/tool_calls, same as the ollama library did.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
import httpx
|
|
11
|
+
|
|
12
|
+
DEFAULT_BASE_URL = os.environ.get("OLLAMA_HOST", "http://localhost:11434")
|
|
13
|
+
DEFAULT_API_KEY = os.environ.get("OLLAMA_API_KEY", "") # set via env, never hardcode
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _normalize_tool_call(call: dict) -> dict:
|
|
17
|
+
if not isinstance(call, dict) or call.get("type") != "function":
|
|
18
|
+
return call
|
|
19
|
+
|
|
20
|
+
function = call.get("function")
|
|
21
|
+
if not isinstance(function, dict):
|
|
22
|
+
return call
|
|
23
|
+
|
|
24
|
+
args = function.get("arguments")
|
|
25
|
+
if args is None or isinstance(args, str):
|
|
26
|
+
return call
|
|
27
|
+
|
|
28
|
+
normalized = function.copy()
|
|
29
|
+
normalized["arguments"] = json.dumps(args, ensure_ascii=False)
|
|
30
|
+
return {**call, "function": normalized}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _normalize_messages(messages: list) -> list:
|
|
34
|
+
normalized = []
|
|
35
|
+
for msg in messages:
|
|
36
|
+
if not isinstance(msg, dict):
|
|
37
|
+
normalized.append(msg)
|
|
38
|
+
continue
|
|
39
|
+
tool_calls = msg.get("tool_calls")
|
|
40
|
+
if isinstance(tool_calls, list):
|
|
41
|
+
normalized.append({
|
|
42
|
+
**msg,
|
|
43
|
+
"tool_calls": [_normalize_tool_call(call) for call in tool_calls],
|
|
44
|
+
})
|
|
45
|
+
else:
|
|
46
|
+
normalized.append(msg)
|
|
47
|
+
return normalized
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class OllamaError(Exception):
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
async def chat(
|
|
55
|
+
model: str,
|
|
56
|
+
messages: list,
|
|
57
|
+
tools: list = None,
|
|
58
|
+
format: str = None,
|
|
59
|
+
base_url: str = None,
|
|
60
|
+
api_key: str = None,
|
|
61
|
+
timeout: float = 120.0,
|
|
62
|
+
) -> dict:
|
|
63
|
+
"""POST /api/v1/chat/completions (OpenAI-compatible) with stream=false
|
|
64
|
+
and return the `message` dict.
|
|
65
|
+
|
|
66
|
+
This hits our Open WebUI gateway in front of Ollama, not Ollama's native
|
|
67
|
+
/api/chat — the gateway only exposes the OpenAI-style route. Response
|
|
68
|
+
shape is `choices[0].message`, but that dict already has the
|
|
69
|
+
role/content/tool_calls keys the rest of the agent expects, same as
|
|
70
|
+
Ollama's native `message` field would.
|
|
71
|
+
|
|
72
|
+
If an API key is set (via `api_key`, falling back to $OLLAMA_API_KEY),
|
|
73
|
+
it's sent as `Authorization: Bearer <key>`.
|
|
74
|
+
|
|
75
|
+
Raises OllamaError on a non-2xx response, a connection failure, or an
|
|
76
|
+
unexpected response shape — callers (agent.py, intent.py) already retry
|
|
77
|
+
on this.
|
|
78
|
+
"""
|
|
79
|
+
url = f"{(base_url or DEFAULT_BASE_URL).rstrip('/')}/v1/chat/completions"
|
|
80
|
+
payload = {"model": model, "messages": _normalize_messages(messages), "stream": False}
|
|
81
|
+
if tools:
|
|
82
|
+
payload["tools"] = tools
|
|
83
|
+
if format == "json":
|
|
84
|
+
payload["response_format"] = {"type": "json_object"}
|
|
85
|
+
|
|
86
|
+
key = api_key or DEFAULT_API_KEY
|
|
87
|
+
headers = {"Authorization": f"Bearer {key}"} if key else {}
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
async with httpx.AsyncClient(timeout=timeout) as client:
|
|
91
|
+
resp = await client.post(url, json=payload, headers=headers)
|
|
92
|
+
resp.raise_for_status()
|
|
93
|
+
data = resp.json()
|
|
94
|
+
except httpx.HTTPStatusError as e:
|
|
95
|
+
body = e.response.text[:300]
|
|
96
|
+
raise OllamaError(f"Ollama API returned {e.response.status_code} for {model}: {body}") from e
|
|
97
|
+
except httpx.RequestError as e:
|
|
98
|
+
raise OllamaError(
|
|
99
|
+
f"Could not reach Ollama at {url} ({e}). Is `ollama serve` running?"
|
|
100
|
+
) from e
|
|
101
|
+
|
|
102
|
+
choices = data.get("choices")
|
|
103
|
+
if not choices:
|
|
104
|
+
raise OllamaError(f"Unexpected response shape from Ollama (no 'choices' key): {data}")
|
|
105
|
+
message = choices[0].get("message")
|
|
106
|
+
if message is None:
|
|
107
|
+
raise OllamaError(f"Unexpected response shape from Ollama (no 'message' key): {data}")
|
|
108
|
+
return message
|
|
@@ -44,7 +44,8 @@ def interactive_banner(model: str, resumed: str = None):
|
|
|
44
44
|
console.print(f"[dim]model:[/dim] {model}")
|
|
45
45
|
if resumed:
|
|
46
46
|
console.print(f"[dim]resuming session:[/dim] {resumed}")
|
|
47
|
-
console.print("[dim]Type a task, /sessions to list saved sessions, /exit to quit.
|
|
47
|
+
console.print("[dim]Type a task, /sessions to list saved sessions, /exit to quit. "
|
|
48
|
+
"Ctrl+C interrupts the current turn without leaving the session.[/dim]\n")
|
|
48
49
|
|
|
49
50
|
|
|
50
51
|
async def prompt_task_async(session) -> str:
|
|
@@ -226,6 +227,13 @@ def sessions_table(sessions: list):
|
|
|
226
227
|
console.print(table)
|
|
227
228
|
|
|
228
229
|
|
|
230
|
+
def interrupted():
|
|
231
|
+
console.print(
|
|
232
|
+
"\n[yellow]⏹ Interrupted — back at the prompt. Progress up to the last "
|
|
233
|
+
"completed step was saved; keep chatting or ask the agent to continue.[/yellow]"
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
229
237
|
def warning(text: str):
|
|
230
238
|
console.print(f"[yellow]⚠ {text}[/yellow]")
|
|
231
239
|
|
{ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/ollama_coding_agent.egg-info/PKG-INFO
RENAMED
|
@@ -1,149 +1,149 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: ollama-coding-agent
|
|
3
|
-
Version: 0.5.
|
|
4
|
-
Summary: AI coding agent driving Qwen Coder (or any Ollama-compatible model) through a scoped toolset via MCP
|
|
5
|
-
License-Expression: MIT
|
|
6
|
-
Project-URL: Homepage, https://github.com/HarryChen1995/coding_agent
|
|
7
|
-
Project-URL: Repository, https://github.com/HarryChen1995/coding_agent
|
|
8
|
-
Project-URL: Issues, https://github.com/HarryChen1995/coding_agent/issues
|
|
9
|
-
Classifier: Environment :: Console
|
|
10
|
-
Classifier: Intended Audience :: Developers
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Topic :: Software Development :: Build Tools
|
|
13
|
-
Requires-Python: >=3.10
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
License-File: LICENSE
|
|
16
|
-
Requires-Dist: httpx>=0.28
|
|
17
|
-
Requires-Dist: rich>=15.0
|
|
18
|
-
Requires-Dist: typer>=0.27
|
|
19
|
-
Requires-Dist: mcp>=1.27
|
|
20
|
-
Requires-Dist: prompt_toolkit>=3.0
|
|
21
|
-
Dynamic: license-file
|
|
22
|
-
|
|
23
|
-
# Ollama Coding Agent
|
|
24
|
-
|
|
25
|
-
An AI coding agent that plans, edits, and tests code by driving Qwen Coder
|
|
26
|
-
(or any Ollama-compatible model) through a scoped set of file and shell
|
|
27
|
-
tools, with human approval on every write, edit, or shell command.
|
|
28
|
-
|
|
29
|
-
## Install
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
pip install ollama-coding-agent
|
|
33
|
-
ollama pull qwen3-coder:30b
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Usage
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
coding-agent "Add type hints to utils.py, then run the test suite" \
|
|
40
|
-
--project-root ./myrepo
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Equivalent: `python -m coding_agent "..." --project-root ./myrepo`.
|
|
44
|
-
|
|
45
|
-
Omit the task string to enter an interactive session instead:
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
coding-agent --project-root ./myrepo
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Run `coding-agent --help` for the full option list.
|
|
52
|
-
|
|
53
|
-
## Features
|
|
54
|
-
|
|
55
|
-
- **Structured intent parsing** — the raw task is classified (bug fix,
|
|
56
|
-
feature, refactor, risk level, target files) before any action is taken,
|
|
57
|
-
and high-risk tasks force human approval even under `--auto-approve`.
|
|
58
|
-
- **Session persistence** — every message is saved to SQLite as the run
|
|
59
|
-
happens. Resume a previous run by id or a name you gave it
|
|
60
|
-
(`--resume`), browse saved sessions (`--list-sessions`), or delete one
|
|
61
|
-
(`--delete-session`).
|
|
62
|
-
- **Interactive mode** — drop into a REPL that keeps the model connection
|
|
63
|
-
and tool session alive across turns.
|
|
64
|
-
- **Human-in-the-loop approval** — every write, edit, or shell command
|
|
65
|
-
shows a diff or command preview before you confirm, unless explicitly
|
|
66
|
-
marked safe or run with `--auto-approve`.
|
|
67
|
-
- **Retry and recovery** — transient model failures retry with backoff;
|
|
68
|
-
malformed tool-call output is caught and reported back to the model
|
|
69
|
-
instead of crashing the run.
|
|
70
|
-
- **Codebase exploration tools** — regex content search with glob
|
|
71
|
-
filtering, pattern-based file discovery, directory listing, and git diff,
|
|
72
|
-
all skipping noise directories (`.git`, `node_modules`, build output).
|
|
73
|
-
- **Extensible via custom MCP servers** — point at any MCP server, local
|
|
74
|
-
(stdio) or remote (SSE / Streamable HTTP), and its tools merge into the
|
|
75
|
-
model's toolset automatically, no code changes required. Register one
|
|
76
|
-
permanently (`--add-mcp-server`, available on every future run) or add
|
|
77
|
-
one per run (`--mcp-server`/`--mcp-config`).
|
|
78
|
-
|
|
79
|
-
## Architecture
|
|
80
|
-
|
|
81
|
-
Tools are served over the Model Context Protocol (MCP), not called
|
|
82
|
-
in-process — the agent is an MCP *client* that talks to a tool server over
|
|
83
|
-
stdio:
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
+-----------------------------+
|
|
87
|
-
| CLI / REPL |
|
|
88
|
-
+-----------------------------+
|
|
89
|
-
|
|
|
90
|
-
v
|
|
91
|
-
+-----------------------------+
|
|
92
|
-
| Agent loop |
|
|
93
|
-
| parse intent, call model, |
|
|
94
|
-
| approve, execute, persist |
|
|
95
|
-
+-----------------------------+
|
|
96
|
-
|
|
|
97
|
-
v
|
|
98
|
-
+-----------------------------+
|
|
99
|
-
| MCP client |
|
|
100
|
-
| built-in + custom servers |
|
|
101
|
-
| merged into one tool list |
|
|
102
|
-
+-----------------------------+
|
|
103
|
-
|
|
|
104
|
-
stdio / SSE / streamable-http
|
|
105
|
-
v
|
|
106
|
-
+-----------------------------+
|
|
107
|
-
| MCP server(s) |
|
|
108
|
-
+-----------------------------+
|
|
109
|
-
|
|
|
110
|
-
v
|
|
111
|
-
+-----------------------------+
|
|
112
|
-
| Tools |
|
|
113
|
-
| read / write / edit / |
|
|
114
|
-
| search / shell |
|
|
115
|
-
+-----------------------------+
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Because tools are exposed over MCP, any MCP-compatible client — Claude
|
|
119
|
-
Desktop, another agent framework, a different model entirely — can reach
|
|
120
|
-
the exact same toolset, approval-preview logic, and path scoping. The
|
|
121
|
-
reverse also holds: any additional MCP server — local (stdio) or remote
|
|
122
|
-
(SSE / Streamable HTTP) — can be plugged into this agent, and its tools
|
|
123
|
-
merge into the same list the model already sees —
|
|
124
|
-
```bash
|
|
125
|
-
coding-agent --add-mcp-server "weather=python -m weather_mcp_server" # local, stdio
|
|
126
|
-
coding-agent --add-mcp-server "weather=https://example.com/mcp/sse" # remote, SSE
|
|
127
|
-
coding-agent "what's the forecast?" # picked up automatically, every run from here on
|
|
128
|
-
```
|
|
129
|
-
A value after `name=` starting with `http://`/`https://` is treated as a
|
|
130
|
-
remote server (SSE by default, append `,streamable_http` for that transport
|
|
131
|
-
instead); anything else is a local command spawned over stdio — it doesn't
|
|
132
|
-
need to be `-m`-invokable, a standalone script's absolute path works too
|
|
133
|
-
(e.g. `"myserver=python C:/absolute/path/to/mcp_server.py"`).
|
|
134
|
-
|
|
135
|
-
## Configuration
|
|
136
|
-
|
|
137
|
-
Point at any Ollama-compatible host with `--ollama-host` or the
|
|
138
|
-
`OLLAMA_HOST` env var. If it sits behind an authenticated proxy, set
|
|
139
|
-
`OLLAMA_API_KEY` as an environment variable rather than a CLI flag so the
|
|
140
|
-
key doesn't end up in shell history.
|
|
141
|
-
|
|
142
|
-
## Links
|
|
143
|
-
|
|
144
|
-
Source, full documentation, and issue tracker:
|
|
145
|
-
https://github.com/HarryChen1995/coding_agent
|
|
146
|
-
|
|
147
|
-
## License
|
|
148
|
-
|
|
149
|
-
MIT
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ollama-coding-agent
|
|
3
|
+
Version: 0.5.4
|
|
4
|
+
Summary: AI coding agent driving Qwen Coder (or any Ollama-compatible model) through a scoped toolset via MCP
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/HarryChen1995/coding_agent
|
|
7
|
+
Project-URL: Repository, https://github.com/HarryChen1995/coding_agent
|
|
8
|
+
Project-URL: Issues, https://github.com/HarryChen1995/coding_agent/issues
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: httpx>=0.28
|
|
17
|
+
Requires-Dist: rich>=15.0
|
|
18
|
+
Requires-Dist: typer>=0.27
|
|
19
|
+
Requires-Dist: mcp>=1.27
|
|
20
|
+
Requires-Dist: prompt_toolkit>=3.0
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# Ollama Coding Agent
|
|
24
|
+
|
|
25
|
+
An AI coding agent that plans, edits, and tests code by driving Qwen Coder
|
|
26
|
+
(or any Ollama-compatible model) through a scoped set of file and shell
|
|
27
|
+
tools, with human approval on every write, edit, or shell command.
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install ollama-coding-agent
|
|
33
|
+
ollama pull qwen3-coder:30b
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
coding-agent "Add type hints to utils.py, then run the test suite" \
|
|
40
|
+
--project-root ./myrepo
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Equivalent: `python -m coding_agent "..." --project-root ./myrepo`.
|
|
44
|
+
|
|
45
|
+
Omit the task string to enter an interactive session instead:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
coding-agent --project-root ./myrepo
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Run `coding-agent --help` for the full option list.
|
|
52
|
+
|
|
53
|
+
## Features
|
|
54
|
+
|
|
55
|
+
- **Structured intent parsing** — the raw task is classified (bug fix,
|
|
56
|
+
feature, refactor, risk level, target files) before any action is taken,
|
|
57
|
+
and high-risk tasks force human approval even under `--auto-approve`.
|
|
58
|
+
- **Session persistence** — every message is saved to SQLite as the run
|
|
59
|
+
happens. Resume a previous run by id or a name you gave it
|
|
60
|
+
(`--resume`), browse saved sessions (`--list-sessions`), or delete one
|
|
61
|
+
(`--delete-session`).
|
|
62
|
+
- **Interactive mode** — drop into a REPL that keeps the model connection
|
|
63
|
+
and tool session alive across turns.
|
|
64
|
+
- **Human-in-the-loop approval** — every write, edit, or shell command
|
|
65
|
+
shows a diff or command preview before you confirm, unless explicitly
|
|
66
|
+
marked safe or run with `--auto-approve`.
|
|
67
|
+
- **Retry and recovery** — transient model failures retry with backoff;
|
|
68
|
+
malformed tool-call output is caught and reported back to the model
|
|
69
|
+
instead of crashing the run.
|
|
70
|
+
- **Codebase exploration tools** — regex content search with glob
|
|
71
|
+
filtering, pattern-based file discovery, directory listing, and git diff,
|
|
72
|
+
all skipping noise directories (`.git`, `node_modules`, build output).
|
|
73
|
+
- **Extensible via custom MCP servers** — point at any MCP server, local
|
|
74
|
+
(stdio) or remote (SSE / Streamable HTTP), and its tools merge into the
|
|
75
|
+
model's toolset automatically, no code changes required. Register one
|
|
76
|
+
permanently (`--add-mcp-server`, available on every future run) or add
|
|
77
|
+
one per run (`--mcp-server`/`--mcp-config`).
|
|
78
|
+
|
|
79
|
+
## Architecture
|
|
80
|
+
|
|
81
|
+
Tools are served over the Model Context Protocol (MCP), not called
|
|
82
|
+
in-process — the agent is an MCP *client* that talks to a tool server over
|
|
83
|
+
stdio:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
+-----------------------------+
|
|
87
|
+
| CLI / REPL |
|
|
88
|
+
+-----------------------------+
|
|
89
|
+
|
|
|
90
|
+
v
|
|
91
|
+
+-----------------------------+
|
|
92
|
+
| Agent loop |
|
|
93
|
+
| parse intent, call model, |
|
|
94
|
+
| approve, execute, persist |
|
|
95
|
+
+-----------------------------+
|
|
96
|
+
|
|
|
97
|
+
v
|
|
98
|
+
+-----------------------------+
|
|
99
|
+
| MCP client |
|
|
100
|
+
| built-in + custom servers |
|
|
101
|
+
| merged into one tool list |
|
|
102
|
+
+-----------------------------+
|
|
103
|
+
|
|
|
104
|
+
stdio / SSE / streamable-http
|
|
105
|
+
v
|
|
106
|
+
+-----------------------------+
|
|
107
|
+
| MCP server(s) |
|
|
108
|
+
+-----------------------------+
|
|
109
|
+
|
|
|
110
|
+
v
|
|
111
|
+
+-----------------------------+
|
|
112
|
+
| Tools |
|
|
113
|
+
| read / write / edit / |
|
|
114
|
+
| search / shell |
|
|
115
|
+
+-----------------------------+
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Because tools are exposed over MCP, any MCP-compatible client — Claude
|
|
119
|
+
Desktop, another agent framework, a different model entirely — can reach
|
|
120
|
+
the exact same toolset, approval-preview logic, and path scoping. The
|
|
121
|
+
reverse also holds: any additional MCP server — local (stdio) or remote
|
|
122
|
+
(SSE / Streamable HTTP) — can be plugged into this agent, and its tools
|
|
123
|
+
merge into the same list the model already sees —
|
|
124
|
+
```bash
|
|
125
|
+
coding-agent --add-mcp-server "weather=python -m weather_mcp_server" # local, stdio
|
|
126
|
+
coding-agent --add-mcp-server "weather=https://example.com/mcp/sse" # remote, SSE
|
|
127
|
+
coding-agent "what's the forecast?" # picked up automatically, every run from here on
|
|
128
|
+
```
|
|
129
|
+
A value after `name=` starting with `http://`/`https://` is treated as a
|
|
130
|
+
remote server (SSE by default, append `,streamable_http` for that transport
|
|
131
|
+
instead); anything else is a local command spawned over stdio — it doesn't
|
|
132
|
+
need to be `-m`-invokable, a standalone script's absolute path works too
|
|
133
|
+
(e.g. `"myserver=python C:/absolute/path/to/mcp_server.py"`).
|
|
134
|
+
|
|
135
|
+
## Configuration
|
|
136
|
+
|
|
137
|
+
Point at any Ollama-compatible host with `--ollama-host` or the
|
|
138
|
+
`OLLAMA_HOST` env var. If it sits behind an authenticated proxy, set
|
|
139
|
+
`OLLAMA_API_KEY` as an environment variable rather than a CLI flag so the
|
|
140
|
+
key doesn't end up in shell history.
|
|
141
|
+
|
|
142
|
+
## Links
|
|
143
|
+
|
|
144
|
+
Source, full documentation, and issue tracker:
|
|
145
|
+
https://github.com/HarryChen1995/coding_agent
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
MIT
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=68"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "ollama-coding-agent"
|
|
7
|
-
version = "0.5.
|
|
8
|
-
description = "AI coding agent driving Qwen Coder (or any Ollama-compatible model) through a scoped toolset via MCP"
|
|
9
|
-
readme = "PYPI_README.md"
|
|
10
|
-
requires-python = ">=3.10"
|
|
11
|
-
license = "MIT"
|
|
12
|
-
classifiers = [
|
|
13
|
-
"Environment :: Console",
|
|
14
|
-
"Intended Audience :: Developers",
|
|
15
|
-
"Programming Language :: Python :: 3",
|
|
16
|
-
"Topic :: Software Development :: Build Tools",
|
|
17
|
-
]
|
|
18
|
-
dependencies = [
|
|
19
|
-
"httpx>=0.28",
|
|
20
|
-
"rich>=15.0",
|
|
21
|
-
"typer>=0.27",
|
|
22
|
-
"mcp>=1.27",
|
|
23
|
-
"prompt_toolkit>=3.0",
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
[project.urls]
|
|
27
|
-
Homepage = "https://github.com/HarryChen1995/coding_agent"
|
|
28
|
-
Repository = "https://github.com/HarryChen1995/coding_agent"
|
|
29
|
-
Issues = "https://github.com/HarryChen1995/coding_agent/issues"
|
|
30
|
-
|
|
31
|
-
[project.scripts]
|
|
32
|
-
coding-agent = "coding_agent.cli:app"
|
|
33
|
-
|
|
34
|
-
[tool.setuptools.packages.find]
|
|
35
|
-
include = ["coding_agent*"]
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ollama-coding-agent"
|
|
7
|
+
version = "0.5.4"
|
|
8
|
+
description = "AI coding agent driving Qwen Coder (or any Ollama-compatible model) through a scoped toolset via MCP"
|
|
9
|
+
readme = "PYPI_README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Topic :: Software Development :: Build Tools",
|
|
17
|
+
]
|
|
18
|
+
dependencies = [
|
|
19
|
+
"httpx>=0.28",
|
|
20
|
+
"rich>=15.0",
|
|
21
|
+
"typer>=0.27",
|
|
22
|
+
"mcp>=1.27",
|
|
23
|
+
"prompt_toolkit>=3.0",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/HarryChen1995/coding_agent"
|
|
28
|
+
Repository = "https://github.com/HarryChen1995/coding_agent"
|
|
29
|
+
Issues = "https://github.com/HarryChen1995/coding_agent/issues"
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
coding-agent = "coding_agent.cli:app"
|
|
33
|
+
|
|
34
|
+
[tool.setuptools.packages.find]
|
|
35
|
+
include = ["coding_agent*"]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[egg_info]
|
|
2
|
-
tag_build =
|
|
3
|
-
tag_date = 0
|
|
4
|
-
|
|
1
|
+
[egg_info]
|
|
2
|
+
tag_build =
|
|
3
|
+
tag_date = 0
|
|
4
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/ollama_coding_agent.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/ollama_coding_agent.egg-info/requires.txt
RENAMED
|
File without changes
|
{ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.4}/ollama_coding_agent.egg-info/top_level.txt
RENAMED
|
File without changes
|