agentic-python-coder 3.4.1__py3-none-any.whl → 3.4.3__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.
@@ -19,6 +19,55 @@ from agentic_python_coder.tools import (
19
19
  # Default maximum number of steps the agent can take before stopping
20
20
  DEFAULT_STEP_LIMIT = 200
21
21
 
22
+ # Retries for API error responses the OpenAI SDK parses without raising:
23
+ # OpenRouter intermittently returns HTTP 200 whose body is an error object
24
+ # ({"choices": null, "error": {...}}), or a choice with finish_reason "error"
25
+ API_ERROR_MAX_RETRIES = 3
26
+ API_ERROR_BACKOFF_SECONDS = 5
27
+
28
+
29
+ def _response_error(response) -> Optional[str]:
30
+ """Return a description if the response is an error envelope, else None."""
31
+ if not response.choices:
32
+ error = (getattr(response, "model_extra", None) or {}).get("error")
33
+ if error:
34
+ return f"no choices, error: {error}"
35
+ dump = getattr(response, "model_dump_json", None)
36
+ body = dump() if callable(dump) else repr(response)
37
+ return f"no choices, body: {body[:500]}"
38
+ choice = response.choices[0]
39
+ if choice.finish_reason == "error":
40
+ error = (getattr(choice, "model_extra", None) or {}).get("error") or (
41
+ getattr(response, "model_extra", None) or {}
42
+ ).get("error")
43
+ return f"finish_reason 'error', error: {error}"
44
+ return None
45
+
46
+
47
+ def _create_with_retry(llm_config: LLMConfig, request_kwargs: dict, quiet: bool):
48
+ """Call the completions API, retrying error responses.
49
+
50
+ Raises RuntimeError when retries are exhausted, so callers see a failure
51
+ instead of a silent early stop reported as success.
52
+ """
53
+ detail = ""
54
+ for attempt in range(API_ERROR_MAX_RETRIES + 1):
55
+ response = llm_config.client.chat.completions.create(**request_kwargs)
56
+ detail = _response_error(response)
57
+ if detail is None:
58
+ return response
59
+ if not quiet:
60
+ print(
61
+ f"Warning: API returned an error response "
62
+ f"(attempt {attempt + 1}/{API_ERROR_MAX_RETRIES + 1}); {detail}"
63
+ )
64
+ if attempt < API_ERROR_MAX_RETRIES:
65
+ time.sleep(API_ERROR_BACKOFF_SECONDS * (attempt + 1))
66
+ raise RuntimeError(
67
+ f"API returned error responses on {API_ERROR_MAX_RETRIES + 1} attempts; "
68
+ f"last: {detail}"
69
+ )
70
+
22
71
 
23
72
  def load_prompt(prompt_path: Path) -> str:
24
73
  """Load a prompt from file."""
@@ -246,8 +295,8 @@ def run_agent(
246
295
  request_kwargs["tools"] = openai_tools
247
296
  request_kwargs["tool_choice"] = "auto"
248
297
 
249
- # Call API
250
- response = agent.llm_config.client.chat.completions.create(**request_kwargs)
298
+ # Call API (retries transient error responses, raises if they persist)
299
+ response = _create_with_retry(agent.llm_config, request_kwargs, quiet)
251
300
 
252
301
  # Track tokens (some providers return usage objects with None fields)
253
302
  if response.usage:
@@ -261,9 +310,6 @@ def run_agent(
261
310
  response.usage.total_tokens or 0
262
311
  )
263
312
 
264
- if not response.choices:
265
- break
266
-
267
313
  assistant_message = response.choices[0].message
268
314
 
269
315
  # Check for tool calls
@@ -8,6 +8,8 @@ from pathlib import Path
8
8
  from typing import Optional, Dict, Any
9
9
  from importlib import resources
10
10
 
11
+ from openai import AuthenticationError
12
+
11
13
  from agentic_python_coder.runner import (
12
14
  solve_task,
13
15
  get_system_prompt_path,
@@ -485,6 +487,10 @@ def main():
485
487
  display_statistics(stats)
486
488
  print(f"Log saved to: {log_path}")
487
489
 
490
+ except (ValueError, AuthenticationError) as e:
491
+ # Configuration errors (missing or invalid API key): no traceback
492
+ print(f"Error: {e}")
493
+ sys.exit(1)
488
494
  except Exception as e:
489
495
  print(f"Error: {e}")
490
496
  import traceback
@@ -11,6 +11,7 @@ import os
11
11
  import re
12
12
  import shutil
13
13
  import signal
14
+ import sys
14
15
  import threading
15
16
  import time
16
17
  import uuid
@@ -101,6 +102,10 @@ class UVKernelManager(KernelManager):
101
102
  # Don't load project dependencies (create clean environment)
102
103
  uv_prefix.append("--no-project")
103
104
 
105
+ # Match the host's Python; uv's default may be a newer version for
106
+ # which packages (e.g. ortools) have no wheels yet
107
+ uv_prefix.extend(["--python", f"{sys.version_info[0]}.{sys.version_info[1]}"])
108
+
104
109
  # Add user-specified packages
105
110
  for pkg in self.with_packages:
106
111
  uv_prefix.extend(["--with", pkg])
@@ -175,9 +180,8 @@ class PythonKernel:
175
180
 
176
181
  # Wait for kernel to be ready
177
182
  logger.debug("Waiting for kernel to be ready...")
178
- self.kc.wait_for_ready(
179
- timeout=30
180
- ) # Increased timeout for UV package installation
183
+ # Generous timeout: a cold uv cache or a source build can take minutes
184
+ self.kc.wait_for_ready(timeout=180)
181
185
  logger.info("Kernel started successfully")
182
186
 
183
187
  # Configure IPython and inject startup code
@@ -11,7 +11,7 @@ from dotenv import load_dotenv
11
11
  from openai import OpenAI
12
12
 
13
13
  # Default model name (without .json)
14
- DEFAULT_MODEL = "sonnet45"
14
+ DEFAULT_MODEL = "sonnet55"
15
15
 
16
16
 
17
17
  @dataclass
@@ -0,0 +1,6 @@
1
+ {
2
+ "path": "google/gemini-4-argon",
3
+ "temperature": 0.0,
4
+ "max_tokens": 16384,
5
+ "request_timeout": 120
6
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "path": "openai/gpt-6-astra",
3
+ "max_tokens": 16384,
4
+ "no_sampling_params": true
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "path": "openai/gpt-6-sol",
3
+ "max_tokens": 16384,
4
+ "no_sampling_params": true
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "path": "x-ai/grok-4.7",
3
+ "temperature": 0.0,
4
+ "max_tokens": 16384
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "path": "anthropic/claude-opus-5.5",
3
+ "max_tokens": 32768,
4
+ "no_sampling_params": true
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "path": "anthropic/claude-sonnet-5.5",
3
+ "max_tokens": 32768,
4
+ "no_sampling_params": true
5
+ }
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: agentic-python-coder
3
- Version: 3.4.1
3
+ Version: 3.4.3
4
4
  Summary: A lightweight Python coding agent that writes, executes, and iterates on code through natural language instructions
5
5
  Author: Stefan Szeider
6
6
  License: Apache-2.0
@@ -11,12 +11,14 @@ Classifier: Intended Audience :: Developers
11
11
  Classifier: License :: OSI Approved :: Apache Software License
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Programming Language :: Python :: 3.15
14
16
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
17
  Classifier: Topic :: Software Development :: Code Generators
16
- Requires-Python: <3.14,>=3.13
18
+ Requires-Python: >=3.13
17
19
  Requires-Dist: ipykernel>=7.3.0
18
20
  Requires-Dist: jupyter-client>=8.9.1
19
- Requires-Dist: mcp>=1.28.1
21
+ Requires-Dist: mcp<2,>=1.28.1
20
22
  Requires-Dist: openai>=2.45.0
21
23
  Requires-Dist: python-dotenv>=1.2.2
22
24
  Requires-Dist: pyyaml>=6.0.3
@@ -33,7 +35,7 @@ Description-Content-Type: text/markdown
33
35
 
34
36
  # Agentic Python Coder
35
37
 
36
- [![Python 3.13](https://img.shields.io/badge/python-3.13-blue.svg)](https://www.python.org/downloads/)
38
+ [![Python 3.13](https://img.shields.io/badge/python-3.13%2B-blue.svg)](https://www.python.org/downloads/)
37
39
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
38
40
  [![MCP Compatible](https://img.shields.io/badge/MCP-Compatible-green.svg)](https://modelcontextprotocol.io/)
39
41
  [![UV](https://img.shields.io/badge/Packaged%20with-UV-purple)](https://github.com/astral-sh/uv)
@@ -51,14 +53,14 @@ For details on architecture and constraint modelling applications, see [[Szeider
51
53
 
52
54
  ### Prerequisites
53
55
 
54
- - Python 3.13
56
+ - Python 3.13 or newer
55
57
  - UV package manager: `curl -LsSf https://astral.sh/uv/install.sh | sh`
56
58
 
57
59
  ### For the Coding Agent
58
60
 
59
61
  ```bash
60
- # Install as CLI tool
61
- uv tool install agentic-python-coder
62
+ # Install as CLI tool (--python 3.14: ortools, used by cpmpy, has no 3.15 wheels yet)
63
+ uv tool install --python 3.14 agentic-python-coder
62
64
 
63
65
  # Set up OpenRouter API key
64
66
  mkdir -p ~/.config/coder
@@ -97,7 +99,7 @@ Add to your Claude Desktop MCP configuration:
97
99
  "mcpServers": {
98
100
  "ipython": {
99
101
  "command": "uvx",
100
- "args": ["--from", "agentic-python-coder", "ipython_mcp"]
102
+ "args": ["--python", "3.14", "--from", "agentic-python-coder", "ipython_mcp"]
101
103
  }
102
104
  }
103
105
  }
@@ -132,7 +134,7 @@ coder -i
132
134
  | `--version`, `-V` | Show version and exit |
133
135
  | `--init [TEMPLATE]` | Initialize example templates (cpmpy, clingo, regex, or all) |
134
136
  | `--task`, `-t FILE` | Load task from markdown file |
135
- | `--model MODEL` | Model name or JSON file (default: sonnet45) |
137
+ | `--model MODEL` | Model name or JSON file (default: sonnet55) |
136
138
  | `--project`, `-p FILE` | Project template for domain-specific prompts |
137
139
  | `--with PACKAGE` | Add packages dynamically (repeatable) |
138
140
  | `--dir`, `-d DIR` | Working directory |
@@ -146,21 +148,25 @@ coder -i
146
148
 
147
149
  ```bash
148
150
  # Built-in models (versioned names)
149
- coder --model sonnet45 "task" # Claude Sonnet 4.5 (default)
151
+ coder --model sonnet45 "task" # Claude Sonnet 4.5
150
152
  coder --model sonnet46 "task" # Claude Sonnet 4.6
151
153
  coder --model sonnet5 "task" # Claude Sonnet 5
152
154
  coder --model opus45 "task" # Claude Opus 4.5
153
155
  coder --model opus48 "task" # Claude Opus 4.8
156
+ coder --model sonnet55 "task" # Claude Sonnet 5.5 (default)
157
+ coder --model opus55 "task" # Claude Opus 5.5
154
158
  coder --model deepseek31 "task" # DeepSeek v3.1
155
- coder --model grok41 "task" # X.AI Grok 4.1
159
+ coder --model grok47 "task" # X.AI Grok 4.7
156
160
  coder --model qwen3 "task" # Qwen3 Coder
157
161
  coder --model gemini25 "task" # Gemini Pro 2.5
158
- coder --model gemini3pro "task" # Gemini 3 Pro Preview
159
162
  coder --model gemini31 "task" # Gemini 3.1 Pro Preview
160
163
  coder --model gemini3flash "task" # Gemini 3 Flash Preview (fast, low-cost)
161
164
  coder --model gpt52 "task" # GPT-5.2
162
165
  coder --model gpt56sol "task" # GPT-5.6 Sol
163
166
  coder --model gpt56terra "task" # GPT-5.6 Terra
167
+ coder --model gpt6sol "task" # GPT-6 Sol
168
+ coder --model gpt6astra "task" # GPT-6 Astra
169
+ coder --model gemini4argon "task" # Gemini 4 Argon
164
170
 
165
171
  # Custom model (JSON file)
166
172
  coder --model ./mymodel.json "task"
@@ -217,7 +223,7 @@ import agentic_python_coder as coder
217
223
  messages, stats, log_path = coder.solve_task(
218
224
  "Write a fibonacci function",
219
225
  working_directory="/tmp/workspace",
220
- model="sonnet45",
226
+ model="sonnet55",
221
227
  quiet=True,
222
228
  )
223
229
 
@@ -236,7 +242,7 @@ from agentic_python_coder import solve_task
236
242
  messages, stats, log_path = solve_task(
237
243
  task="Your task description",
238
244
  working_directory=".", # Where to run and save files
239
- model=None, # Model name: "sonnet45", "opus45", or JSON file
245
+ model=None, # Model name: "sonnet55", "opus55", or JSON file
240
246
  system_prompt=None, # Custom system prompt (string)
241
247
  system_prompt_path=None, # Path to system prompt file
242
248
  project_prompt=None, # Domain-specific context
@@ -300,9 +306,9 @@ agent = create_coding_agent(
300
306
  ```python
301
307
  from agentic_python_coder import get_openrouter_llm, list_available_models
302
308
 
303
- llm = get_openrouter_llm(model="sonnet45")
309
+ llm = get_openrouter_llm(model="sonnet55")
304
310
  print(list_available_models())
305
- # ['deepseek31', 'gemini25', 'gemini3flash', 'gemini3pro', 'gpt52', 'grok41', 'opus45', 'qwen3', 'sonnet45']
311
+ # ['deepseek31', 'gemini25', 'gemini31', 'gemini3flash', 'gpt52', ...]
306
312
  ```
307
313
 
308
314
  ---
@@ -320,7 +326,7 @@ Add to your MCP settings (e.g., `~/.claude/claude_desktop_config.json` or projec
320
326
  "mcpServers": {
321
327
  "ipython": {
322
328
  "command": "uvx",
323
- "args": ["--from", "agentic-python-coder", "ipython_mcp"]
329
+ "args": ["--python", "3.14", "--from", "agentic-python-coder", "ipython_mcp"]
324
330
  }
325
331
  }
326
332
  }
@@ -1,8 +1,8 @@
1
1
  agentic_python_coder/__init__.py,sha256=e6o-k__u5xNIiQAkZbHtbZC2-NwpeOdi4MdQtAqJBjE,2112
2
- agentic_python_coder/agent.py,sha256=gzDFf4n7J1JdWawYPzWQFVwcHZ2rsRHUzVZVcGYjQWo,14451
3
- agentic_python_coder/cli.py,sha256=HS9nlqsiWZAvg0Hc8ExoVT8eEcy2t3Bux6UGukERWqQ,14663
4
- agentic_python_coder/kernel.py,sha256=Q-yLb8Il54kZv41qev2uzASFlr6bGjQ7ztBy7yD48GM,23273
5
- agentic_python_coder/llm.py,sha256=zjsk4-Kdx92hFSxywPGIkLv8zflWnE2cMEcpeXu6ttw,6998
2
+ agentic_python_coder/agent.py,sha256=0JfVNO-NEss9ZNEYkYvVlJSRzIxNa6sgRqLTdsD4zbs,16484
3
+ agentic_python_coder/cli.py,sha256=NWc1LCEL-L2TVCT6Su9a0AQ3ub3zg5GrY6XG3j_qPgI,14877
4
+ agentic_python_coder/kernel.py,sha256=_gIvDvtLpYGClm5IxTAqijwHG-wi2OtKUaH2Jtk2v0Q,23511
5
+ agentic_python_coder/llm.py,sha256=ZK3b9wLzjDr6BIxUkfKhuiSDbXNR2XaQsE1J-960IzE,6998
6
6
  agentic_python_coder/mcp_server.py,sha256=Osdl8UnjkupXbPLiYCugiapGDJsryZfVai0o-jepuqw,22047
7
7
  agentic_python_coder/project_md.py,sha256=4xkQHlWb4cDPEkvegw1YwcfaTJ3aFbrl0CYcC_xxABY,3249
8
8
  agentic_python_coder/runner.py,sha256=Kbw1ceYJ4MVfUKgSIkiuBhMb8ZtbZuJwbBeTUsvPRts,13045
@@ -28,21 +28,25 @@ agentic_python_coder/models/deepseek31.json,sha256=42qWgfBn2ErZndbpp-4-JtqRna2xl
28
28
  agentic_python_coder/models/gemini25.json,sha256=I3nNMz2GwhFQLtHtZotV3hNUyWXq9ToMm96byM98LFA,123
29
29
  agentic_python_coder/models/gemini31.json,sha256=q8y8pPEZE1hsv2vV7c1KckPHKE7Gfbi51xQgwM62i-o,117
30
30
  agentic_python_coder/models/gemini3flash.json,sha256=S0AMVpzi3O5CQk68Q3Hi8iCHXMQQFnM4NbSh23x0qIM,91
31
- agentic_python_coder/models/gemini3pro.json,sha256=5yWdmtkKSpAvr8svGjAgSoXvCnu1SCoVnhdbx-1L4fQ,131
31
+ agentic_python_coder/models/gemini4argon.json,sha256=MSFWsqRBsO8hVDoY89Qhgrv6FmSxVQSdQRb-R0KeF2M,109
32
32
  agentic_python_coder/models/gpt52.json,sha256=oDYxC21iQTKC9uVbFRlAs-hCnu_4cEDFK3mmqPVIIes,84
33
33
  agentic_python_coder/models/gpt56sol.json,sha256=xFNDxSz0ZC2qtDldgZ3ms1ela1InmhL5x_-UZktR1K8,88
34
34
  agentic_python_coder/models/gpt56terra.json,sha256=NnVvnnF7EMK-pADCZsm1fJ8O8DLCT4obHc0x_00kcus,90
35
- agentic_python_coder/models/grok41.json,sha256=l76RtbnFiNNQEe_dFoxn0HNbjgTcOMk5MswYqhcw764,96
35
+ agentic_python_coder/models/gpt6astra.json,sha256=XlLKLXCs7Qt7B8yM0cHMQY0Np1Swhr9yT0XUsWxmfs0,88
36
+ agentic_python_coder/models/gpt6sol.json,sha256=xQvQIiu1XNcGseYVGHzZfibmqmY5YbKazgjYrWIgdcQ,86
37
+ agentic_python_coder/models/grok47.json,sha256=vXNCFAA9sejVdk5p6H2wca2RXYlAtxS-vxLOhr8rcLA,75
36
38
  agentic_python_coder/models/opus45.json,sha256=wbRqoIrn1CSlu0pRnpR2S-1j1zWGD_jza7udZNnU3wY,87
37
39
  agentic_python_coder/models/opus48.json,sha256=grMqaY0sCQnZeH4VxsPfwUIqlHpxNxTjmM47hHuyPkY,87
40
+ agentic_python_coder/models/opus55.json,sha256=FZaru1YCBd32aj3RGJkj4NbTvI94KoiZgbAQ7iUj9to,95
38
41
  agentic_python_coder/models/qwen3.json,sha256=TJuIx5EllPIc8QBnagINlhNVxkLlsSDWRZAsFMqP_lo,94
39
42
  agentic_python_coder/models/sonnet45.json,sha256=WeWezJxt4r7IugBMzRbnSIocmmcd6qc_756M4CHdEa8,89
40
43
  agentic_python_coder/models/sonnet46.json,sha256=Ops1FpBoyx9PBGRhIXG8u-YGBgIui9DqvYxIc2BkJFM,89
41
44
  agentic_python_coder/models/sonnet5.json,sha256=kf6DIkQlcGVZ40IzRv3GXFtNncZF_gKqQeGzZAxE_KM,87
45
+ agentic_python_coder/models/sonnet55.json,sha256=ibqrXCS21NfgE95XBeyeNrbs6XmV00eKA586uf7o0ic,97
42
46
  agentic_python_coder/prompts/system.md,sha256=hREDVAhJXwCBAgJ3AE9JD6j-JRHREUPlkRSvThOvM3A,3807
43
47
  agentic_python_coder/prompts/system_todo.md,sha256=TuNeeUNS9KqyF62Da6t2mlUCYhKsgzwGe5ic_vFPDqw,5054
44
- agentic_python_coder-3.4.1.dist-info/METADATA,sha256=C9UTWTVtnf7-0Bgiu44LMEd16zA00T3UxkS92MVV_Ac,12872
45
- agentic_python_coder-3.4.1.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
46
- agentic_python_coder-3.4.1.dist-info/entry_points.txt,sha256=XIW3nZzL4kJ-Igohilj_mTvBcCyHBouDq2jmGzDILrk,107
47
- agentic_python_coder-3.4.1.dist-info/licenses/LICENSE,sha256=R9-M_V-SPdN71IphOVzM7kCNpUYs_hwj7rtroTwDhs0,11362
48
- agentic_python_coder-3.4.1.dist-info/RECORD,,
48
+ agentic_python_coder-3.4.3.dist-info/METADATA,sha256=Yr9xBjQt73msWBT7C5YABEO3zXSvUp3r2rUOsTdpw74,13255
49
+ agentic_python_coder-3.4.3.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
50
+ agentic_python_coder-3.4.3.dist-info/entry_points.txt,sha256=XIW3nZzL4kJ-Igohilj_mTvBcCyHBouDq2jmGzDILrk,107
51
+ agentic_python_coder-3.4.3.dist-info/licenses/LICENSE,sha256=R9-M_V-SPdN71IphOVzM7kCNpUYs_hwj7rtroTwDhs0,11362
52
+ agentic_python_coder-3.4.3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.31.0
2
+ Generator: hatchling 1.32.4
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,7 +0,0 @@
1
- {
2
- "path": "google/gemini-3-pro-preview",
3
- "temperature": 0.3,
4
- "max_tokens": 16384,
5
- "top_p": 0.9,
6
- "request_timeout": 120
7
- }
@@ -1,6 +0,0 @@
1
- {
2
- "path": "x-ai/grok-4.1-fast",
3
- "temperature": 0.15,
4
- "max_tokens": 2000,
5
- "top_p": 0.9
6
- }