agentic-python-coder 3.3.0__tar.gz → 3.4.1__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.
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/.gitignore +0 -4
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/PKG-INFO +1 -1
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/kernel.py +58 -7
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/mcp_server.py +101 -5
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/pyproject.toml +5 -1
- agentic_python_coder-3.3.0/MEM/MEM_000.md +0 -131
- agentic_python_coder-3.3.0/MEM/MEM_001_frameworkless_react_agent.md +0 -110
- agentic_python_coder-3.3.0/MEM/MEM_002_tool_description_quality.md +0 -107
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/LICENSE +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/README.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/.gitignore +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/prompts/system.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/prompts/system_todo.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/__init__.py +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/agent.py +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/cli.py +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/__init__.py +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/clingo/README.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/clingo/clingo.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/clingo/sample_tasks/bird_reasoning.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/clingo/sample_tasks/diagnosis.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/clingo/sample_tasks/simple_coloring.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/clingo/sample_tasks/stable_marriage.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/clingo/sample_tasks/sudoku_mini.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/cpmpy/README.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/cpmpy/cpmpy.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/cpmpy/sample_tasks/magic_square.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/cpmpy/sample_tasks/n_queens.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/regex/README.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/regex/regex.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/regex/sample_tasks/email_extraction.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/regex/sample_tasks/phone_validation.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/examples/regex/sample_tasks/url_parsing.md +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/llm.py +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/deepseek31.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/gemini25.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/gemini31.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/gemini3flash.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/gemini3pro.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/gpt52.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/gpt56sol.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/gpt56terra.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/grok41.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/opus45.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/opus48.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/qwen3.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/sonnet45.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/sonnet46.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/models/sonnet5.json +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/project_md.py +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/runner.py +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/tools.py +0 -0
- {agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/examples/clingo/clingo.md +0 -0
|
@@ -154,7 +154,6 @@ uv.lock
|
|
|
154
154
|
# Project specific
|
|
155
155
|
tests/
|
|
156
156
|
coder-examples/
|
|
157
|
-
CLAUDE-archive.md
|
|
158
157
|
EXPERTISE/
|
|
159
158
|
PROCESS_NOTES.md
|
|
160
159
|
conversation_log.json
|
|
@@ -162,8 +161,6 @@ coder_output.log
|
|
|
162
161
|
task.md
|
|
163
162
|
solution.py
|
|
164
163
|
*.tmp
|
|
165
|
-
CLAUDE.md
|
|
166
|
-
**/CLAUDE.md
|
|
167
164
|
TRASH/
|
|
168
165
|
LOCAL/
|
|
169
166
|
ASP/
|
|
@@ -172,7 +169,6 @@ CPMPY/
|
|
|
172
169
|
PAPER/
|
|
173
170
|
PAPER-ASP/
|
|
174
171
|
ZEBRA/
|
|
175
|
-
.mcp.json
|
|
176
172
|
|
|
177
173
|
# Test files and folders (root level only)
|
|
178
174
|
/test-*/
|
{agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/kernel.py
RENAMED
|
@@ -10,6 +10,7 @@ import logging
|
|
|
10
10
|
import os
|
|
11
11
|
import re
|
|
12
12
|
import shutil
|
|
13
|
+
import signal
|
|
13
14
|
import threading
|
|
14
15
|
import time
|
|
15
16
|
import uuid
|
|
@@ -219,13 +220,13 @@ except ImportError:
|
|
|
219
220
|
self._execute_raw(startup_code)
|
|
220
221
|
|
|
221
222
|
def _cleanup_on_error(self):
|
|
222
|
-
"""Clean up resources if initialization fails.
|
|
223
|
+
"""Clean up resources if initialization fails.
|
|
224
|
+
|
|
225
|
+
Routes through shutdown() so a partially-started kernel tree gets
|
|
226
|
+
the same defensive process-group kill as a healthy one.
|
|
227
|
+
"""
|
|
223
228
|
try:
|
|
224
|
-
|
|
225
|
-
self.kc.stop_channels()
|
|
226
|
-
if hasattr(self, "km") and self.km:
|
|
227
|
-
if self.km.is_alive():
|
|
228
|
-
self.km.shutdown_kernel(now=True)
|
|
229
|
+
self.shutdown()
|
|
229
230
|
except Exception:
|
|
230
231
|
pass # Best effort cleanup
|
|
231
232
|
|
|
@@ -311,7 +312,21 @@ except ImportError:
|
|
|
311
312
|
return self._execute_raw(code, deadline_timeout)
|
|
312
313
|
|
|
313
314
|
def shutdown(self):
|
|
314
|
-
"""Shutdown the kernel and clean up.
|
|
315
|
+
"""Shutdown the kernel and clean up.
|
|
316
|
+
|
|
317
|
+
Kernels run in their own process group (jupyter_client launches with
|
|
318
|
+
start_new_session=True). After the regular shutdown, defensively kill
|
|
319
|
+
the whole group: uv-wrapped kernels are a tree (uv parent + python
|
|
320
|
+
child) and a surviving member would be orphaned.
|
|
321
|
+
"""
|
|
322
|
+
# Capture the kernel's process group before shutdown clears it
|
|
323
|
+
pgid = None
|
|
324
|
+
try:
|
|
325
|
+
if hasattr(self, "km") and self.km:
|
|
326
|
+
pgid = getattr(getattr(self.km, "provisioner", None), "pgid", None)
|
|
327
|
+
except Exception:
|
|
328
|
+
pass
|
|
329
|
+
|
|
315
330
|
try:
|
|
316
331
|
if hasattr(self, "kc") and self.kc:
|
|
317
332
|
try:
|
|
@@ -330,6 +345,15 @@ except ImportError:
|
|
|
330
345
|
# Ignore errors during shutdown
|
|
331
346
|
pass
|
|
332
347
|
|
|
348
|
+
# Defensive: ensure no process-tree member survived. Never signal our
|
|
349
|
+
# own group (pgid could be bogus if start_new_session did not apply).
|
|
350
|
+
if pgid and pgid > 0:
|
|
351
|
+
try:
|
|
352
|
+
if pgid != os.getpgid(0):
|
|
353
|
+
os.killpg(pgid, signal.SIGKILL)
|
|
354
|
+
except (ProcessLookupError, PermissionError, OSError):
|
|
355
|
+
pass
|
|
356
|
+
|
|
333
357
|
|
|
334
358
|
# =============================================================================
|
|
335
359
|
# Core Registry Functions
|
|
@@ -603,6 +627,33 @@ def shutdown_all_kernels():
|
|
|
603
627
|
pass # Best effort
|
|
604
628
|
|
|
605
629
|
|
|
630
|
+
def kill_all_kernel_process_groups():
|
|
631
|
+
"""Hard-kill (SIGKILL) every registered kernel's process group.
|
|
632
|
+
|
|
633
|
+
Deliberately lock-free: this is the termination path, where a busy
|
|
634
|
+
kernel's _exec_lock may be held indefinitely by an in-flight execution
|
|
635
|
+
and the graceful shutdown_all_kernels() would block behind it. Snapshot
|
|
636
|
+
the registry and signal each group directly. Never signals our own
|
|
637
|
+
process group. Kernels mid-creation (registry slot still None) cannot
|
|
638
|
+
be reached here — that sub-second window is a known limitation.
|
|
639
|
+
"""
|
|
640
|
+
try:
|
|
641
|
+
own_pgid = os.getpgid(0)
|
|
642
|
+
except OSError:
|
|
643
|
+
own_pgid = None
|
|
644
|
+
|
|
645
|
+
for state in list(_kernels.values()):
|
|
646
|
+
if state is None:
|
|
647
|
+
continue
|
|
648
|
+
try:
|
|
649
|
+
km = state.kernel.km
|
|
650
|
+
pgid = getattr(getattr(km, "provisioner", None), "pgid", None)
|
|
651
|
+
if pgid and pgid > 0 and pgid != own_pgid:
|
|
652
|
+
os.killpg(pgid, signal.SIGKILL)
|
|
653
|
+
except (ProcessLookupError, PermissionError, OSError, AttributeError):
|
|
654
|
+
pass # Best effort
|
|
655
|
+
|
|
656
|
+
|
|
606
657
|
# =============================================================================
|
|
607
658
|
# Backward Compatibility API
|
|
608
659
|
# =============================================================================
|
|
@@ -7,6 +7,9 @@ import ast
|
|
|
7
7
|
import asyncio
|
|
8
8
|
import json
|
|
9
9
|
import logging
|
|
10
|
+
import os
|
|
11
|
+
import signal
|
|
12
|
+
import threading
|
|
10
13
|
|
|
11
14
|
from mcp.server import Server
|
|
12
15
|
from mcp.server.stdio import stdio_server
|
|
@@ -18,8 +21,10 @@ from agentic_python_coder.kernel import (
|
|
|
18
21
|
execute_in_kernel,
|
|
19
22
|
interrupt_kernel_by_id,
|
|
20
23
|
kernel_exists,
|
|
24
|
+
kill_all_kernel_process_groups,
|
|
21
25
|
list_kernels,
|
|
22
26
|
restart_kernel,
|
|
27
|
+
shutdown_all_kernels,
|
|
23
28
|
)
|
|
24
29
|
|
|
25
30
|
# Configure logging
|
|
@@ -32,6 +37,7 @@ server = Server("ipython_mcp")
|
|
|
32
37
|
MAX_OUTPUT = 100 * 1024 # 100KB truncation limit
|
|
33
38
|
MAX_TIMEOUT = 300 # Maximum allowed timeout in seconds
|
|
34
39
|
DEFAULT_TIMEOUT = 30 # Default timeout in seconds
|
|
40
|
+
STATUS_PROBE_TIMEOUT = 10 # Timeout for python_status introspection probes
|
|
35
41
|
KERNEL_TIMEOUT_BUFFER = 5 # Extra seconds for kernel deadline vs asyncio timeout
|
|
36
42
|
|
|
37
43
|
# Async lock for session operations (default kernel management)
|
|
@@ -240,6 +246,30 @@ No side effects - safe to call anytime.""",
|
|
|
240
246
|
},
|
|
241
247
|
},
|
|
242
248
|
),
|
|
249
|
+
Tool(
|
|
250
|
+
name="submit_code",
|
|
251
|
+
description="""Submit your final, verified, self-contained Python program.
|
|
252
|
+
|
|
253
|
+
Call this ONCE at the end of a solve, only after you have executed the program
|
|
254
|
+
via python_exec and your verification passed. The submission must be a
|
|
255
|
+
standalone program: all imports included, no reliance on session state.
|
|
256
|
+
|
|
257
|
+
The code is syntax-checked with compile():
|
|
258
|
+
- {"ok": true} if it parses
|
|
259
|
+
- {"ok": false, "error": "<detail>"} on a syntax error — fix and resubmit
|
|
260
|
+
|
|
261
|
+
The code is NOT executed and NOT written to disk; the client persists it.""",
|
|
262
|
+
inputSchema={
|
|
263
|
+
"type": "object",
|
|
264
|
+
"properties": {
|
|
265
|
+
"code": {
|
|
266
|
+
"type": "string",
|
|
267
|
+
"description": "Complete standalone Python program (final answer).",
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
"required": ["code"],
|
|
271
|
+
},
|
|
272
|
+
),
|
|
243
273
|
Tool(
|
|
244
274
|
name="python_interrupt",
|
|
245
275
|
description="""Interrupt running code in the session.
|
|
@@ -318,7 +348,9 @@ versions
|
|
|
318
348
|
% packages
|
|
319
349
|
)
|
|
320
350
|
try:
|
|
321
|
-
result = await execute_with_timeout(
|
|
351
|
+
result = await execute_with_timeout(
|
|
352
|
+
version_code, DEFAULT_TIMEOUT, kernel_id
|
|
353
|
+
)
|
|
322
354
|
if result.get("result"):
|
|
323
355
|
versions = ast.literal_eval(result["result"])
|
|
324
356
|
if isinstance(versions, dict):
|
|
@@ -391,6 +423,24 @@ versions
|
|
|
391
423
|
result = await execute_with_timeout(code, timeout, kernel_id)
|
|
392
424
|
return [TextContent(type="text", text=json.dumps(result))]
|
|
393
425
|
|
|
426
|
+
elif name == "submit_code":
|
|
427
|
+
code = arguments.get("code", "")
|
|
428
|
+
if not code.strip():
|
|
429
|
+
payload = {"ok": False, "error": "Empty submission"}
|
|
430
|
+
else:
|
|
431
|
+
try:
|
|
432
|
+
compile(code, "<submission>", "exec")
|
|
433
|
+
payload = {"ok": True}
|
|
434
|
+
except SyntaxError as e:
|
|
435
|
+
payload = {
|
|
436
|
+
"ok": False,
|
|
437
|
+
"error": f"Syntax error at line {e.lineno or '?'}: {e.msg}",
|
|
438
|
+
}
|
|
439
|
+
except ValueError as e:
|
|
440
|
+
# compile() raises ValueError e.g. for null bytes in source
|
|
441
|
+
payload = {"ok": False, "error": f"Invalid source: {e}"}
|
|
442
|
+
return [TextContent(type="text", text=json.dumps(payload))]
|
|
443
|
+
|
|
394
444
|
elif name == "python_status":
|
|
395
445
|
kernel_id = get_kernel_id(arguments)
|
|
396
446
|
is_active = kernel_exists(kernel_id)
|
|
@@ -412,7 +462,7 @@ versions
|
|
|
412
462
|
# Get Python version
|
|
413
463
|
try:
|
|
414
464
|
result = await execute_with_timeout(
|
|
415
|
-
"import sys; sys.version",
|
|
465
|
+
"import sys; sys.version", STATUS_PROBE_TIMEOUT, kernel_id
|
|
416
466
|
)
|
|
417
467
|
if result.get("result"):
|
|
418
468
|
status["python_version"] = result["result"].strip("'\"")
|
|
@@ -426,7 +476,9 @@ import importlib.metadata
|
|
|
426
476
|
[f"{d.metadata['Name']} {d.version}" for d in importlib.metadata.distributions()
|
|
427
477
|
if d.metadata['Name'] not in ('pip', 'setuptools', 'wheel', 'ipykernel', 'jupyter-client')][:20]
|
|
428
478
|
"""
|
|
429
|
-
result = await execute_with_timeout(
|
|
479
|
+
result = await execute_with_timeout(
|
|
480
|
+
pkg_code, STATUS_PROBE_TIMEOUT, kernel_id
|
|
481
|
+
)
|
|
430
482
|
if result.get("result"):
|
|
431
483
|
status["packages"] = ast.literal_eval(result["result"])
|
|
432
484
|
except Exception:
|
|
@@ -438,7 +490,9 @@ import importlib.metadata
|
|
|
438
490
|
[name for name in dir() if not name.startswith('_')
|
|
439
491
|
and name not in ('In', 'Out', 'get_ipython', 'exit', 'quit', 'open')]
|
|
440
492
|
"""
|
|
441
|
-
result = await execute_with_timeout(
|
|
493
|
+
result = await execute_with_timeout(
|
|
494
|
+
var_code, STATUS_PROBE_TIMEOUT, kernel_id
|
|
495
|
+
)
|
|
442
496
|
if result.get("result"):
|
|
443
497
|
status["variables"] = ast.literal_eval(result["result"])
|
|
444
498
|
except Exception:
|
|
@@ -521,9 +575,51 @@ async def run_server():
|
|
|
521
575
|
await server.run(read, write, server.create_initialization_options())
|
|
522
576
|
|
|
523
577
|
|
|
578
|
+
# Hard-exit fallback if kernel cleanup hangs after a termination signal
|
|
579
|
+
_TERMINATION_CLEANUP_TIMEOUT = 10.0
|
|
580
|
+
|
|
581
|
+
# Set on the first termination signal; later signals are ignored instead of
|
|
582
|
+
# stacking additional timers and cleanup threads
|
|
583
|
+
_terminating = threading.Event()
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
def _handle_termination(signum, frame):
|
|
587
|
+
"""Shut down all kernels on SIGTERM/SIGINT, then exit.
|
|
588
|
+
|
|
589
|
+
Kernel process groups are hard-killed first (lock-free, cannot block on
|
|
590
|
+
a busy kernel's exec lock); the graceful registry cleanup then runs in a
|
|
591
|
+
thread, with a timer that hard-exits if it hangs.
|
|
592
|
+
"""
|
|
593
|
+
if _terminating.is_set():
|
|
594
|
+
return
|
|
595
|
+
_terminating.set()
|
|
596
|
+
|
|
597
|
+
def _cleanup_and_exit():
|
|
598
|
+
try:
|
|
599
|
+
kill_all_kernel_process_groups()
|
|
600
|
+
shutdown_all_kernels()
|
|
601
|
+
finally:
|
|
602
|
+
os._exit(128 + signum)
|
|
603
|
+
|
|
604
|
+
threading.Timer(
|
|
605
|
+
_TERMINATION_CLEANUP_TIMEOUT, lambda: os._exit(128 + signum)
|
|
606
|
+
).start()
|
|
607
|
+
threading.Thread(target=_cleanup_and_exit, daemon=True).start()
|
|
608
|
+
|
|
609
|
+
|
|
524
610
|
def main():
|
|
525
611
|
"""Entry point for coder-mcp command."""
|
|
526
|
-
|
|
612
|
+
signal.signal(signal.SIGTERM, _handle_termination)
|
|
613
|
+
signal.signal(signal.SIGINT, _handle_termination)
|
|
614
|
+
try:
|
|
615
|
+
asyncio.run(run_server())
|
|
616
|
+
finally:
|
|
617
|
+
# stdin EOF / transport close / normal exit: the client is gone, so
|
|
618
|
+
# hard-kill kernel groups first (immune to a busy kernel's exec
|
|
619
|
+
# lock), then clean up the registry (atexit also runs the graceful
|
|
620
|
+
# path, but only on clean interpreter shutdown)
|
|
621
|
+
kill_all_kernel_process_groups()
|
|
622
|
+
shutdown_all_kernels()
|
|
527
623
|
|
|
528
624
|
|
|
529
625
|
if __name__ == "__main__":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "agentic-python-coder"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.4.1"
|
|
4
4
|
description = "A lightweight Python coding agent that writes, executes, and iterates on code through natural language instructions"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.13,<3.14"
|
|
@@ -60,6 +60,10 @@ exclude = [
|
|
|
60
60
|
"*.jsonl",
|
|
61
61
|
"*_code.py",
|
|
62
62
|
"RELEASE_NOTES_*.md",
|
|
63
|
+
"CLAUDE.md",
|
|
64
|
+
"CLAUDE-archive.md",
|
|
65
|
+
"MEM/",
|
|
66
|
+
".claude/",
|
|
63
67
|
]
|
|
64
68
|
|
|
65
69
|
[tool.hatch.build.targets.wheel]
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
keywords: [session log, process notes, history]
|
|
3
|
-
context: Searchable session log — grep when needed, not loaded routinely
|
|
4
|
-
added: 2026-01-31
|
|
5
|
-
---
|
|
6
|
-
# Process Notes
|
|
7
|
-
|
|
8
|
-
Searchable session log. Not loaded routinely—search with grep when needed.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
## 2026-02-23
|
|
12
|
-
|
|
13
|
-
**Goal**: Add new model configs (sonnet46, gemini31) and publish v3.2.0
|
|
14
|
-
|
|
15
|
-
**Done**:
|
|
16
|
-
- Created sonnet46.json (anthropic/claude-sonnet-4.6, temp 0.0)
|
|
17
|
-
- Created gemini31.json (google/gemini-3.1-pro-preview, temp 0.0, timeout 120)
|
|
18
|
-
- Added reasoning/thinking token support in llm.py
|
|
19
|
-
- Bumped version to 3.2.0, all 70 unit tests pass
|
|
20
|
-
- Published to PyPI
|
|
21
|
-
|
|
22
|
-
**Tried**:
|
|
23
|
-
- Initially copied gemini3pro params (temp 0.3, top_p 0.9) for gemini31 — Stefan corrected to temp 0.0, no top_p
|
|
24
|
-
|
|
25
|
-
**Notes**: Quick session. Stefan provided the gemini model path directly (google/gemini-3.1-pro-preview).
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
## 2026-02-15
|
|
29
|
-
|
|
30
|
-
**Goal**: Routine maintenance — dependency updates, new model config, code review fixes
|
|
31
|
-
|
|
32
|
-
**Done**:
|
|
33
|
-
- Bumped deps: openai 2.16→2.21, rich 14.3.1→14.3.2, ipykernel 7.1→7.2
|
|
34
|
-
- Added gemini3flash model config (Gemini 3 Flash Preview)
|
|
35
|
-
- Code review (ULTRA) found 6 issues in llm.py — all fixed: provider routing bug, OSError handling, model_path→model_id rename, empty "Available:" message, Warning→Error label, unnecessary ./ prefix
|
|
36
|
-
- Published v3.1.0 to PyPI
|
|
37
|
-
- Migrated EXPERTISE/ → MEM/ (2 entries + PROCESS_NOTES.md)
|
|
38
|
-
|
|
39
|
-
**Tried**:
|
|
40
|
-
- Initially copied gemini3pro.json params blindly for gemini3flash — Stefan caught this, verified actual supported params via WS7
|
|
41
|
-
|
|
42
|
-
**Notes**: PyPI token is at ~/git/.pipy.txt (updated CLAUDE.md to record this)
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
## 2026-01-31 (session 3)
|
|
48
|
-
|
|
49
|
-
**Goal**: Run e2e benchmark tests across models, fix failures, improve prompts, merge v3.0.0 to main, publish to PyPI
|
|
50
|
-
|
|
51
|
-
**Done**:
|
|
52
|
-
- Ran hard problem benchmarks (5 CPMpy + 5 Clingo) across opus45, gpt52, gemini3pro
|
|
53
|
-
- Created gemini3pro.json model config (google/gemini-3-pro-preview)
|
|
54
|
-
- Fixed gpt52 max_tokens: 3000→16384 (was truncating tool calls, caused 0/5 Clingo)
|
|
55
|
-
- Rewrote Clingo validate.py (old one was wrong ASP-Bench full-suite validator)
|
|
56
|
-
- Added mandatory verification prompts to system.md, system_todo.md, and save_code tool description
|
|
57
|
-
- Analyzed GPT-5.2 CPMpy failures with GPPT consult (circular verification, wrong problem interpretation)
|
|
58
|
-
- Fixed flaky test_todo_flag_integration (catch TimeoutExpired for partial output)
|
|
59
|
-
- Squash-merged dev→main, published v3.0.0 to PyPI
|
|
60
|
-
- Updated README: examples link, gemini3pro in model list
|
|
61
|
-
|
|
62
|
-
**Tried**:
|
|
63
|
-
- Verification prompts in system prompt + tool description — improved opus45 CPMpy 4/5→5/5 and gpt52 Clingo 0/5→5/5
|
|
64
|
-
- GPT-5.2 on CPMpy still only 2/5 despite verification prompts — model sometimes ignores them (2 tool calls before save) or writes circular verify()
|
|
65
|
-
- Gemini 3 Pro initially 0/10 with max_tokens=2048; bumped to 16384 → 5/10
|
|
66
|
-
|
|
67
|
-
**Notes**: Key insight — verification gates work but models can write verify() functions that re-implement solver bugs instead of checking problem text independently. Future prompt work should address this circular verification pitfall.
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## 2026-01-31 (session 2)
|
|
72
|
-
|
|
73
|
-
**Goal**: Clean up dev branch for v3.0.0 release — model configs, tool descriptions, README, examples consolidation
|
|
74
|
-
|
|
75
|
-
**Done**:
|
|
76
|
-
- Replaced gpt5 model config with gpt52 (openai/gpt-5.2)
|
|
77
|
-
- Restored verbose LangGraph-era tool descriptions in tools.py (fixes performance regression on hard tasks)
|
|
78
|
-
- Restored parameter schemas to match tested reference (title fields, additionalProperties style)
|
|
79
|
-
- Created EXPERTISE/E002_tool_description_quality.md
|
|
80
|
-
- Removed LangGraph badge and references from README
|
|
81
|
-
- Bumped all dependency minimum versions to current
|
|
82
|
-
- Consolidated examples: deleted legacy examples/ dir, kept only bundled coder/src/.../examples/
|
|
83
|
-
- Confirmed _todo.md project prompts are unused (--todo only switches system prompt)
|
|
84
|
-
- Improved CPMpy project prompt with InDomain constraint and pitfalls section
|
|
85
|
-
- Copied e2e challenge tests (hard_cpmpy, hard_clingo) to tests/ (gitignored)
|
|
86
|
-
- All 70 unit tests pass
|
|
87
|
-
|
|
88
|
-
**Tried**:
|
|
89
|
-
- Initially kept minimal tool descriptions after LangGraph removal — caused performance regression on challenging tasks, discovered in separate test session
|
|
90
|
-
- Tried using "description" field in JSON schemas instead of "title" — reverted to match LangGraph-generated style that was proven to work
|
|
91
|
-
|
|
92
|
-
**Notes**: Tool descriptions are behavioral instructions for the model, not documentation. Verbose descriptions with examples, Args/Returns sections are essential for tool-calling quality. This is documented in E002.
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
## 2026-01-31
|
|
97
|
-
|
|
98
|
-
**Goal**: Update model configs and fix tool description regression
|
|
99
|
-
|
|
100
|
-
**Done**:
|
|
101
|
-
- Replaced gpt5 model config with gpt52 (openai/gpt-5.2) — JSON, README, tests
|
|
102
|
-
- Restored tool descriptions in tools.py to verbose LangGraph-era format (critical for performance)
|
|
103
|
-
- Restored parameter schemas to match tested reference (title fields, additionalProperties style)
|
|
104
|
-
- Created EXPERTISE/E002_tool_description_quality.md
|
|
105
|
-
- Removed unused _task_basename import in test_library_api.py
|
|
106
|
-
|
|
107
|
-
**Tried**:
|
|
108
|
-
- Initially kept minimal tool descriptions after LangGraph removal — caused performance regression on challenging tasks
|
|
109
|
-
- Discovered that verbose descriptions with examples, Args/Returns sections are essential for model tool-calling quality
|
|
110
|
-
|
|
111
|
-
**Notes**: Tool descriptions are behavioral instructions for the model, not documentation for humans. This is a key insight for any framework migration.
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
## 2026-01-30
|
|
116
|
-
|
|
117
|
-
**Goal**: Verify test suite, create expertise entry for frameworkless agent pattern, housekeeping
|
|
118
|
-
|
|
119
|
-
**Done**:
|
|
120
|
-
- Ran all 70 pytest tests — all pass after v3.0.0 migration
|
|
121
|
-
- Confirmed examples/ has sample tasks but no automated e2e tests
|
|
122
|
-
- Created EXPERTISE/E001_frameworkless_react_agent.md documenting the frameworkless ReAct pattern
|
|
123
|
-
- Added EXPERTISE/ to .gitignore, committed and pushed to dev
|
|
124
|
-
- Removed dead links from Key Documents (LOCAL/ directory no longer exists)
|
|
125
|
-
|
|
126
|
-
**Tried**:
|
|
127
|
-
- Looked for e2e tests in examples/ — only sample task files and one manual test run (regex/sample_tasks/test_email/)
|
|
128
|
-
|
|
129
|
-
**Notes**: E2E tests remain the top priority open goal. They need mocked OpenAI API responses (mock client.chat.completions.create()).
|
|
130
|
-
|
|
131
|
-
---
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
keywords: [react, agent, openai, frameworkless, langgraph, langchain, migration, tool-calling]
|
|
3
|
-
context: Building LLM-powered agents without heavy frameworks (LangGraph, LangChain, CrewAI, etc.)
|
|
4
|
-
added: 2026-01-30
|
|
5
|
-
---
|
|
6
|
-
# Frameworkless ReAct Agent Pattern
|
|
7
|
-
|
|
8
|
-
## Insight
|
|
9
|
-
|
|
10
|
-
A fully functional ReAct agent requires only ~4 components using the `openai` Python client directly, with no framework overhead:
|
|
11
|
-
|
|
12
|
-
1. **LLM config** — A dataclass wrapping `openai.OpenAI` client, model path, and API params (temperature, max_tokens). Route through OpenRouter for multi-provider access.
|
|
13
|
-
|
|
14
|
-
2. **Tool registry** — A `Tool` dataclass (name, description, JSON Schema parameters, callable function) with a `ToolRegistry` class that converts tools to OpenAI format via `to_openai_tool()`. Each tool's `execute()` returns a JSON string.
|
|
15
|
-
|
|
16
|
-
3. **ReAct loop** — A simple `for step in range(limit)` loop that:
|
|
17
|
-
- Calls `client.chat.completions.create()` with messages + tools
|
|
18
|
-
- If response has `tool_calls`: execute each, append tool results to messages
|
|
19
|
-
- If no `tool_calls`: it's the final answer — break
|
|
20
|
-
- Messages list grows naturally (system → user → assistant+tool_calls → tool → assistant+tool_calls → ... → assistant)
|
|
21
|
-
|
|
22
|
-
4. **Agent dataclass** — Holds config, tools, system prompt, working directory, and persistent `messages` list (enables multi-turn/interactive mode).
|
|
23
|
-
|
|
24
|
-
### Key advantages over LangGraph/LangChain
|
|
25
|
-
|
|
26
|
-
- **Dependency reduction**: 112 → 69 installed packages (removed all LangChain/LangGraph deps)
|
|
27
|
-
- **Debuggability**: The entire agent loop is ~60 lines of straightforward Python. No graph compilation, no state machines, no hidden middleware.
|
|
28
|
-
- **Message format control**: Full control over the `messages` list. No framework-imposed message wrappers or serialization formats.
|
|
29
|
-
- **Token tracking**: Direct access to `response.usage.prompt_tokens` / `completion_tokens`.
|
|
30
|
-
- **Error handling**: Tool errors are just JSON strings fed back to the model — the model self-corrects. No need for framework error recovery machinery.
|
|
31
|
-
|
|
32
|
-
### Pitfalls learned during migration
|
|
33
|
-
|
|
34
|
-
- **`model or "default"` bug**: If `model=""` (empty string), `or` evaluates to `"default"` — use explicit `None` checks instead.
|
|
35
|
-
- **Environment variable leaks**: Global env vars (e.g., `CODER_WITH_PACKAGES`) persist across runs — always clear them with `os.environ.pop()` when not set.
|
|
36
|
-
- **Global state accumulation**: Module-level globals (todo lists, file basenames) accumulate across runs. Add a `reset_global_state()` function called at agent creation time.
|
|
37
|
-
- **Tool call message format**: OpenAI API requires tool_calls in assistant messages to be dicts with `id`, `type`, `function.name`, `function.arguments`. Missing any field causes cryptic errors.
|
|
38
|
-
- **UTF-8 encoding**: Always use `encoding="utf-8"` when opening files — platform default encoding can vary.
|
|
39
|
-
|
|
40
|
-
### When to use a framework instead
|
|
41
|
-
|
|
42
|
-
- If you need **graph-based workflows** with conditional branching between multiple agents
|
|
43
|
-
- If you need **built-in memory/persistence** across sessions (vector stores, checkpoints)
|
|
44
|
-
- If you need **streaming with backpressure** and complex output routing
|
|
45
|
-
- For simple single-agent ReAct loops, the framework adds complexity without benefit
|
|
46
|
-
|
|
47
|
-
## Example
|
|
48
|
-
|
|
49
|
-
```python
|
|
50
|
-
from dataclasses import dataclass, field
|
|
51
|
-
from openai import OpenAI
|
|
52
|
-
import json
|
|
53
|
-
|
|
54
|
-
@dataclass
|
|
55
|
-
class Tool:
|
|
56
|
-
name: str
|
|
57
|
-
description: str
|
|
58
|
-
parameters: dict
|
|
59
|
-
function: callable
|
|
60
|
-
|
|
61
|
-
def to_openai_tool(self):
|
|
62
|
-
return {
|
|
63
|
-
"type": "function",
|
|
64
|
-
"function": {
|
|
65
|
-
"name": self.name,
|
|
66
|
-
"description": self.description,
|
|
67
|
-
"parameters": self.parameters,
|
|
68
|
-
},
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
def execute(self, **kwargs):
|
|
72
|
-
return self.function(**kwargs)
|
|
73
|
-
|
|
74
|
-
# ReAct loop core (~30 lines)
|
|
75
|
-
def run(client, model, messages, tools, limit=200):
|
|
76
|
-
openai_tools = [t.to_openai_tool() for t in tools]
|
|
77
|
-
tool_map = {t.name: t for t in tools}
|
|
78
|
-
|
|
79
|
-
for _ in range(limit):
|
|
80
|
-
resp = client.chat.completions.create(
|
|
81
|
-
model=model, messages=messages, tools=openai_tools, tool_choice="auto"
|
|
82
|
-
)
|
|
83
|
-
msg = resp.choices[0].message
|
|
84
|
-
|
|
85
|
-
if msg.tool_calls:
|
|
86
|
-
messages.append({
|
|
87
|
-
"role": "assistant",
|
|
88
|
-
"content": msg.content or "",
|
|
89
|
-
"tool_calls": [
|
|
90
|
-
{"id": tc.id, "type": "function",
|
|
91
|
-
"function": {"name": tc.function.name,
|
|
92
|
-
"arguments": tc.function.arguments}}
|
|
93
|
-
for tc in msg.tool_calls
|
|
94
|
-
],
|
|
95
|
-
})
|
|
96
|
-
for tc in msg.tool_calls:
|
|
97
|
-
args = json.loads(tc.function.arguments)
|
|
98
|
-
result = tool_map[tc.function.name].execute(**args)
|
|
99
|
-
messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})
|
|
100
|
-
else:
|
|
101
|
-
messages.append({"role": "assistant", "content": msg.content or ""})
|
|
102
|
-
break
|
|
103
|
-
return messages
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
## Reference
|
|
107
|
-
|
|
108
|
-
- Blueprint implementation: `/Users/szeider/work/myreact` (the original pattern)
|
|
109
|
-
- Production implementation: `coder/src/agentic_python_coder/agent.py` (v3.0.0)
|
|
110
|
-
- Migration context: LangGraph v2.x → frameworkless in one session, all 70 tests passing
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
keywords: [tool-descriptions, openai, tool-calling, performance, langgraph, schema, regression]
|
|
3
|
-
context: When writing or modifying OpenAI tool definitions for agents that use tool calling
|
|
4
|
-
added: 2026-01-31
|
|
5
|
-
---
|
|
6
|
-
# Tool Description Quality Impacts Agent Performance
|
|
7
|
-
|
|
8
|
-
## Insight
|
|
9
|
-
|
|
10
|
-
Verbose, LangGraph-style tool descriptions significantly outperform minimal descriptions on challenging tasks. When migrating from LangGraph to frameworkless tool definitions, preserving the full docstring content is critical.
|
|
11
|
-
|
|
12
|
-
### What works (LangGraph-style verbose descriptions)
|
|
13
|
-
|
|
14
|
-
1. **Multiple examples** showing multi-step usage patterns — not just what the tool does, but how to chain calls (e.g., define a function in one call, use it in the next)
|
|
15
|
-
2. **Explicit Args section** describing each parameter in natural language
|
|
16
|
-
3. **Explicit Returns section** listing every possible field in the response JSON (`success`, `stdout`, `result`, `stderr`, `error`)
|
|
17
|
-
4. **Behavioral hints** embedded in the description (e.g., "The kernel maintains state between executions!", "use print() to see output")
|
|
18
|
-
|
|
19
|
-
### What fails (minimal descriptions)
|
|
20
|
-
|
|
21
|
-
Stripping descriptions to just the core purpose (e.g., "Execute Python code in a persistent IPython kernel.") removes behavioral guidance the model relies on for:
|
|
22
|
-
- Understanding that state persists across calls
|
|
23
|
-
- Knowing what output format to expect
|
|
24
|
-
- Planning multi-step tool use sequences
|
|
25
|
-
|
|
26
|
-
### Parameter schema style also matters
|
|
27
|
-
|
|
28
|
-
The LangGraph auto-generated schemas use `"title"` fields on properties and top-level schema, plus `"additionalProperties": True` for flexible object items. Switching to `"description"` fields and strict schemas (with explicit properties and enums) may change how models interpret and use the tools. When in doubt, match the schema style that was tested and proven to work.
|
|
29
|
-
|
|
30
|
-
### Verification gates in tool descriptions
|
|
31
|
-
|
|
32
|
-
Adding verification requirements to `save_code` tool description ("Only call this AFTER you have executed the code and confirmed it produces correct output") measurably improved benchmark scores. Opus 4.5 went from 4/5→5/5 on hard CPMpy and GPT-5.2 from 0/5→5/5 on hard Clingo after adding these gates. However, GPT-5.2 still sometimes ignores verification (only 2 tool calls before saving on 016_sports). The verification prompt works better on some models than others.
|
|
33
|
-
|
|
34
|
-
### Circular verification pitfall
|
|
35
|
-
|
|
36
|
-
Models that do write verify() functions sometimes verify against their own wrong model rather than the problem statement. The verify() re-implements the same bugs as the solver constraints. Prompt language should explicitly require deriving verification checks from the problem text, not from the model code.
|
|
37
|
-
|
|
38
|
-
### Key takeaway
|
|
39
|
-
|
|
40
|
-
Tool descriptions are not documentation for humans — they are **behavioral instructions for the model**. Treat them as part of the prompt engineering, not as code comments to be minimized.
|
|
41
|
-
|
|
42
|
-
**Updated**: 2026-01-31
|
|
43
|
-
|
|
44
|
-
## Example
|
|
45
|
-
|
|
46
|
-
```python
|
|
47
|
-
# BAD: Minimal description (causes performance regression)
|
|
48
|
-
PYTHON_EXEC_TOOL = Tool(
|
|
49
|
-
name="python_exec",
|
|
50
|
-
description="Execute Python code in a persistent IPython kernel.",
|
|
51
|
-
parameters={
|
|
52
|
-
"type": "object",
|
|
53
|
-
"properties": {
|
|
54
|
-
"code": {"type": "string", "description": "Python code to execute."},
|
|
55
|
-
},
|
|
56
|
-
"required": ["code"],
|
|
57
|
-
},
|
|
58
|
-
function=python_exec,
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
# GOOD: Verbose LangGraph-style description (proven performance)
|
|
62
|
-
PYTHON_EXEC_TOOL = Tool(
|
|
63
|
-
name="python_exec",
|
|
64
|
-
description=(
|
|
65
|
-
"Execute Python code in a persistent IPython kernel.\n\n"
|
|
66
|
-
"IMPORTANT: The kernel maintains state between executions!\n"
|
|
67
|
-
"- Variables, functions, and imports persist across calls\n"
|
|
68
|
-
"- Use print() to see output, or the last expression will be returned\n"
|
|
69
|
-
"- The kernel runs in the working directory context\n\n"
|
|
70
|
-
"Example:\n"
|
|
71
|
-
" First call: x = 5\n"
|
|
72
|
-
' Second call: print(x) # Returns: {"success": true, "stdout": "5"}\n\n'
|
|
73
|
-
" First call: def add(a, b): return a + b\n"
|
|
74
|
-
' Second call: add(3, 4) # Returns: {"success": true, "result": "7"}\n\n'
|
|
75
|
-
"The code executes in the working directory context, so you can read/write files\n"
|
|
76
|
-
"using relative paths.\n\n"
|
|
77
|
-
"Args:\n"
|
|
78
|
-
" code: Python code to execute. Multi-line code is supported.\n\n"
|
|
79
|
-
"Returns:\n"
|
|
80
|
-
" JSON string with execution results:\n"
|
|
81
|
-
" - success: boolean indicating if execution succeeded\n"
|
|
82
|
-
" - stdout: captured print output (if any)\n"
|
|
83
|
-
" - result: the last expression's value (if any)\n"
|
|
84
|
-
" - stderr: warnings (if any)\n"
|
|
85
|
-
" - error: error message (if execution failed)"
|
|
86
|
-
),
|
|
87
|
-
parameters={
|
|
88
|
-
"type": "object",
|
|
89
|
-
"properties": {
|
|
90
|
-
"code": {
|
|
91
|
-
"type": "string",
|
|
92
|
-
"title": "Code",
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
"required": ["code"],
|
|
96
|
-
"title": "python_exec",
|
|
97
|
-
},
|
|
98
|
-
function=python_exec,
|
|
99
|
-
)
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Reference
|
|
103
|
-
|
|
104
|
-
- Regression discovered: 2026-01-31 during benchmark testing of dev branch
|
|
105
|
-
- Fix verified in: `/Users/szeider/temp/codertest/agentic-python-coder-dev/`
|
|
106
|
-
- Production file: `coder/src/agentic_python_coder/tools.py`
|
|
107
|
-
- Related: E001_frameworkless_react_agent.md (migration context)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/__init__.py
RENAMED
|
File without changes
|
{agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/agent.py
RENAMED
|
File without changes
|
{agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/cli.py
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/llm.py
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/runner.py
RENAMED
|
File without changes
|
{agentic_python_coder-3.3.0 → agentic_python_coder-3.4.1}/coder/src/agentic_python_coder/tools.py
RENAMED
|
File without changes
|
|
File without changes
|