v0.2.0
Breaking changes
execute() now raises AgentExecutionError instead of returning on failure.
Previously a crashed, truncated or agent-level-failed run was indistinguishable from an
empty answer. Callers that relied on inspecting an empty response must now catch:
from agent_shell.models.agent import AgentExecutionError
try:
result = await shell.execute(cwd=..., prompt=...)
except AgentExecutionError as e:
print(f"failed: {e}") # str(e) is the bare reasonAgentExecutionError carries whatever partial data the run produced (response, cost,
session_id, duration, output_tokens).
AgentType.GEMINI_CLI removed. Gemini is deprecated and never had an adapter, so
constructing it always raised ValueError. shell.py now has a module-level _ADAPTERS
registry, pinned to the enum by a test so a future AgentType cannot ship without one.
Fixes
- #7 Process and stderr teardown was duplicated and subtly wrong across all six adapters.
Now a sharedrelease_process()called from afinallyin everystream().
kill_process_group()signals only while the pid still leads its own group — asyncio's
ThreadedChildWatcherreaps the child and frees its pid before settingreturncode, so
returncodeis not a sound liveness test and a recycled pid could be signalled. - #10 The Pi adapter reported success for failed runs. It now recognises failing stop
reasons, prefers Pi's structurederrorMessage, and judges only the last assistant message,
since Pi emits multipleagent_endevents when it auto-retries. - #11 A shared
outcome.pyholds one success predicate and reason precedence used by both
execute()andhealth_check(), so the two cannot drift;response.pyholds the shared
aggregation. cleanup_process_groups()bypassed the new pid-leader guard and calledos.killpgdirectly.- Orphaned grandchildren leaked when the child was reaped while its process group still had
live members. Reclaimed on the abandoned path. - A failing unit test could leave an invented pid in the module-global registry, and
atexit
would then SIGKILL whatever real process group held that number.
Documentation
- Codex and Cursor cannot enforce
disallowed_tools; the skill docs told readers to rely on it
for read-only reviewers. - Stderr in
errorevents is head+tail (500 characters each side), not the documented last 500. - Added a Pi section and documented Cursor as a supported agent.
- Corrected process-cleanup docstrings that asserted measurably false claims.
Tests
Session-resumption e2e tests asserted that a model would recall a planted word, measuring model
compliance rather than library behaviour — one failed because the model declined to repeat the
token. All six adapters now assert session-id identity across a resume plus a distinct id for a
fresh session. Copilot e2e is pinned to the free auto model, with the two reasoning-effort
tests gated behind COPILOT_PAID_TIER.
682 unit and integration tests passing; 57 e2e passing, 2 skipped.