Skip to content

v0.2.0

Choose a tag to compare

@ScottRBK ScottRBK released this 26 Jul 10:04
· 37 commits to main since this release

Closes #7, #10, #11.

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 reason

AgentExecutionError 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 shared release_process() called from a finally in every stream().
    kill_process_group() signals only while the pid still leads its own group — asyncio's
    ThreadedChildWatcher reaps the child and frees its pid before setting returncode, so
    returncode is 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 structured errorMessage, and judges only the last assistant message,
    since Pi emits multiple agent_end events when it auto-retries.
  • #11 A shared outcome.py holds one success predicate and reason precedence used by both
    execute() and health_check(), so the two cannot drift; response.py holds the shared
    aggregation.
  • cleanup_process_groups() bypassed the new pid-leader guard and called os.killpg directly.
  • 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 error events 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.