Repository navigation
[OpenCode V2][2/5] Add opt-in V2 transport, session lifecycle and location mapping #3
Description
Parent epic: #1 · Planned contribution: upstream PR 2/5 · Depends on #2 · Upstream discussion: Intelligent-Internet#550
Goal
Implement a working, explicitly selected OpenCode V2 HTTP/backend connection and session slice, while leaving V1 as the default and refusing all unfinished V2 A2A execution/extension behavior. Deliver a small upstream PR reviewers can test independently, without pretending that chat is implemented yet.
Background
The current src/opencode_a2a/opencode_upstream_client.py uses V1 paths (/session, /event, /session/{id}/message), V1 directory/workspace query semantics, and expects JSON payloads for many operations. V2 routes are under /api/* and often wrap success results in { "data": ... }, while some mutations return HTTP 204. V2 location references are not a simple rename of every V1 query parameter.
Sources:
- V2 API https://opencode.ai/v2/docs/api (especially
/api/info,/api/location,/api/session) - Migration guide https://opencode.ai/v2/docs/migrate-v1#server-api-and-clients
- Existing config
src/opencode_a2a/config.py:OPENCODE_BASE_URL,OPENCODE_AUTH_USERNAME,OPENCODE_AUTH_PASSWORD,OPENCODE_WORKSPACE_ROOT.
KISS
- Add one V2 adapter implementing only server identity, create/get/list/continue-session primitives needed by next PR; keep common HTTP/auth/concurrency handling in existing code.
- Add
OPENCODE_API_VERSION=v1|v2withv1default; explicit version selection, no auto-detection or fallback. - Do not implement V2 A2A prompting, streaming, forms, command/shell, workspace/worktree extras or broad session extension parity in this PR.
- Do not change A2A 1.0 protocol version, application ports, or inbound auth configuration.
- Until PR 3, selecting V2 for A2A prompt execution must fail fast with a clear unsupported/incomplete-backend error, not accept and hang or return a fake completed task.
- Advertise only the V2 capabilities actually usable; hide/reject all unimplemented OpenCode-specific methods now, not only in PR 5.
Detailed implementation plan (junior-friendly)
- Read [OpenCode V2][1/5] Extract typed upstream adapter boundary without changing V1 behavior #2's resulting contract and current source:
src/opencode_a2a/config.py,opencode_upstream_client.py,execution/session_manager.py,server/application.py,server/agent_card.py,contracts/extensions/capabilities.py. Check current upstream OpenCode API reference for the exact pinned V2 binary; save representative/api/info,/api/sessionrequest/response fixtures. - Add a validated enum/literal setting
OPENCODE_API_VERSIONdefaulting tov1. Update config tests to cover omitted setting, explicitv1, explicitv2and invalid values. Avoid "auto" as an accepted value for now. - Add a small factory or selector that injects
V1UpstreamAdapterorV2UpstreamAdapterinto the existing executor/session manager. Preserve old constructor compatibility where feasible, and preserve startup/shutdownclose()ownership. - Implement
V2requests forGET /api/info,GET /api/location,POST /api/session,GET /api/session/{sessionID}, and the minimum list/lookup needed for continuity. Distinguish optional location query objects, JSON body and absolute directory paths using the published schema, not V1's?directory=approach. Resolve workspace root paths server-side only; reject unauthorized or outside-root directory references before sending. - Reuse
httpxconnection pool, Basic auth, trace headers, request/stream budgets, timeout and redaction. Accept both non-default upstream port and externally suppliedOPENCODE_BASE_URL. Do not implement process management or dynamic port discovery. - Make response decoding protocol-aware: check status/media type, parse documented V2
dataenvelopes, accept exact204success for no-body actions, reject HTML SPA fallback or mismatched V1/V2 server versions with actionable diagnostics. Preserve typed errors without logging tokens or request bodies. - Add strict initial capability gates: V2 A2A execution and unmapped
opencode.*controls are unavailable. Ensure Agent Card/extension discovery does not suggest they work; direct calls must receive a stable unsupported-operation error rather than hitting a V1 route. Avoid disabling standard A2A discovery entirely if a truthful limited card can be served; document readiness/limitations clearly. - Add V2 unit fixture tests and real HTTP-boundary tests for status codes, query/body construction, response envelope shape, auth, 401/404/409, protocol mismatch, bad location, non-JSON responses and partial-state handling. Re-run V1 tests unmodified.
- Record implemented routes, explicitly disabled features and PR 3 dependencies in
docs/compatibility.md, labelled experimental V2 session transport only, not "OpenCode V2 supported".
Pitfalls to avoid
- Prefixing every V1 endpoint with
/apiwithout checking its V2 contract. - Assuming every successful V2 route returns JSON (some return
204). - Reusing V1
directoryparams for V2 location. - Assuming V2 default external-directory permissions sandbox work; V2 permits external directories by default, so retain/enforce gateway workspace policy and specify safe upstream permission policy.
- Starting
/api/eventonly after a prompt is already sent and assuming no events can be lost. - Returning an "accepted" task as "completed" when prompt execution remains unimplemented.
- Bypassing A2A session ownership in direct session continuation; V2 IDs remain untrusted input.
Final manual E2E acceptance test (PR 2's transport/session vertical slice)
Prerequisites: pinned real OpenCode V1 and V2 binaries, isolated temp HOME/XDG/workspace per version, valid upstream Basic auth, and throwaway ports. This PR is not expected to pass a V2 prompt E2E until PR 3.
- With
OPENCODE_API_VERSION=v1(and separately with env var omitted), start the existing A2A service and run the existing real V1bash ./scripts/live_opencode_smoke.shwithout skipping prompt. Confirm unchanged behavior. - Start the pinned V2
opencode serveon a local non-default port with Basic authentication. VerifyGET /api/inforeturns V2 identity. Instantiate the new V2 adapter via the same application selection/factory and create, fetch and list a session within the configured workspace. Assert stable session ID and correct location. - Try an invalid upstream password, unavailable server, and a deliberate
v1/v2config mismatch; verify early, understandable failure, not an HTML parse traceback. - Try a path outside
OPENCODE_WORKSPACE_ROOT(including normalized traversal or symlink escape) and, where relevant, an unowned existing session; verify rejection before an unauthorized operation. - Send an A2A prompt to V2 mode; verify the clear not-yet-supported response and no false
TASK_STATE_COMPLETEDstatus. Inspect discovery and confirm no unfinished V2 extensions are advertised. - Capture sanitized HTTP status/route evidence, session ID, exact V2 release, and pass/fail output in the PR. Do not call this full V2 chat E2E.
Acceptance criteria
- Explicit, validated API selector; unchanged V1 default.
- V2 authenticated
/api/info, location and session create/get/list work against a pinned real V2 service. - Shared HTTP auth, timeouts, error handling, redaction and concurrency guards are reused.
- Location/workspace restrictions and session ownership are not weakened.
- Non-JSON/mismatch failures and
204handling are correct. - Unsupported V2 execution/extensions are gated in dispatch and capability discovery, with informative errors.
- V1 unit, HTTP-boundary and real smoke tests still pass.
- PR 2 live V2 session vertical slice passes; limitations clearly documented.
Definition of Done
- Config, routing and response unit/HTTP tests green;
bash ./scripts/doctor.shgreen. - Manual V1 and V2 transport/session acceptance run with version + command evidence.
- No dead, misleading V2 "full support" feature flag; no silent fallback and no change to V1 defaults.
- Upstream PR small and reviewable, linked to [OpenCode V2][Epic] Deliver opt-in server API V2 support in five reviewable upstream PRs #1/[OpenCode V2][1/5] Extract typed upstream adapter boundary without changing V1 behavior #2 and upstream [Question] OpenCode V2 server API 兼容性与支持计划 Intelligent-Internet/opencode-a2a#550, with scope exclusions and security implications explained.
- Close this issue after upstream PR merge or explicitly documented reconciliation.
Next: #4 (V2 execution), which must consume the admitted prompt and correlate it to a true terminal result.
Activity
tbrandenburg commentedon Oct 25, 2026
Session slice 更新
上游 session PR 仍是明确 stacked Draft,依赖 typed boundary:Intelligent-Internet#552 。Exact head
cc8470ddoctor:890 passed,92.88% coverage;默认 V2 discovery/dispatch gating 修复已追加,未重写历史。单独
OPENCODE_API_VERSION=v2仍不启用 A2A execution。额外的 exclusive profile 使用固定 workspace;默认 session-only location mapping 保持不变。最终 acceptance stack 另提供 hardened、isolated 2.0.28 session smoke。未关闭本 issue;完整范围和上游顺序见 #1 / #7。tbrandenburg commentedon Oct 25, 2026
Fork session-transport scope 完成:明确 reconciliation
#7 已 normal merge 到 fork
main19943955704bf05347619ca5b98addb94a683c97;GitHub-only experimental fork prerelease 已发布。本 session slice 的显式 selector、V2 info/location/session create/get/list、Basic auth 与默认 fail-closed gates 已交付。Main 重新执行真实 OpenCode 2.0.28
bash ./scripts/live_opencode_v2_session_smoke.sh:Basic-auth rejection 和 routes 通过,未提交 model prompt。V1 默认不变;只选OPENCODE_API_VERSION=v2不启用 execution;还需OPENCODE_V2_EXECUTION=exclusive与完整 operator boundary。36 个 default/opt-in focused tests 通过;candidate/main doctor 各 1021 passed、conformance 各 8/8。Recorded pinned V1/V2 real-model evidence 与 main 生产 source digest 精确匹配:evidence。按本 issue 允许的 “upstream merge 或明确 reconciliation” closure 条件,本次授权的 fork merge 记录为 fork scope reconciliation,关闭 session-transport implementation issue。不是 upstream 已合并:Intelligent-Internet#552 仍 open,分支未改写/删除。后续 unrestricted execution 不在此 closure 范围,由 #4/#9 与 epic #1 继续跟踪。