agentic-python-coder 3.1.0__py3-none-any.whl → 3.3.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.
- agentic_python_coder/__init__.py +6 -1
- agentic_python_coder/agent.py +52 -14
- agentic_python_coder/cli.py +19 -4
- agentic_python_coder/examples/clingo/clingo.md +64 -1
- agentic_python_coder/examples/cpmpy/cpmpy.md +45 -2
- agentic_python_coder/kernel.py +17 -0
- agentic_python_coder/llm.py +23 -5
- agentic_python_coder/mcp_server.py +5 -6
- agentic_python_coder/models/deepseek31.json +0 -1
- agentic_python_coder/models/gemini25.json +0 -1
- agentic_python_coder/models/gemini31.json +6 -0
- agentic_python_coder/models/gemini3pro.json +0 -1
- agentic_python_coder/models/gpt52.json +0 -1
- agentic_python_coder/models/gpt56sol.json +5 -0
- agentic_python_coder/models/gpt56terra.json +5 -0
- agentic_python_coder/models/grok41.json +0 -1
- agentic_python_coder/models/opus45.json +1 -2
- agentic_python_coder/models/opus48.json +5 -0
- agentic_python_coder/models/qwen3.json +0 -1
- agentic_python_coder/models/sonnet45.json +1 -2
- agentic_python_coder/models/sonnet46.json +5 -0
- agentic_python_coder/models/sonnet5.json +5 -0
- agentic_python_coder/project_md.py +6 -2
- agentic_python_coder/runner.py +8 -1
- agentic_python_coder/tools.py +28 -7
- {agentic_python_coder-3.1.0.dist-info → agentic_python_coder-3.3.0.dist-info}/METADATA +54 -12
- agentic_python_coder-3.3.0.dist-info/RECORD +48 -0
- {agentic_python_coder-3.1.0.dist-info → agentic_python_coder-3.3.0.dist-info}/WHEEL +1 -1
- agentic_python_coder-3.1.0.dist-info/RECORD +0 -42
- {agentic_python_coder-3.1.0.dist-info → agentic_python_coder-3.3.0.dist-info}/entry_points.txt +0 -0
- {agentic_python_coder-3.1.0.dist-info → agentic_python_coder-3.3.0.dist-info}/licenses/LICENSE +0 -0
agentic_python_coder/__init__.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"""Python Coding Agent - A minimal coding assistant using direct OpenAI API and OpenRouter."""
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version as _package_version
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = _package_version("agentic-python-coder")
|
|
7
|
+
except PackageNotFoundError: # running from source without installation
|
|
8
|
+
__version__ = "0.0.0+unknown"
|
|
4
9
|
|
|
5
10
|
# High-level API (recommended for most users)
|
|
6
11
|
from agentic_python_coder.runner import solve_task
|
agentic_python_coder/agent.py
CHANGED
|
@@ -50,6 +50,7 @@ def create_coding_agent(
|
|
|
50
50
|
api_key: Optional[str] = None,
|
|
51
51
|
todo: bool = False,
|
|
52
52
|
verbose: bool = False,
|
|
53
|
+
llm_config: Optional[LLMConfig] = None,
|
|
53
54
|
) -> CodingAgent:
|
|
54
55
|
"""Create a ReAct agent for Python coding tasks.
|
|
55
56
|
|
|
@@ -65,6 +66,8 @@ def create_coding_agent(
|
|
|
65
66
|
api_key: Optional API key override
|
|
66
67
|
todo: If True, includes todo_write tool for task tracking
|
|
67
68
|
verbose: If True, print progress info (default False for library use)
|
|
69
|
+
llm_config: Optional pre-built LLMConfig (any OpenAI-compatible
|
|
70
|
+
client); takes precedence over model/api_key
|
|
68
71
|
|
|
69
72
|
Returns:
|
|
70
73
|
Configured CodingAgent
|
|
@@ -77,17 +80,19 @@ def create_coding_agent(
|
|
|
77
80
|
set_task_basename(task_basename)
|
|
78
81
|
|
|
79
82
|
# Store packages for kernel initialization (clear if None to avoid state leaks)
|
|
83
|
+
# JSON-encoded: a comma join would corrupt specs like "pkg[extra1,extra2]"
|
|
80
84
|
if with_packages is not None:
|
|
81
|
-
os.environ["CODER_WITH_PACKAGES"] =
|
|
85
|
+
os.environ["CODER_WITH_PACKAGES"] = json.dumps(with_packages)
|
|
82
86
|
else:
|
|
83
87
|
os.environ.pop("CODER_WITH_PACKAGES", None)
|
|
84
88
|
|
|
85
|
-
# Get LLM config
|
|
86
|
-
llm_config
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
# Get LLM config (a pre-built one takes precedence)
|
|
90
|
+
if llm_config is None:
|
|
91
|
+
llm_config = get_openrouter_llm(
|
|
92
|
+
model=model or DEFAULT_MODEL,
|
|
93
|
+
api_key=api_key,
|
|
94
|
+
verbose=verbose,
|
|
95
|
+
)
|
|
91
96
|
|
|
92
97
|
# Create tool registry
|
|
93
98
|
tools = create_tool_registry(todo=todo)
|
|
@@ -199,8 +204,9 @@ def run_agent(
|
|
|
199
204
|
Returns:
|
|
200
205
|
Tuple of (List of new messages from this call, Statistics dictionary)
|
|
201
206
|
"""
|
|
202
|
-
#
|
|
203
|
-
#
|
|
207
|
+
# The working directory is a process-wide singleton; set it at execution
|
|
208
|
+
# time so it always matches the agent currently running (concurrent
|
|
209
|
+
# run_agent calls in one process are not supported)
|
|
204
210
|
working_dir.set(agent.working_directory)
|
|
205
211
|
|
|
206
212
|
limit = step_limit if step_limit is not None else DEFAULT_STEP_LIMIT
|
|
@@ -228,7 +234,7 @@ def run_agent(
|
|
|
228
234
|
openai_tools = agent.tools.get_openai_tools()
|
|
229
235
|
|
|
230
236
|
# ReAct loop
|
|
231
|
-
for
|
|
237
|
+
for _ in range(limit):
|
|
232
238
|
# Build request kwargs
|
|
233
239
|
request_kwargs: dict[str, Any] = {
|
|
234
240
|
"model": agent.llm_config.model,
|
|
@@ -243,13 +249,17 @@ def run_agent(
|
|
|
243
249
|
# Call API
|
|
244
250
|
response = agent.llm_config.client.chat.completions.create(**request_kwargs)
|
|
245
251
|
|
|
246
|
-
# Track tokens
|
|
252
|
+
# Track tokens (some providers return usage objects with None fields)
|
|
247
253
|
if response.usage:
|
|
248
|
-
stats["token_consumption"]["input_tokens"] +=
|
|
254
|
+
stats["token_consumption"]["input_tokens"] += (
|
|
255
|
+
response.usage.prompt_tokens or 0
|
|
256
|
+
)
|
|
249
257
|
stats["token_consumption"]["output_tokens"] += (
|
|
250
|
-
response.usage.completion_tokens
|
|
258
|
+
response.usage.completion_tokens or 0
|
|
259
|
+
)
|
|
260
|
+
stats["token_consumption"]["total_tokens"] += (
|
|
261
|
+
response.usage.total_tokens or 0
|
|
251
262
|
)
|
|
252
|
-
stats["token_consumption"]["total_tokens"] += response.usage.total_tokens
|
|
253
263
|
|
|
254
264
|
if not response.choices:
|
|
255
265
|
break
|
|
@@ -324,6 +334,29 @@ def run_agent(
|
|
|
324
334
|
}
|
|
325
335
|
)
|
|
326
336
|
|
|
337
|
+
elif response.choices[0].finish_reason == "length":
|
|
338
|
+
# Response cut off at max_tokens with no tool call — don't accept
|
|
339
|
+
# the truncated text as a final answer; ask the model to continue
|
|
340
|
+
agent.messages.append(
|
|
341
|
+
{
|
|
342
|
+
"role": "assistant",
|
|
343
|
+
"content": assistant_message.content or "",
|
|
344
|
+
}
|
|
345
|
+
)
|
|
346
|
+
agent.messages.append(
|
|
347
|
+
{
|
|
348
|
+
"role": "user",
|
|
349
|
+
"content": (
|
|
350
|
+
"Your previous response was truncated at the max_tokens "
|
|
351
|
+
"limit. Continue, and be more concise."
|
|
352
|
+
),
|
|
353
|
+
}
|
|
354
|
+
)
|
|
355
|
+
if not quiet:
|
|
356
|
+
print(
|
|
357
|
+
"Warning: response truncated at max_tokens; asking model to continue"
|
|
358
|
+
)
|
|
359
|
+
|
|
327
360
|
else:
|
|
328
361
|
# No tool calls — final answer
|
|
329
362
|
agent.messages.append(
|
|
@@ -333,6 +366,11 @@ def run_agent(
|
|
|
333
366
|
}
|
|
334
367
|
)
|
|
335
368
|
break
|
|
369
|
+
else:
|
|
370
|
+
# Loop exhausted without a final answer
|
|
371
|
+
stats["step_limit_reached"] = True
|
|
372
|
+
if not quiet:
|
|
373
|
+
print(f"Warning: step limit ({limit}) reached without a final response")
|
|
336
374
|
|
|
337
375
|
stats["execution_time_seconds"] = time.time() - start_time
|
|
338
376
|
|
agentic_python_coder/cli.py
CHANGED
|
@@ -260,6 +260,9 @@ def validate_model(model):
|
|
|
260
260
|
print(f" - {m}")
|
|
261
261
|
print("\nOr provide a path to a custom model JSON file.")
|
|
262
262
|
sys.exit(1)
|
|
263
|
+
except ValueError as e:
|
|
264
|
+
print(f"Error: {e}")
|
|
265
|
+
sys.exit(1)
|
|
263
266
|
|
|
264
267
|
|
|
265
268
|
def load_project_prompt(project_path: str) -> Optional[str]:
|
|
@@ -290,12 +293,19 @@ def load_project_prompt(project_path: str) -> Optional[str]:
|
|
|
290
293
|
|
|
291
294
|
|
|
292
295
|
def run_interactive(
|
|
293
|
-
working_dir: Path,
|
|
296
|
+
working_dir: Path,
|
|
297
|
+
model: str,
|
|
298
|
+
project_prompt: str,
|
|
299
|
+
api_key: str,
|
|
300
|
+
todo: bool,
|
|
301
|
+
with_packages=None,
|
|
294
302
|
):
|
|
295
303
|
"""Run the agent in interactive mode."""
|
|
296
304
|
print(f"\nInteractive mode - working in: {working_dir}")
|
|
297
305
|
if project_prompt:
|
|
298
306
|
print("Project configuration loaded")
|
|
307
|
+
if with_packages:
|
|
308
|
+
print(f"Dynamic packages: {', '.join(with_packages)}")
|
|
299
309
|
print("Type 'exit' or 'quit' to stop.\n")
|
|
300
310
|
|
|
301
311
|
# Load system prompt
|
|
@@ -307,12 +317,12 @@ def run_interactive(
|
|
|
307
317
|
system_prompt=system_prompt,
|
|
308
318
|
model=model,
|
|
309
319
|
project_prompt=project_prompt,
|
|
320
|
+
with_packages=with_packages,
|
|
310
321
|
api_key=api_key,
|
|
311
322
|
todo=todo,
|
|
312
323
|
verbose=True,
|
|
313
324
|
)
|
|
314
325
|
|
|
315
|
-
thread_id = "interactive"
|
|
316
326
|
all_messages = []
|
|
317
327
|
cumulative_stats = {
|
|
318
328
|
"tool_usage": {},
|
|
@@ -333,7 +343,7 @@ def run_interactive(
|
|
|
333
343
|
continue
|
|
334
344
|
|
|
335
345
|
print("\nAgent working...\n")
|
|
336
|
-
messages, stats = run_agent(agent, user_input,
|
|
346
|
+
messages, stats = run_agent(agent, user_input, quiet=False)
|
|
337
347
|
all_messages.extend(messages)
|
|
338
348
|
|
|
339
349
|
# Update cumulative stats
|
|
@@ -440,7 +450,12 @@ def main():
|
|
|
440
450
|
try:
|
|
441
451
|
if args.interactive:
|
|
442
452
|
run_interactive(
|
|
443
|
-
working_dir,
|
|
453
|
+
working_dir,
|
|
454
|
+
args.model,
|
|
455
|
+
project_prompt,
|
|
456
|
+
args.api_key,
|
|
457
|
+
args.todo,
|
|
458
|
+
with_packages=args.with_packages,
|
|
444
459
|
)
|
|
445
460
|
else:
|
|
446
461
|
# Use solve_task for the main flow
|
|
@@ -29,9 +29,10 @@ Before completing your solution, verify:
|
|
|
29
29
|
☐ 2. **Model solves correctly** - At least one answer set is found (or UNSAT handled)
|
|
30
30
|
☐ 3. **Optimization applied** - If problem asks for optimal, use #minimize/#maximize
|
|
31
31
|
☐ 4. **Solution extracted** - Answer set atoms properly extracted and formatted
|
|
32
|
+
☐ 4b. **No Model escapes on_model** - All solution data extracted to plain Python objects inside the callback (touching a Model after solve() returns segfaults)
|
|
32
33
|
☐ 5. **Output format correct** - JSON output with appropriate structure
|
|
33
34
|
☐ 6. **Predicates meaningful** - Clear names that reflect the problem domain
|
|
34
|
-
☐ 7. **Constraints verified** - All problem constraints are encoded
|
|
35
|
+
☐ 7. **Constraints verified independently** - All problem constraints are encoded AND re-checked by a plain-Python verify() whose expectations are re-derived from the problem text, not from your encoding's own interpretation
|
|
35
36
|
☐ 8. **File written** - Create `solution.py` with complete working code
|
|
36
37
|
|
|
37
38
|
## Section 2: Critical Rules of Engagement
|
|
@@ -474,6 +475,38 @@ def extract_solution(model):
|
|
|
474
475
|
return solution
|
|
475
476
|
```
|
|
476
477
|
|
|
478
|
+
### CRITICAL: The Model Object Is Only Valid Inside on_model (Segfault Risk)
|
|
479
|
+
|
|
480
|
+
The `clingo.Model` object passed to your `on_model` callback is only valid DURING
|
|
481
|
+
that callback. After `ctl.solve()` returns, clingo frees the underlying model —
|
|
482
|
+
touching it later is a use-after-free that crashes the Python process with a
|
|
483
|
+
segmentation fault (exit code 139) and NO Python traceback.
|
|
484
|
+
|
|
485
|
+
Extract everything you need into plain Python objects (ints, strings, lists, dicts)
|
|
486
|
+
INSIDE the callback. Never store the Model object itself for later use.
|
|
487
|
+
|
|
488
|
+
```python
|
|
489
|
+
# WRONG - segfaults after solve() returns:
|
|
490
|
+
saved = None
|
|
491
|
+
def on_model(m):
|
|
492
|
+
global saved
|
|
493
|
+
saved = m # Model outlives the callback
|
|
494
|
+
ctl.solve(on_model=on_model)
|
|
495
|
+
atoms = saved.symbols(atoms=True) # use-after-free -> SIGSEGV, no traceback
|
|
496
|
+
|
|
497
|
+
# CORRECT - extract inside the callback:
|
|
498
|
+
result = []
|
|
499
|
+
def on_model(m):
|
|
500
|
+
for a in m.symbols(atoms=True):
|
|
501
|
+
if a.match("assigned", 2):
|
|
502
|
+
result.append((str(a.arguments[0]), str(a.arguments[1])))
|
|
503
|
+
ctl.solve(on_model=on_model)
|
|
504
|
+
# work with the plain tuples in result
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
This also applies to verification: snapshot the atoms into plain Python inside
|
|
508
|
+
`on_model`, then run your checks on the snapshot after solving.
|
|
509
|
+
|
|
477
510
|
## Section 4: Problem-Solving Pattern Library
|
|
478
511
|
|
|
479
512
|
### 4.1 Modeling State and Change (NEW - CRITICAL)
|
|
@@ -964,6 +997,36 @@ possible_col(C) :- col(C).
|
|
|
964
997
|
4. **Let solver determine gaps**: Don't over-constrain non-run cells
|
|
965
998
|
5. **Different is adjacent**: Cells of different colors/states CAN touch
|
|
966
999
|
|
|
1000
|
+
### 4.11 "Reachable Only After" / Ordered Reachability Constraints
|
|
1001
|
+
|
|
1002
|
+
When a problem requires that some target element become reachable only after all
|
|
1003
|
+
other elements (or only after specific ones) under an evolving reachability process,
|
|
1004
|
+
do NOT model it as an existential ordering — guessing a permutation with the target
|
|
1005
|
+
pinned last only proves that SOME order exists, which is weaker than what such
|
|
1006
|
+
problems ask. The intended reading is almost always about the actual reachability
|
|
1007
|
+
process: everything reachable gets reached as soon as it is reachable.
|
|
1008
|
+
|
|
1009
|
+
Model the process directly with a time-indexed fixpoint and constrain first-reach
|
|
1010
|
+
times:
|
|
1011
|
+
|
|
1012
|
+
```asp
|
|
1013
|
+
step(0..max_step).
|
|
1014
|
+
reached(S, 0) :- start(S).
|
|
1015
|
+
reached(Y, T+1) :- edge(X, Y), reached(X, T), step(T+1), unlocked(X, Y, T).
|
|
1016
|
+
reached(X, T+1) :- reached(X, T), step(T+1). % persistence
|
|
1017
|
+
first_reached(X, 0) :- reached(X, 0).
|
|
1018
|
+
first_reached(X, T) :- reached(X, T), not reached(X, T-1), T > 0, step(T).
|
|
1019
|
+
|
|
1020
|
+
% target must not become reachable before (or together with) any other element:
|
|
1021
|
+
:- first_reached(target, Tg), first_reached(X, Tx), X != target, Tx >= Tg.
|
|
1022
|
+
```
|
|
1023
|
+
|
|
1024
|
+
Adapt `unlocked/3` to whatever gates progression (collected items, satisfied
|
|
1025
|
+
prerequisites, ...). Verify with a plain-Python simulation of the same process:
|
|
1026
|
+
repeatedly add everything currently reachable, one step at a time, and check the
|
|
1027
|
+
required ordering of first-reach steps against the problem text — do not reuse
|
|
1028
|
+
your encoding's ordering predicates in the verifier.
|
|
1029
|
+
|
|
967
1030
|
## Section 5: Debugging & Advanced Techniques
|
|
968
1031
|
|
|
969
1032
|
### 5.1 Efficient Generation: Constrain Choices Early (Anti-Pattern: Generate-and-Filter)
|
|
@@ -31,7 +31,7 @@ else:
|
|
|
31
31
|
- `AllDifferent(vars)` - all different values
|
|
32
32
|
- `sum(vars) == total` - sum constraint
|
|
33
33
|
- `Circuit(x)` - variables x form a Hamiltonian circuit (for routing/tour problems)
|
|
34
|
-
- `InDomain(var, [values])` - restrict variable to a set of values
|
|
34
|
+
- `InDomain(var, [values])` - restrict variable to a set of values. **Must be explicitly imported**: `from cpmpy import InDomain`
|
|
35
35
|
- Logical: `&`, `|`, `~` on constraints; `(cond).implies(other)` on constraints only
|
|
36
36
|
- Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=` between variables and expressions
|
|
37
37
|
- Element: `vars[idx]` where idx is a decision variable (direct indexing works)
|
|
@@ -54,4 +54,47 @@ else:
|
|
|
54
54
|
model.maximize(profit)
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
## Output Format Rules
|
|
58
|
+
- Follow the output JSON format specification EXACTLY — do not invent alternative encodings
|
|
59
|
+
- If a field is described as nested arrays, output nested arrays (e.g., `[[1,2],[3,4]]`), never compress to single integers
|
|
60
|
+
- If the narrative text conflicts with the explicit "Output format" block, the Output format block wins
|
|
61
|
+
- If the narrative mentions optional variants or extensions of the problem ("one extension is...", "another version..."), solve the base problem as specified by the input data and the Output format block — do not output an extended variant unless the output spec explicitly requires it
|
|
62
|
+
- Derive every output array's dimensions from parameters stated in the problem and from the axis names in the format spec: `result[a][b]` means outer axis `a` and inner axis `b` — never swap axes or substitute a different quantity
|
|
63
|
+
- Check array dimensions and value ranges match the spec before saving
|
|
64
|
+
|
|
65
|
+
## Verification Requirement (MANDATORY)
|
|
66
|
+
|
|
67
|
+
CPMpy models can easily contain subtle logic bugs. Before saving, you MUST:
|
|
68
|
+
|
|
69
|
+
1. **Solve and extract** the solution values
|
|
70
|
+
2. **Write a `verify()` function** that checks every constraint from the problem statement using plain Python loops and asserts — independent of your CPMpy model:
|
|
71
|
+
```python
|
|
72
|
+
def verify(result):
|
|
73
|
+
# Check array shapes — sizes re-derived from the problem text,
|
|
74
|
+
# NOT from variables your model introduced
|
|
75
|
+
assert len(result["schedule"]) == n_weeks
|
|
76
|
+
# Check each constraint with plain Python
|
|
77
|
+
for w in range(n_weeks):
|
|
78
|
+
teams_this_week = [result["schedule"][w][p] for p in range(n_periods)]
|
|
79
|
+
assert len(set(teams_this_week)) == len(teams_this_week), "Duplicate team in week"
|
|
80
|
+
# ... check ALL constraints from the problem statement
|
|
81
|
+
print("All checks passed")
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The verifier must be derived from the problem text alone: re-read the problem
|
|
85
|
+
statement and re-derive every expected dimension, entry encoding, and constraint
|
|
86
|
+
from its own parameters. Never assert against quantities or interpretations that
|
|
87
|
+
your model introduced — `assert len(x) == my_total` proves nothing if `my_total`
|
|
88
|
+
encodes a misreading. If your model and your verifier share an assumption, a
|
|
89
|
+
wrong assumption passes silently.
|
|
90
|
+
3. **Execute the verification** via python_exec and confirm it passes
|
|
91
|
+
4. **For optimization**: verify optimality by re-solving with a stricter bound:
|
|
92
|
+
```python
|
|
93
|
+
model2 = Model(model.constraints)
|
|
94
|
+
model2 += objective < best_value # or > for maximize
|
|
95
|
+
assert not model2.solve(), "Solution is not optimal"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Do NOT call save_code until verification passes. If it fails, fix the model and re-verify.
|
|
99
|
+
|
|
100
|
+
That's it. Read the problem carefully, model it declaratively, verify independently, and let CPMpy find the optimal solution.
|
agentic_python_coder/kernel.py
CHANGED
|
@@ -250,6 +250,7 @@ except ImportError:
|
|
|
250
250
|
|
|
251
251
|
# Wait for and collect messages with hard deadline
|
|
252
252
|
deadline = time.monotonic() + deadline_timeout
|
|
253
|
+
completed = False
|
|
253
254
|
|
|
254
255
|
while time.monotonic() < deadline:
|
|
255
256
|
try:
|
|
@@ -274,10 +275,26 @@ except ImportError:
|
|
|
274
275
|
if content.get("traceback"):
|
|
275
276
|
output["error"] += "\n" + "\n".join(content["traceback"])
|
|
276
277
|
elif msg_type == "status" and content["execution_state"] == "idle":
|
|
278
|
+
completed = True
|
|
277
279
|
break # Only exit on idle status
|
|
278
280
|
except Empty:
|
|
279
281
|
continue # Keep waiting, don't break
|
|
280
282
|
|
|
283
|
+
if not completed:
|
|
284
|
+
# Deadline hit while the kernel was still running: report a
|
|
285
|
+
# timeout instead of silently returning partial output as success,
|
|
286
|
+
# and interrupt so the kernel doesn't block the next execution
|
|
287
|
+
if output["error"] is None:
|
|
288
|
+
output["error"] = (
|
|
289
|
+
f"Execution timed out after {deadline_timeout} seconds"
|
|
290
|
+
" (partial output returned)"
|
|
291
|
+
)
|
|
292
|
+
try:
|
|
293
|
+
self.km.interrupt_kernel()
|
|
294
|
+
time.sleep(0.5) # grace period so the next execute isn't aborted
|
|
295
|
+
except Exception:
|
|
296
|
+
pass # Best effort
|
|
297
|
+
|
|
281
298
|
return output
|
|
282
299
|
|
|
283
300
|
def execute(self, code: str, deadline_timeout: int = 60) -> Dict[str, str]:
|
agentic_python_coder/llm.py
CHANGED
|
@@ -133,6 +133,10 @@ def get_openrouter_llm(
|
|
|
133
133
|
) -> LLMConfig:
|
|
134
134
|
"""Create a fully configured LLMConfig for OpenRouter.
|
|
135
135
|
|
|
136
|
+
The model JSON may override the endpoint with "base_url" (any
|
|
137
|
+
OpenAI-compatible server) and "api_key_env" (name of the environment
|
|
138
|
+
variable holding the key for that endpoint).
|
|
139
|
+
|
|
136
140
|
Args:
|
|
137
141
|
model: Model name (e.g., "sonnet45") or path to JSON file
|
|
138
142
|
api_key: Optional API key
|
|
@@ -158,17 +162,27 @@ def get_openrouter_llm(
|
|
|
158
162
|
|
|
159
163
|
# Get API key
|
|
160
164
|
if not api_key:
|
|
161
|
-
|
|
165
|
+
if "api_key_env" in config:
|
|
166
|
+
api_key = os.getenv(config["api_key_env"])
|
|
167
|
+
if not api_key:
|
|
168
|
+
raise ValueError(
|
|
169
|
+
f"Environment variable '{config['api_key_env']}' not set "
|
|
170
|
+
f"(required by model config '{model}')"
|
|
171
|
+
)
|
|
172
|
+
else:
|
|
173
|
+
api_key = get_api_key()
|
|
162
174
|
|
|
163
175
|
# Build client kwargs
|
|
164
176
|
client_kwargs: dict[str, Any] = {
|
|
165
177
|
"api_key": api_key,
|
|
166
|
-
"base_url": "https://openrouter.ai/api/v1",
|
|
167
|
-
|
|
178
|
+
"base_url": config.get("base_url", "https://openrouter.ai/api/v1"),
|
|
179
|
+
}
|
|
180
|
+
if "base_url" not in config:
|
|
181
|
+
# OpenRouter attribution headers; skip for custom endpoints
|
|
182
|
+
client_kwargs["default_headers"] = {
|
|
168
183
|
"HTTP-Referer": "https://github.com/szeider/agentic-python-coder",
|
|
169
184
|
"X-Title": "Agentic Python Coder",
|
|
170
|
-
}
|
|
171
|
-
}
|
|
185
|
+
}
|
|
172
186
|
|
|
173
187
|
# Add request_timeout as client timeout
|
|
174
188
|
if "request_timeout" in config:
|
|
@@ -201,4 +215,8 @@ def get_openrouter_llm(
|
|
|
201
215
|
if "provider" in config:
|
|
202
216
|
api_params.setdefault("extra_body", {})["provider"] = config["provider"]
|
|
203
217
|
|
|
218
|
+
# Reasoning/thinking tokens (e.g. Gemini 3 Flash thinking levels)
|
|
219
|
+
if "reasoning" in config:
|
|
220
|
+
api_params.setdefault("extra_body", {})["reasoning"] = config["reasoning"]
|
|
221
|
+
|
|
204
222
|
return LLMConfig(client=client, model=model_id, api_params=api_params)
|
|
@@ -39,16 +39,15 @@ _session_lock = asyncio.Lock()
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def truncate_output(result: dict) -> dict:
|
|
42
|
-
"""Truncate
|
|
42
|
+
"""Truncate oversized text fields and add success flag."""
|
|
43
43
|
# Add success flag based on error field
|
|
44
44
|
result["success"] = result.get("error") is None
|
|
45
45
|
|
|
46
46
|
max_kb = MAX_OUTPUT // 1024
|
|
47
|
-
for key in ["stdout", "stderr"]:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
47
|
+
for key in ["stdout", "stderr", "result", "error"]:
|
|
48
|
+
value = result.get(key)
|
|
49
|
+
if isinstance(value, str) and len(value) > MAX_OUTPUT:
|
|
50
|
+
result[key] = value[:MAX_OUTPUT] + f"\n[{key} truncated at {max_kb}KB]"
|
|
52
51
|
return result
|
|
53
52
|
|
|
54
53
|
|
|
@@ -53,8 +53,12 @@ def check_packages_available(packages: List[str]) -> List[str]:
|
|
|
53
53
|
unavailable = []
|
|
54
54
|
|
|
55
55
|
for package in packages:
|
|
56
|
-
# Try to find the package
|
|
57
|
-
|
|
56
|
+
# Try to find the package; find_spec raises for dotted names with a
|
|
57
|
+
# missing parent or otherwise invalid names — treat those as unavailable
|
|
58
|
+
try:
|
|
59
|
+
spec = importlib.util.find_spec(package)
|
|
60
|
+
except (ImportError, ValueError):
|
|
61
|
+
spec = None
|
|
58
62
|
if spec is None:
|
|
59
63
|
unavailable.append(package)
|
|
60
64
|
|
agentic_python_coder/runner.py
CHANGED
|
@@ -5,6 +5,7 @@ from pathlib import Path
|
|
|
5
5
|
from typing import Optional, List, Any, Dict
|
|
6
6
|
|
|
7
7
|
from agentic_python_coder.agent import create_coding_agent, run_agent
|
|
8
|
+
from agentic_python_coder.llm import LLMConfig
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
def get_system_prompt_path(todo: bool = False) -> Path:
|
|
@@ -233,7 +234,9 @@ def save_conversation_log(
|
|
|
233
234
|
json.dumps(
|
|
234
235
|
{
|
|
235
236
|
"event": "complete",
|
|
236
|
-
"status": "
|
|
237
|
+
"status": "step_limit_reached"
|
|
238
|
+
if stats and stats.get("step_limit_reached")
|
|
239
|
+
else "success",
|
|
237
240
|
}
|
|
238
241
|
)
|
|
239
242
|
+ "\n"
|
|
@@ -256,6 +259,7 @@ def solve_task(
|
|
|
256
259
|
save_log: bool = True,
|
|
257
260
|
task_basename: Optional[str] = None,
|
|
258
261
|
step_limit: Optional[int] = None,
|
|
262
|
+
llm_config: Optional[LLMConfig] = None,
|
|
259
263
|
) -> tuple[List[Any], Dict[str, Any], Optional[Path]]:
|
|
260
264
|
"""Run a complete coding task end-to-end.
|
|
261
265
|
|
|
@@ -275,6 +279,8 @@ def solve_task(
|
|
|
275
279
|
save_log: Save conversation log to file (default: True)
|
|
276
280
|
task_basename: Base name for output files
|
|
277
281
|
step_limit: Maximum agent steps before stopping (default: 200)
|
|
282
|
+
llm_config: Optional pre-built LLMConfig (any OpenAI-compatible
|
|
283
|
+
client); takes precedence over model/api_key
|
|
278
284
|
|
|
279
285
|
Returns:
|
|
280
286
|
Tuple of (messages, stats, log_path)
|
|
@@ -313,6 +319,7 @@ def solve_task(
|
|
|
313
319
|
api_key=api_key,
|
|
314
320
|
todo=todo,
|
|
315
321
|
verbose=not quiet,
|
|
322
|
+
llm_config=llm_config,
|
|
316
323
|
)
|
|
317
324
|
|
|
318
325
|
# Run agent
|
agentic_python_coder/tools.py
CHANGED
|
@@ -5,7 +5,7 @@ from dataclasses import dataclass
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import List, Dict, Any, Callable
|
|
7
7
|
|
|
8
|
-
from .kernel import get_kernel, format_output
|
|
8
|
+
from .kernel import get_kernel, format_output, shutdown_kernel
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@dataclass
|
|
@@ -50,10 +50,6 @@ class ToolRegistry:
|
|
|
50
50
|
"""Get a tool by name."""
|
|
51
51
|
return self._tools.get(name)
|
|
52
52
|
|
|
53
|
-
def has(self, name: str) -> bool:
|
|
54
|
-
"""Check if a tool is registered."""
|
|
55
|
-
return name in self._tools
|
|
56
|
-
|
|
57
53
|
def get_openai_tools(self) -> list[dict[str, Any]]:
|
|
58
54
|
"""Get all tools in OpenAI format."""
|
|
59
55
|
return [tool.to_openai_tool() for tool in self._tools.values()]
|
|
@@ -171,7 +167,14 @@ def python_exec(code: str) -> str:
|
|
|
171
167
|
with_packages = None
|
|
172
168
|
if "CODER_WITH_PACKAGES" in os.environ:
|
|
173
169
|
packages_str = os.environ["CODER_WITH_PACKAGES"]
|
|
174
|
-
|
|
170
|
+
if not packages_str:
|
|
171
|
+
with_packages = []
|
|
172
|
+
else:
|
|
173
|
+
try:
|
|
174
|
+
with_packages = json.loads(packages_str)
|
|
175
|
+
except json.JSONDecodeError:
|
|
176
|
+
# Legacy comma-joined format
|
|
177
|
+
with_packages = packages_str.split(",")
|
|
175
178
|
|
|
176
179
|
try:
|
|
177
180
|
kernel = get_kernel(cwd=str(working_dir.get()), with_packages=with_packages)
|
|
@@ -214,6 +217,16 @@ def save_code(code: str) -> str:
|
|
|
214
217
|
else:
|
|
215
218
|
filename = "solution.py"
|
|
216
219
|
|
|
220
|
+
# Reject non-compiling code so the model gets feedback instead of a
|
|
221
|
+
# silently broken file (e.g. from a bad escape in the tool-call JSON)
|
|
222
|
+
try:
|
|
223
|
+
compile(code, filename, "exec")
|
|
224
|
+
except SyntaxError as e:
|
|
225
|
+
return error_response(
|
|
226
|
+
f"Code NOT saved — syntax error at line {e.lineno}: {e.msg}. "
|
|
227
|
+
"Fix the code and call save_code again."
|
|
228
|
+
)
|
|
229
|
+
|
|
217
230
|
output_path = working_dir.get() / filename
|
|
218
231
|
output_path.write_text(code)
|
|
219
232
|
|
|
@@ -223,10 +236,16 @@ def save_code(code: str) -> str:
|
|
|
223
236
|
|
|
224
237
|
|
|
225
238
|
def reset_global_state():
|
|
226
|
-
"""Reset all global state to avoid accumulation across runs.
|
|
239
|
+
"""Reset all global state to avoid accumulation across runs.
|
|
240
|
+
|
|
241
|
+
Also shuts down the default kernel so the next execution starts a fresh
|
|
242
|
+
one — otherwise a second agent in the same process would silently reuse
|
|
243
|
+
the previous agent's kernel (its cwd, packages, and variables).
|
|
244
|
+
"""
|
|
227
245
|
global _todos, _task_basename
|
|
228
246
|
_todos = []
|
|
229
247
|
_task_basename = None
|
|
248
|
+
shutdown_kernel()
|
|
230
249
|
|
|
231
250
|
|
|
232
251
|
# Tool definitions with explicit JSON schemas
|
|
@@ -281,6 +300,8 @@ SAVE_CODE_TOOL = Tool(
|
|
|
281
300
|
"2. Verified the output format matches the specification exactly (JSON keys, array shapes, value ranges)\n"
|
|
282
301
|
"3. For constraint/logic problems: run an independent verification checking every constraint\n"
|
|
283
302
|
"Do NOT save unverified code. If verification fails, fix the code and re-verify first.\n\n"
|
|
303
|
+
"The code is syntax-checked before saving; on a syntax error nothing is\n"
|
|
304
|
+
"written and an error is returned — fix the code and save again.\n\n"
|
|
284
305
|
"Args:\n"
|
|
285
306
|
" code: The complete Python code\n\n"
|
|
286
307
|
"Returns:\n"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-python-coder
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
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
|
|
@@ -14,21 +14,21 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
14
14
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
15
15
|
Classifier: Topic :: Software Development :: Code Generators
|
|
16
16
|
Requires-Python: <3.14,>=3.13
|
|
17
|
-
Requires-Dist: ipykernel>=7.
|
|
18
|
-
Requires-Dist: jupyter-client>=8.
|
|
19
|
-
Requires-Dist: mcp>=1.
|
|
20
|
-
Requires-Dist: openai>=2.
|
|
21
|
-
Requires-Dist: python-dotenv>=1.2.
|
|
17
|
+
Requires-Dist: ipykernel>=7.3.0
|
|
18
|
+
Requires-Dist: jupyter-client>=8.9.1
|
|
19
|
+
Requires-Dist: mcp>=1.28.1
|
|
20
|
+
Requires-Dist: openai>=2.45.0
|
|
21
|
+
Requires-Dist: python-dotenv>=1.2.2
|
|
22
22
|
Requires-Dist: pyyaml>=6.0.3
|
|
23
|
-
Requires-Dist: rich>=
|
|
23
|
+
Requires-Dist: rich>=15.0.0
|
|
24
24
|
Provides-Extra: dev
|
|
25
|
-
Requires-Dist: mypy>=
|
|
26
|
-
Requires-Dist: ruff>=0.
|
|
25
|
+
Requires-Dist: mypy>=2.2.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.15.21; extra == 'dev'
|
|
27
27
|
Provides-Extra: test
|
|
28
|
-
Requires-Dist: pytest-asyncio>=1.
|
|
29
|
-
Requires-Dist: pytest-cov>=7.
|
|
28
|
+
Requires-Dist: pytest-asyncio>=1.4.0; extra == 'test'
|
|
29
|
+
Requires-Dist: pytest-cov>=7.1.0; extra == 'test'
|
|
30
30
|
Requires-Dist: pytest-watch>=4.2.0; extra == 'test'
|
|
31
|
-
Requires-Dist: pytest>=9.
|
|
31
|
+
Requires-Dist: pytest>=9.1.1; extra == 'test'
|
|
32
32
|
Description-Content-Type: text/markdown
|
|
33
33
|
|
|
34
34
|
# Agentic Python Coder
|
|
@@ -147,19 +147,41 @@ coder -i
|
|
|
147
147
|
```bash
|
|
148
148
|
# Built-in models (versioned names)
|
|
149
149
|
coder --model sonnet45 "task" # Claude Sonnet 4.5 (default)
|
|
150
|
+
coder --model sonnet46 "task" # Claude Sonnet 4.6
|
|
151
|
+
coder --model sonnet5 "task" # Claude Sonnet 5
|
|
150
152
|
coder --model opus45 "task" # Claude Opus 4.5
|
|
153
|
+
coder --model opus48 "task" # Claude Opus 4.8
|
|
151
154
|
coder --model deepseek31 "task" # DeepSeek v3.1
|
|
152
155
|
coder --model grok41 "task" # X.AI Grok 4.1
|
|
153
156
|
coder --model qwen3 "task" # Qwen3 Coder
|
|
154
157
|
coder --model gemini25 "task" # Gemini Pro 2.5
|
|
155
158
|
coder --model gemini3pro "task" # Gemini 3 Pro Preview
|
|
159
|
+
coder --model gemini31 "task" # Gemini 3.1 Pro Preview
|
|
156
160
|
coder --model gemini3flash "task" # Gemini 3 Flash Preview (fast, low-cost)
|
|
157
161
|
coder --model gpt52 "task" # GPT-5.2
|
|
162
|
+
coder --model gpt56sol "task" # GPT-5.6 Sol
|
|
163
|
+
coder --model gpt56terra "task" # GPT-5.6 Terra
|
|
158
164
|
|
|
159
165
|
# Custom model (JSON file)
|
|
160
166
|
coder --model ./mymodel.json "task"
|
|
161
167
|
```
|
|
162
168
|
|
|
169
|
+
A custom model JSON can also point at any OpenAI-compatible endpoint
|
|
170
|
+
(OpenAI directly, a local Ollama/vLLM server, etc.) instead of OpenRouter:
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"path": "gpt-4o-mini",
|
|
175
|
+
"base_url": "https://api.openai.com/v1",
|
|
176
|
+
"api_key_env": "OPENAI_API_KEY",
|
|
177
|
+
"temperature": 0.0
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`base_url` overrides the OpenRouter endpoint; `api_key_env` names the
|
|
182
|
+
environment variable holding the key for that endpoint (default:
|
|
183
|
+
`OPENROUTER_API_KEY`).
|
|
184
|
+
|
|
163
185
|
### Project Templates
|
|
164
186
|
|
|
165
187
|
Domain-specific templates improve results. Bundled examples are available on GitHub at [`coder/src/agentic_python_coder/examples/`](coder/src/agentic_python_coder/examples/). Use `--init` to copy them locally:
|
|
@@ -225,6 +247,7 @@ messages, stats, log_path = solve_task(
|
|
|
225
247
|
save_log=True, # Save conversation log
|
|
226
248
|
task_basename=None, # Base name for output files
|
|
227
249
|
step_limit=None, # Max agent steps (default: 200)
|
|
250
|
+
llm_config=None, # Pre-built LLMConfig (overrides model/api_key)
|
|
228
251
|
)
|
|
229
252
|
```
|
|
230
253
|
|
|
@@ -253,6 +276,25 @@ messages2, stats2 = run_agent(agent, "Now plot column A", quiet=True)
|
|
|
253
276
|
print(get_final_response(messages2))
|
|
254
277
|
```
|
|
255
278
|
|
|
279
|
+
Instead of a model name, you can pass a pre-built `LLMConfig` wrapping any
|
|
280
|
+
OpenAI-compatible client:
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
from openai import OpenAI
|
|
284
|
+
from agentic_python_coder import LLMConfig, create_coding_agent
|
|
285
|
+
|
|
286
|
+
llm_config = LLMConfig(
|
|
287
|
+
client=OpenAI(api_key="...", base_url="https://api.openai.com/v1"),
|
|
288
|
+
model="gpt-4o-mini",
|
|
289
|
+
api_params={"temperature": 0.0},
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
agent = create_coding_agent(
|
|
293
|
+
working_directory="/tmp/workspace",
|
|
294
|
+
llm_config=llm_config,
|
|
295
|
+
)
|
|
296
|
+
```
|
|
297
|
+
|
|
256
298
|
#### `get_openrouter_llm()` — LLM Access
|
|
257
299
|
|
|
258
300
|
```python
|
|
@@ -0,0 +1,48 @@
|
|
|
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=PQrKMi0_mKVeG1q2wXTu3-W2ZYKwYNjtPI_3A4m4Gvg,21284
|
|
5
|
+
agentic_python_coder/llm.py,sha256=zjsk4-Kdx92hFSxywPGIkLv8zflWnE2cMEcpeXu6ttw,6998
|
|
6
|
+
agentic_python_coder/mcp_server.py,sha256=2Z5O9n5QgZrgn3GdFljjF7Yq5e9tE1zNlAWBPyckrlI,18503
|
|
7
|
+
agentic_python_coder/project_md.py,sha256=4xkQHlWb4cDPEkvegw1YwcfaTJ3aFbrl0CYcC_xxABY,3249
|
|
8
|
+
agentic_python_coder/runner.py,sha256=Kbw1ceYJ4MVfUKgSIkiuBhMb8ZtbZuJwbBeTUsvPRts,13045
|
|
9
|
+
agentic_python_coder/tools.py,sha256=tjhQbsF3n3bFIegnEOtE8czjzbtMSXy6B9gYeb-YAJ4,12088
|
|
10
|
+
agentic_python_coder/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
agentic_python_coder/examples/clingo/README.md,sha256=SgWBqdJ2cHIfYWRV1YYqzfY0rth7mjCR5Act_hchcx0,2345
|
|
12
|
+
agentic_python_coder/examples/clingo/clingo.md,sha256=n8JOtpOww4T494OgLI_at8Zoz5pl7lv3AGOKlCA-cVE,52959
|
|
13
|
+
agentic_python_coder/examples/clingo/sample_tasks/bird_reasoning.md,sha256=OsOZDOzaj_wDEEhvq2raIK_P8VJY0Se6pgt3UJ8DY30,1660
|
|
14
|
+
agentic_python_coder/examples/clingo/sample_tasks/diagnosis.md,sha256=s5Q9WoLvInKcwitgY2TCdqFt4xdnxfd5FcMNywfT7p8,1818
|
|
15
|
+
agentic_python_coder/examples/clingo/sample_tasks/simple_coloring.md,sha256=T_44hh5nY-RSNw021DL-flEoLlfwyZMOheIf5-C0hE4,538
|
|
16
|
+
agentic_python_coder/examples/clingo/sample_tasks/stable_marriage.md,sha256=mWNAHmMstUq0VIYkDzrgK4PuiS59n6gMU3lMJrQ02c4,679
|
|
17
|
+
agentic_python_coder/examples/clingo/sample_tasks/sudoku_mini.md,sha256=rdEd3dkuh0V4sfosoXwEVe049T4QcOA4ZcgwdLQnC-M,475
|
|
18
|
+
agentic_python_coder/examples/cpmpy/README.md,sha256=4XqG8kvdBON6WGw5TPrGpqqBspuH2nsQ3NkZl9FzAM0,1399
|
|
19
|
+
agentic_python_coder/examples/cpmpy/cpmpy.md,sha256=O5WtJOoJl8i-MgzrFCbuCCGRrfo-zI8hZcCUkhzOqO0,4971
|
|
20
|
+
agentic_python_coder/examples/cpmpy/sample_tasks/magic_square.md,sha256=lUsnYoiJy7i6tXmFFISkTB6OrFTRPBDoxkJv9mceY-o,1127
|
|
21
|
+
agentic_python_coder/examples/cpmpy/sample_tasks/n_queens.md,sha256=WybTtZMlD28B1XAUf91IWqvrXIh5MTKWXHXnqfvpysM,848
|
|
22
|
+
agentic_python_coder/examples/regex/README.md,sha256=3K8nK-nVFrjweusS0Zdjt3Oh-UIc0mhgUuxVKGfi3QU,1378
|
|
23
|
+
agentic_python_coder/examples/regex/regex.md,sha256=3D64k-hoLiV_Io5LAjOXcdSrCNVAkKoqTzieOfXqM14,3126
|
|
24
|
+
agentic_python_coder/examples/regex/sample_tasks/email_extraction.md,sha256=M5_CZ1Tf-o1HBCqTlWszGQSYQ2QCkOxiIA08tRfoDiE,785
|
|
25
|
+
agentic_python_coder/examples/regex/sample_tasks/phone_validation.md,sha256=yoij3IlEDfWsNQ6UXkDUaNHPVbOb3pMcYO5v1pdLS-E,748
|
|
26
|
+
agentic_python_coder/examples/regex/sample_tasks/url_parsing.md,sha256=C2E6ze-AeIXbzM-gB0aJ3_QSiaJB3c2MbMTNJXzuYhA,1683
|
|
27
|
+
agentic_python_coder/models/deepseek31.json,sha256=42qWgfBn2ErZndbpp-4-JtqRna2xlwzkfCaYnKFEboQ,104
|
|
28
|
+
agentic_python_coder/models/gemini25.json,sha256=I3nNMz2GwhFQLtHtZotV3hNUyWXq9ToMm96byM98LFA,123
|
|
29
|
+
agentic_python_coder/models/gemini31.json,sha256=q8y8pPEZE1hsv2vV7c1KckPHKE7Gfbi51xQgwM62i-o,117
|
|
30
|
+
agentic_python_coder/models/gemini3flash.json,sha256=S0AMVpzi3O5CQk68Q3Hi8iCHXMQQFnM4NbSh23x0qIM,91
|
|
31
|
+
agentic_python_coder/models/gemini3pro.json,sha256=5yWdmtkKSpAvr8svGjAgSoXvCnu1SCoVnhdbx-1L4fQ,131
|
|
32
|
+
agentic_python_coder/models/gpt52.json,sha256=oDYxC21iQTKC9uVbFRlAs-hCnu_4cEDFK3mmqPVIIes,84
|
|
33
|
+
agentic_python_coder/models/gpt56sol.json,sha256=xFNDxSz0ZC2qtDldgZ3ms1ela1InmhL5x_-UZktR1K8,88
|
|
34
|
+
agentic_python_coder/models/gpt56terra.json,sha256=NnVvnnF7EMK-pADCZsm1fJ8O8DLCT4obHc0x_00kcus,90
|
|
35
|
+
agentic_python_coder/models/grok41.json,sha256=l76RtbnFiNNQEe_dFoxn0HNbjgTcOMk5MswYqhcw764,96
|
|
36
|
+
agentic_python_coder/models/opus45.json,sha256=wbRqoIrn1CSlu0pRnpR2S-1j1zWGD_jza7udZNnU3wY,87
|
|
37
|
+
agentic_python_coder/models/opus48.json,sha256=grMqaY0sCQnZeH4VxsPfwUIqlHpxNxTjmM47hHuyPkY,87
|
|
38
|
+
agentic_python_coder/models/qwen3.json,sha256=TJuIx5EllPIc8QBnagINlhNVxkLlsSDWRZAsFMqP_lo,94
|
|
39
|
+
agentic_python_coder/models/sonnet45.json,sha256=WeWezJxt4r7IugBMzRbnSIocmmcd6qc_756M4CHdEa8,89
|
|
40
|
+
agentic_python_coder/models/sonnet46.json,sha256=Ops1FpBoyx9PBGRhIXG8u-YGBgIui9DqvYxIc2BkJFM,89
|
|
41
|
+
agentic_python_coder/models/sonnet5.json,sha256=kf6DIkQlcGVZ40IzRv3GXFtNncZF_gKqQeGzZAxE_KM,87
|
|
42
|
+
agentic_python_coder/prompts/system.md,sha256=hREDVAhJXwCBAgJ3AE9JD6j-JRHREUPlkRSvThOvM3A,3807
|
|
43
|
+
agentic_python_coder/prompts/system_todo.md,sha256=TuNeeUNS9KqyF62Da6t2mlUCYhKsgzwGe5ic_vFPDqw,5054
|
|
44
|
+
agentic_python_coder-3.3.0.dist-info/METADATA,sha256=ec4FIlQitVNa_5bMQhu2NPpJV-5VwDRQy1hzK_4b_G8,12872
|
|
45
|
+
agentic_python_coder-3.3.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
46
|
+
agentic_python_coder-3.3.0.dist-info/entry_points.txt,sha256=XIW3nZzL4kJ-Igohilj_mTvBcCyHBouDq2jmGzDILrk,107
|
|
47
|
+
agentic_python_coder-3.3.0.dist-info/licenses/LICENSE,sha256=R9-M_V-SPdN71IphOVzM7kCNpUYs_hwj7rtroTwDhs0,11362
|
|
48
|
+
agentic_python_coder-3.3.0.dist-info/RECORD,,
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
agentic_python_coder/__init__.py,sha256=AE7tDIivH7H0BBwhrR9C64rY6pO1d6AWDQYGAvGjeuk,1881
|
|
2
|
-
agentic_python_coder/agent.py,sha256=Z7I0zvh3XEouPgt9hvkSIKYuZyHfsTrsTEFiJjsK4hk,12821
|
|
3
|
-
agentic_python_coder/cli.py,sha256=pjmKHwLmC41wJ4Z6tQPFNeS2VwC-HCvtXklmv__xOco,14349
|
|
4
|
-
agentic_python_coder/kernel.py,sha256=Xjqsl-Rzb6JBqWMTE4JBsxNsy1eRVUL5FvtfT1OFLD4,20541
|
|
5
|
-
agentic_python_coder/llm.py,sha256=8BxNK8FmECbcJhP5qeB8IxErbm1NKBZO4Z-bB5-JtaE,6157
|
|
6
|
-
agentic_python_coder/mcp_server.py,sha256=U_YfjeUvaVJ4poCsIqkzOx70J190RYH2Ln_H5tDc6Zg,18508
|
|
7
|
-
agentic_python_coder/project_md.py,sha256=c4A-rbsc3ryqUkCJLGOKBHH8QJL5kAqvTSsM0tDeD4Y,3041
|
|
8
|
-
agentic_python_coder/runner.py,sha256=AtdtRusD5ThTlsdL2SDjYk73jD0fYRWkJ4vmpeIWBl4,12683
|
|
9
|
-
agentic_python_coder/tools.py,sha256=Qo_VI5ABqrHOFb80JlwYbH_RJmgCNZagFsTv7RmJNNE,11127
|
|
10
|
-
agentic_python_coder/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
agentic_python_coder/examples/clingo/README.md,sha256=SgWBqdJ2cHIfYWRV1YYqzfY0rth7mjCR5Act_hchcx0,2345
|
|
12
|
-
agentic_python_coder/examples/clingo/clingo.md,sha256=VhIcECJwbmoV8T-GKok27Er_AvDpKj1qnzz4Zn7ddBI,49901
|
|
13
|
-
agentic_python_coder/examples/clingo/sample_tasks/bird_reasoning.md,sha256=OsOZDOzaj_wDEEhvq2raIK_P8VJY0Se6pgt3UJ8DY30,1660
|
|
14
|
-
agentic_python_coder/examples/clingo/sample_tasks/diagnosis.md,sha256=s5Q9WoLvInKcwitgY2TCdqFt4xdnxfd5FcMNywfT7p8,1818
|
|
15
|
-
agentic_python_coder/examples/clingo/sample_tasks/simple_coloring.md,sha256=T_44hh5nY-RSNw021DL-flEoLlfwyZMOheIf5-C0hE4,538
|
|
16
|
-
agentic_python_coder/examples/clingo/sample_tasks/stable_marriage.md,sha256=mWNAHmMstUq0VIYkDzrgK4PuiS59n6gMU3lMJrQ02c4,679
|
|
17
|
-
agentic_python_coder/examples/clingo/sample_tasks/sudoku_mini.md,sha256=rdEd3dkuh0V4sfosoXwEVe049T4QcOA4ZcgwdLQnC-M,475
|
|
18
|
-
agentic_python_coder/examples/cpmpy/README.md,sha256=4XqG8kvdBON6WGw5TPrGpqqBspuH2nsQ3NkZl9FzAM0,1399
|
|
19
|
-
agentic_python_coder/examples/cpmpy/cpmpy.md,sha256=tQpZpM2CO1lG0r-_TGYi-fd9KrdyGr6kyqyeWjyPECs,2207
|
|
20
|
-
agentic_python_coder/examples/cpmpy/sample_tasks/magic_square.md,sha256=lUsnYoiJy7i6tXmFFISkTB6OrFTRPBDoxkJv9mceY-o,1127
|
|
21
|
-
agentic_python_coder/examples/cpmpy/sample_tasks/n_queens.md,sha256=WybTtZMlD28B1XAUf91IWqvrXIh5MTKWXHXnqfvpysM,848
|
|
22
|
-
agentic_python_coder/examples/regex/README.md,sha256=3K8nK-nVFrjweusS0Zdjt3Oh-UIc0mhgUuxVKGfi3QU,1378
|
|
23
|
-
agentic_python_coder/examples/regex/regex.md,sha256=3D64k-hoLiV_Io5LAjOXcdSrCNVAkKoqTzieOfXqM14,3126
|
|
24
|
-
agentic_python_coder/examples/regex/sample_tasks/email_extraction.md,sha256=M5_CZ1Tf-o1HBCqTlWszGQSYQ2QCkOxiIA08tRfoDiE,785
|
|
25
|
-
agentic_python_coder/examples/regex/sample_tasks/phone_validation.md,sha256=yoij3IlEDfWsNQ6UXkDUaNHPVbOb3pMcYO5v1pdLS-E,748
|
|
26
|
-
agentic_python_coder/examples/regex/sample_tasks/url_parsing.md,sha256=C2E6ze-AeIXbzM-gB0aJ3_QSiaJB3c2MbMTNJXzuYhA,1683
|
|
27
|
-
agentic_python_coder/models/deepseek31.json,sha256=m3h2-rieY23gTXj9AOFoWxnrYUfqNpDpyNpPW0SMqVE,125
|
|
28
|
-
agentic_python_coder/models/gemini25.json,sha256=Z9qJrIUNel366A3hSdg3qQixTh-EU8lehXKebW-XEUY,144
|
|
29
|
-
agentic_python_coder/models/gemini3flash.json,sha256=S0AMVpzi3O5CQk68Q3Hi8iCHXMQQFnM4NbSh23x0qIM,91
|
|
30
|
-
agentic_python_coder/models/gemini3pro.json,sha256=ptozne-ZwpmuXzpt2x0ZApMIvb5VsWskqI36XscCsrg,152
|
|
31
|
-
agentic_python_coder/models/gpt52.json,sha256=rGYoD83_yioSDJvO3o4FSFhi0B2yTaOpCgr_XpRaPWk,105
|
|
32
|
-
agentic_python_coder/models/grok41.json,sha256=bUFtp2orkBmfiLH7mE8SaS0YEe2kJFF1Ex2jb03p9SA,117
|
|
33
|
-
agentic_python_coder/models/opus45.json,sha256=ujBiZiA-6YNbQxd3xWlGT7YGtEtbWMC8e2TP0I8Gtho,108
|
|
34
|
-
agentic_python_coder/models/qwen3.json,sha256=Lj39r787EcfUcKXfO52aplYurkpM9mG1qg71UkaqVfQ,115
|
|
35
|
-
agentic_python_coder/models/sonnet45.json,sha256=SXDBHwSRMlqG77i4OhvNDlHL7fESnCoqmEplXm3gP4k,110
|
|
36
|
-
agentic_python_coder/prompts/system.md,sha256=hREDVAhJXwCBAgJ3AE9JD6j-JRHREUPlkRSvThOvM3A,3807
|
|
37
|
-
agentic_python_coder/prompts/system_todo.md,sha256=TuNeeUNS9KqyF62Da6t2mlUCYhKsgzwGe5ic_vFPDqw,5054
|
|
38
|
-
agentic_python_coder-3.1.0.dist-info/METADATA,sha256=xnk9vllNKDqyvwZrIc2LH-g7d2O87wGzd5B2i6PAqps,11564
|
|
39
|
-
agentic_python_coder-3.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
40
|
-
agentic_python_coder-3.1.0.dist-info/entry_points.txt,sha256=XIW3nZzL4kJ-Igohilj_mTvBcCyHBouDq2jmGzDILrk,107
|
|
41
|
-
agentic_python_coder-3.1.0.dist-info/licenses/LICENSE,sha256=R9-M_V-SPdN71IphOVzM7kCNpUYs_hwj7rtroTwDhs0,11362
|
|
42
|
-
agentic_python_coder-3.1.0.dist-info/RECORD,,
|
{agentic_python_coder-3.1.0.dist-info → agentic_python_coder-3.3.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{agentic_python_coder-3.1.0.dist-info → agentic_python_coder-3.3.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|