open-coding-env / utils.py
shobhitagnihotri's picture
Upload utils.py with huggingface_hub
bb7723e verified
Raw History Blame Contribute Delete
8.12 kB
"""Plumbing for the one-GRPO-step walkthrough.
Nothing in this file is a concept the notebook teaches -- it is the prompt
text, the sampling boilerplate and the fake environment, kept here so the
notebook itself can stay about the harness, the reward and the update.
Every method of MockEnv is a lie. The comments say which kind.
"""
import difflib
import re
import pandas as pd
import torch
from IPython.display import display
TARGET = "astropy/modeling/separable.py"
# Verbatim source at astropy@d16bfe05, trimmed to the one function the issue is
# about. The bug is the asymmetry: the cleft branch assigns `left`, the cright
MOCK_FILE = '''import numpy as np
class Model:
"""Mock model class."""
pass
def _compute_n_outputs(left, right):
return left.shape[0] if hasattr(left, "shape") else 1
def _coord_matrix(model, side, noutp):
return np.zeros((noutp, 1))
def _cstack(left, right):
"""
Function corresponding to '&' operation.
Parameters
----------
left, right : `astropy.modeling.Model` or ndarray
If input is of an array, it is the output of `coord_matrix`.
Returns
-------
result : ndarray
Result from this operation.
"""
noutp = _compute_n_outputs(left, right)
if isinstance(left, Model):
cleft = _coord_matrix(left, 'left', noutp)
else:
cleft = np.zeros((noutp, left.shape[1]))
cleft[: left.shape[0], : left.shape[1]] = left
if isinstance(right, Model):
cright = _coord_matrix(right, 'right', noutp)
else:
cright = np.zeros((noutp, right.shape[1]))
cright[-right.shape[0]:, -right.shape[1]:] = 1
return np.hstack([cleft, cright])'''
RE_BASH = re.compile(r"```(?:bash|sh)?\s*\n(.*?)```", re.S)
RE_HEREDOC = re.compile(r"cat\s*>\s*(\S+)\s*<<\s*'?EOF'?\n(.*?)\nEOF", re.S)
SYSTEM = f"""You are a software engineering agent. You are in a Python repository.
Fix the bug described in the issue.
Respond with exactly ONE bash command per message, in a fenced block:
```bash
your command here
```
Useful commands:
ls
cat {TARGET}
grep -n "pattern" {TARGET}
python -m pytest
To rewrite a file:
```bash
cat > {TARGET} <<'EOF'
...full new contents...
EOF
```
One short sentence of reasoning, then exactly one command block."""
NO_COMMAND = "No command found. Reply with exactly one ```bash block."
def first_bash_block(reply):
"""The parse step: pull one action out of free text, or None."""
m = RE_BASH.search(reply)
return m.group(1).strip() if m else None
def show_rollout(rollout, preview=160):
"""Trajectory table, commands issued, and the candidate patch.
`preview` caps the preview column; pass None to show messages in full.
"""
def author(i, m):
if m["role"] == "assistant":
return "model"
return "harness" if i < 2 else "environment"
def shorten(text):
one_line = text.replace("\n", " | ")
if preview is None or len(one_line) <= preview:
return one_line
return one_line[:preview] + " […]"
msgs = rollout["messages"]
n_turns = (len(msgs) - 2) // 2
print(f"{len(msgs)} messages = 2 setup + 2 per turn x {n_turns} turns\n")
display(pd.DataFrame([
{"i": i, "turn": "setup" if i < 2 else (i - 2) // 2,
"role": m["role"], "written by": author(i, m),
"chars": len(m["content"]),
"preview": shorten(m["content"])}
for i, m in enumerate(msgs)
]))
print("\ncommands:")
for c in rollout["calls"]:
print(" $", c.splitlines()[0] + (" ..." if "\n" in c else ""))
print("\ncandidate patch:")
print(rollout["patch"] or "(no file changed)")
def show_group(group, reward):
"""Summary table for a group of rollouts, then every trace verbatim."""
display(pd.DataFrame([
{"rollout": i,
"reward": reward[i],
"patch_lines": len(r["patch"].split("\n")) if r["patch"] else 0,
"n_commands": len(r["calls"])}
for i, r in enumerate(group)
]))
for i, r in enumerate(group):
print(f"\n================ rollout {i} ================")
for cmd in r["calls"]:
print(" $", cmd)
print("\ncandidate patch:")
print(r["patch"] or "(no file changed)")
def scripted_sampler(replies):
"""A stand-in for `generate`: replays canned replies, ignoring the prompt.
Lets the same harness be driven by a competent 'model' so a demo can show
what a successful rollout looks like.
"""
it = iter(replies)
def sample(model, tok, prompt, **kwargs):
return next(it, "```bash\nls\n```")
return sample
def generate(model, tok, prompt, max_new_tokens=200, temperature=1.0, max_length=3072):
"""The call step: sample a continuation, return only the new text."""
device = next(model.parameters()).device
ip = tok(prompt, return_tensors="pt", truncation=True, max_length=max_length).to(device)
with torch.no_grad():
out = model.generate(**ip, max_new_tokens=max_new_tokens,
do_sample=temperature > 0,
temperature=max(temperature, 1e-5), top_p=0.95,
pad_token_id=tok.pad_token_id or tok.eos_token_id)
return tok.decode(out[0][ip["input_ids"].shape[1]:], skip_special_tokens=True).strip()
class MockEnv:
"""A shell that never runs a shell.
Stands in for the container a real harness would exec into. Handles ls,
cat, grep, pytest and a heredoc write; anything else returns a stub.
"""
def __init__(self, failing_tests=()):
self.fs = {TARGET: MOCK_FILE}
self.orig = dict(self.fs)
self.failing_tests = list(failing_tests)
self.calls = []
def run(self, cmd):
self.calls.append(cmd)
m = RE_HEREDOC.search(cmd)
if m: # real effect on the virtual FS
path, body = m.group(1), m.group(2)
self.fs[path] = body
return f"[mock env] wrote {len(body.splitlines())} lines to {path}"
if cmd.strip().startswith("ls"): # canned
return "\n".join(sorted(self.fs)) + "\nsetup.py\nREADME.rst\ntests/"
if cmd.strip().startswith("cat "): # real source, one function of it
path = cmd.split()[-1]
if path in self.fs:
return ("[mock env] only the region near the bug is available\n"
+ self.fs[path])
return f"cat: {path}: No such file or directory"
if cmd.strip().startswith("grep"): # real search over the fragment
pat = re.findall(r'"([^"]*)"|\'([^\']*)\'', cmd)
pat = next((a or b for a, b in pat), "")
src = self.fs.get(cmd.split()[-1], "")
hits = [f"{i + 1}:{line}" for i, line in enumerate(src.split("\n"))
if pat and pat in line]
return "\n".join(hits) if hits else "(no matches)"
if "pytest" in cmd: # canned failure, real test names
body = "\n".join(f"FAILED {n}" for n in self.failing_tests)
return (f"{body}\n=== {len(self.failing_tests)} failed ===\n"
"[mock env] test names are real, but nothing was executed")
name = cmd.split()[0] if cmd.split() else cmd
return (f"bash: {name}: command not found\n"
"[mock env] implements only: ls, cat, grep, pytest, cat > FILE <<'EOF'")
def patch(self):
"""The candidate patch: a real unified diff of the virtual FS.
A file the agent created did not exist at the start, so it diffs
against empty -- the same as `git diff` for a new file.
"""
out = []
for path, body in self.fs.items():
before = self.orig.get(path, "")
if body != before:
out += list(difflib.unified_diff(
before.split("\n"), body.split("\n"),
fromfile=f"a/{path}", tofile=f"b/{path}", lineterm=""))
return "\n".join(out)