Try this first
Ask Rover to run a command that fails:
“Run
python3 -c 'import nosuchmodule'and tell me what happens.”
If your bash tool from Lesson 3.3 returns stdout, stderr, and the exit code, Rover reads
the ModuleNotFoundError and explains it. If it returns only stdout, Rover gets an empty
string and tells you the command worked.
Same command. Same failure. The difference is entirely in what you chose to send back.
The principle
An agent’s ability to recover is bounded by the quality of the failure information you give
it. Not by the model. By your tool result.
That is worth stating as a design rule:
Everything that would help a person debug this should go in the tool result.
For a shell command, that means exit code, stdout, and stderr. For an HTTP call, the status
code and the response body. For a file operation, what was attempted and what exists instead.
The recovery loop
Here is the pattern that makes agents feel capable:
model proposes → your code runs it → it fails
→ you send back the error
→ model reads the error and adjusts
→ your code runs the new version → it works
Nothing in that loop is new. It is Module 1’s loop, with useful failure text in the tool
result. That is all “self-healing agent” means.
You can watch it work:
[bash] python3 -c "import nosuchmodule"
exit code 1
ModuleNotFoundError: No module named 'nosuchmodule'
[bash] pip install nosuchmodule
exit code 1
ERROR: Could not find a version that satisfies the requirement nosuchmodule
Rover: That module does not exist on PyPI. Did you mean a different name?
Two failures, and the second one produced the correct conclusion. Neither turn needed you.
Where to trim
Errors can be enormous. A failing test suite produces thousands of lines, and all of it lands
in your transcript and gets resent every turn afterwards.
Trim with intent:
def trim(text, limit=4000):
if len(text) <= limit:
return text
head, tail = text[:1000], text[-3000:]
return f"{head}\n\n[... {len(text) - 4000} characters trimmed ...]\n\n{tail}"
Keep the head and the tail. The head has the command and the first failure; the tail has the
summary line and the last error, which is usually the one that matters. The middle is
repetition.
And say that you trimmed. A silent truncation makes the model reason about a test suite it
thinks had four failures when it had four hundred.
What not to send back
Raw Python tracebacks from your own agent code. If run_tool throws because of a bug in
your code, that is your problem, not the model’s. Send a short message; keep the traceback
in your log.
Secrets. Error messages leak connection strings, tokens, and paths. Once one is in the
transcript it is resent on every turn for the rest of the session, and there is no way to take
it back.
Try this before the next lesson
Break something on purpose. Introduce a syntax error into a file Rover is working on, then ask
it to run the tests.
Watch the loop: run, fail, read, fix, run. Then take the exit code out of your bash result and
run it again. Watch the recovery stop working. That contrast is the lesson.