Repository navigation
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Existing persistence tests in the repo still assert context aliases context_0, and the scaffold-restore logic should not depend on context_0 existing when explicit non-zero context indices are supported.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR updates persistence semantics for RLM REPL environments so the unversioned context name always refers to the most recently added context_N, preventing models in persistent sessions from accidentally using the first-turn context after later completion() calls.
Changes:
- Update
add_context()in LocalREPL, DockerREPL, and IPythonREPL to always setcontext = context_Nfor the latest index. - Update scaffold restoration logic so
contextis restored to the latestcontext_Nif overwritten by executed code. - Update the persistence protocol documentation to describe the new aliasing behavior.
File summaries
| File | Description |
|---|---|
rlm/environments/local_repl.py |
Always aliases context to the latest added context and restores that alias after overwrites. |
rlm/environments/ipython_repl.py |
Updates both subprocess-mode context injection and in-process scaffold restoration to use the latest context. |
rlm/environments/docker_repl.py |
Updates container-side scaffold restoration and add_context() to alias context to the latest context. |
rlm/environments/base_env.py |
Updates SupportsPersistence documentation to reflect new context aliasing semantics. |
Review details
Suppressed comments (3)
rlm/environments/base_env.py:302
- The docstring contradicts itself: it says unversioned names always point to index 0, but then states
contextpoints to the latest numbered context. Update the lead-in line so it matches the new aliasing behavior.
Use isinstance(env, SupportsPersistence) to check if an environment
supports persistence capabilities.
IMPLEMENTING THIS PROTOCOL:
rlm/environments/local_repl.py:549
- Scaffold restoration only resets
contextwhencontext_0exists. Sinceadd_context(..., context_index=N)supports explicit non-zero indices,contextmay exist withoutcontext_0; in that case an overwrite would not be restored. Consider restoring whenever anycontext_\d+key exists.
self.locals["answer"] = replacement
elif name == "context" and "context_0" in self.locals:
self.locals["context"] = get_latest_context(self.locals)
elif name == "history" and "history_0" in self.locals and not self.compaction:
self.locals["history"] = self.locals["history_0"]
elif name == "history" and self.compaction:
self.locals["history"] = self._compaction_history
def execute_code(self, code: str) -> REPLResult:
"""Execute code in the persistent namespace and return result."""
start_time = time.perf_counter()
rlm/environments/ipython_repl.py:1406
- In-process scaffold restoration only resets
contextwhencontext_0exists. If contexts are loaded with an explicit non-zero index (supported by the persistence protocol),contextcould exist withoutcontext_0and would not be restored after an overwrite.
self._last_final_answer = str(current.get("content", ""))
ns["answer"] = replacement
if "context_0" in ns:
ns["context"] = get_latest_context(ns)
if "history_0" in ns:
ns["history"] = ns["history_0"]
# Re-inject custom tools if overwritten
for name, entry in self.custom_tools.items():
- Files reviewed: 4/4 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| # Restore scaffold aliases if overwritten by executed code | ||
| if "context_0" in _locals: | ||
| _locals["context"] = _locals["context_0"] | ||
| _locals["context"] = _locals[max( | ||
| (key for key in _locals if key.startswith("context_") and key[8:].isdigit()), | ||
| key=lambda key: int(key[8:]), | ||
| )] |
| # Alias the latest context as 'context'. | ||
| self.execute_code(f"context = {var_name}") | ||
|
|
||
| self._context_count = max(self._context_count, context_index + 1) | ||
| return context_index |
There was a problem hiding this comment.
🟡 Changes recommended
The Docker exec-script injection via inspect.getsource() currently risks generating an indented top-level script (IndentationError), and existing tests asserting context == context_0 must be updated to match the new contract.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
rlm/environments/base_env.py:315
- This change updates the persistence contract for the
contextalias, but existing tests still assert the old behavior (e.g., tests/test_local_repl_persistent.py::test_context_alias_points_to_first and tests/test_docker_repl_persistent.py::test_context_alias_points_to_first). The PR should update those tests (and any other callers) to checkcontext == context_{latest}and/or usecontext_0explicitly when they want the first payload.
- context -> latest numbered context
- history -> history_0 (first history)
- Files reviewed: 4/4 changed files
- Comments generated: 2
- Review effort level: Lite
| except ImportError: | ||
| import pickle as dill | ||
|
|
||
| {inspect.getsource(get_latest_context)} |
| @@ -298,7 +310,7 @@ class SupportsPersistence(Protocol): | |||
|
|
|||
| ALIASING BEHAVIOR: | |||
| The unversioned names always point to index 0: | |||
In persistent sessions, the system prompt directs the model to
context, but that alias continues to refer to the first input after subsequentcompletion()calls. This can lead weaker models to process an earlier batch instead of the current one.Point
contextto the latest numbered input in Local, Docker, and IPython REPLs, including scaffold restoration. Historical inputs remain available throughcontext_0,context_1, etc. Update the persistence protocol documentation accordingly.Compatibility: callers relying on
contextremaining the first input should usecontext_0explicitly.Validation: local smoke check covered two inputs, retained numbered contexts, and alias restoration after overwrite; formatting and
git diff --checkpassed. No regression tests added; existing tests asserting the first-input alias have not been updated, and Docker/IPython behavior has not been runtime-tested. Draft for review.