ollama-coding-agent 0.5.2__tar.gz → 0.5.3__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.
Files changed (24) hide show
  1. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/PKG-INFO +1 -1
  2. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/cli.py +28 -4
  3. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/config.py +1 -1
  4. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/ui.py +9 -1
  5. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/ollama_coding_agent.egg-info/PKG-INFO +1 -1
  6. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/pyproject.toml +1 -1
  7. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/LICENSE +0 -0
  8. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/PYPI_README.md +0 -0
  9. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/README.md +0 -0
  10. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/__init__.py +0 -0
  11. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/__main__.py +0 -0
  12. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/agent.py +0 -0
  13. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/intent.py +0 -0
  14. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/mcp_client.py +0 -0
  15. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/mcp_server.py +0 -0
  16. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/ollama_client.py +0 -0
  17. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/session_store.py +0 -0
  18. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/coding_agent/tools.py +0 -0
  19. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/ollama_coding_agent.egg-info/SOURCES.txt +0 -0
  20. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/ollama_coding_agent.egg-info/dependency_links.txt +0 -0
  21. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/ollama_coding_agent.egg-info/entry_points.txt +0 -0
  22. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/ollama_coding_agent.egg-info/requires.txt +0 -0
  23. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/ollama_coding_agent.egg-info/top_level.txt +0 -0
  24. {ollama_coding_agent-0.5.2 → ollama_coding_agent-0.5.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ollama-coding-agent
3
- Version: 0.5.2
3
+ Version: 0.5.3
4
4
  Summary: AI coding agent driving Qwen Coder (or any Ollama-compatible model) through a scoped toolset via MCP
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/HarryChen1995/coding_agent
@@ -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(25, "--max-steps", help="Hard cap on agent loop iterations"),
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.\n")
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 agent.run(task, resume_session_id=session_id, client=client,
283
- session_name=session_name, show_banner=False)
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 = 25 # hard cap on agent loop iterations
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.
@@ -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.[/dim]\n")
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ollama-coding-agent
3
- Version: 0.5.2
3
+ Version: 0.5.3
4
4
  Summary: AI coding agent driving Qwen Coder (or any Ollama-compatible model) through a scoped toolset via MCP
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/HarryChen1995/coding_agent
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ollama-coding-agent"
7
- version = "0.5.2"
7
+ version = "0.5.3"
8
8
  description = "AI coding agent driving Qwen Coder (or any Ollama-compatible model) through a scoped toolset via MCP"
9
9
  readme = "PYPI_README.md"
10
10
  requires-python = ">=3.10"