Commit Graph

1 Commits

Author SHA1 Message Date
drew bb8d872ba7 feat(controller): Phase 1d-4 — OpenCode session adapter
The production wrapper that wires the existing
_opencode_worker.run_session_blocking into the controller's
run_opencode_session protocol that production_agent_runner expects.

tools/controller/worker/opencode_session.py:

- agent_name_for(role, tier): role+tier → OpenCode agent name.
  - implementer + tier {0,1,2} → task-implementor-tier-{0,1,2}
  - reviewer → pr-review-worker
  - estimator → estimator-implementation
  - conflict_resolver → conflict-resolver-worker
  - summarizer → controller-summarizer (new agent name)

- DEFAULT_TIER_TIMEOUT_S: per-tier wallclock budgets via env vars.
  Defaults match plan v9 (tier 0: 600s, tier 1: 1200s, tier 2: 1800s).
  Reviewer/estimator/conflict use the default-agent timeout (600s).

- wire_opencode_session(opencode_server_url, ...) → callable matching
  the production_agent_runner's run_opencode_session contract.
  - Resolves role+tier to agent name + per-tier timeout
  - Builds the prompt (default stub or custom builder; per-role prompt
    templates are a follow-up)
  - Calls run_session_blocking with an on_poll callback that raises
    WorkerLostLock if the controller's lost_lock_check returns True
    mid-session (heartbeat thread reaper detected stolen lock)
  - Routes SessionResult.status:
    - 'completed' → return None (MCP's canonical output is in the
      tempfile; production_agent_runner reads it after we return)
    - 'timeout' → raise WorkerError(worker-internal-error)
    - 'transport-error' → raise WorkerError(worker-internal-error,
      including error_kind for forensics)
    - unknown → raise WorkerError defensively
  - Any unexpected exception from run_session_blocking wrapped as
    WorkerError(worker-internal-error).

- Production wiring: dependency injection. wire_opencode_session()
  lazy-imports the real run_session_blocking when not overridden.
  Tests inject a stub.

22 new tests in test_worker_opencode_session.py:
- agent_name_for: parametrized per role (4 implementer-tier rows +
  4 flat-role rows) + invalid tier + unknown role
- DEFAULT_TIER_TIMEOUT_S: each tier has a timeout + monotonic
- wire_opencode_session: completed/timeout/transport-error/unknown-
  status routing; run_session_blocking raises wrapped as WorkerError;
  on_poll propagates lost_lock; on_poll no-op when lock held;
  custom prompt_builder used; default prompt includes role + tier
  + finalize() instruction + rendered input_payload; tag prefix
  customizable.

Total: 398 controller tests; full auto_agents suite 2760 pass.
2026-05-18 14:09:34 -04:00