Skip to content

feat: add OpenCode v2 support and Android stability fixes - #220

Closed
meramsey wants to merge 11 commits into
dzianisv:mainfrom
meramsey:fix/pr218-upstream-ready
Closed

meramsey wants to merge 11 commits into
dzianisv:mainfrom
meramsey:fix/pr218-upstream-ready

Conversation

@meramsey

Copy link
Copy Markdown
Contributor

Supersedes #218 with a clean branch based on current main, without rewriting the published PR branch. Incorporates the transport work and authorship from #209.

What changed

  • add OpenCode v2 transport/event normalization with v1 compatibility
  • harden SSE lifecycle, reconnect reconciliation, permissions, questions, drafts, long prompts, and Android session navigation
  • separate cumulative v2 session usage from per-message usage to prevent inflated token and cost displays
  • surface execution failures inline and improve authentication diagnostics
  • add a side-by-side cc.agentlabs.opencode.test Android artifact while preserving production identity
  • document the upstream integration ledger, lifecycle behavior, and v2 API map

Validation

  • npm test (411 passing)
  • npm run typecheck
  • npm run check:versions
  • npm run check:android-identities
  • clean npx expo prebuild --platform android --no-install --clean
  • ./gradlew assembleRelease assembleTestRelease -PtestVersionCode=45
  • inspected both APK package names, labels, versions, and signatures with Android Build Tools 36.0.0

Fresh live v2/cross-client testing remains dependent on a reachable server. Device installation remains dependent on a reachable ADB target.

bluetoe-99 and others added 11 commits October 26, 2026 18:44
opencode 2.x replaced the HTTP API: routes moved under /api/, the SSE envelope
changed from {"payload":{id,type,properties}} to {id,type,data}, message/part
payloads were renamed (Session.Info, Message.Info, UserMessage/AssistantMessage),
and question prompts became server-side forms. `npm install -g opencode-ai` still
installs the 1.x line (1.18.32 as of 2026-09-24), so a client has to speak both
APIs.

v2 client (src/lib/sdk.ts, src/lib/v2-shape.ts):
- /api/... endpoints, the v2 message shapes, interrupt, staged revert, session diff
- SSE via /api/event; the question tool arrives as a form nested under data.form on
  form.created - reading it flat silently dropped every prompt
- session-scoped permission and form replies

v1 client (src/lib/sdk-v1.ts, src/lib/api-detect.ts):
- the transport main already ships, restored unchanged (sessions, prompts, abort,
  revert, diff, questions, permissions, agents, commands, providers, file browsing)
- a connect-time probe classifies the server by response content type: unknown
  routes on both server generations answer 200 text/html through the web SPA, so
  status codes cannot discriminate. /api/info JSON means v2, /global/health JSON
  means v1; api + serverVersion are recorded on the connection and createClient()
  dispatches on them

Message UI:
- selection and copying rework around MessageTextSheet: Select text / Edit are
  header buttons and the sheet renders the whole message (text, reasoning, tool
  input/result/error, files) in a plain ScrollView where native selection works,
  with Copy all as the whole-message fallback. The bubble has no press at all: a
  press whose movement stays inside its bounds is kept by the touchable, which
  opened the message menu mid-scroll.
- inline selection is iOS-only for user message text, message error text, code
  lines and diff lines: selectable <Text> inside FlatList rows is the Android bug
  (react-native#46999, still open) that Markdown.tsx already works around.
  ToolCallCard, ReasoningBlock, ErrorBoundary and Markdown.tsx are unchanged.
- wide code and diff lines wrap instead of scrolling sideways; CodeBlock's Copy
  still hands the clipboard the original string, so pasted code is byte-identical
- keyboard avoidance via react-native-keyboard-controller, including system-bar
  insets, so the composer is never hidden behind the keyboard; SSE reconnects on
  app foreground

Verified against live servers: opencode 2.0.16 (v2 endpoints, and the question path
replayed from a captured form.created stream) and opencode 1.18.32 (`opencode
serve`: health, project, path, session create/list/update/delete/abort/messages,
agents, commands, questions, permissions, providers, and the wrapped {"payload":...}
event stream through the existing unwrap in stores/events.ts).

docs/v2-api-map.md records the verified API maps, event schemas and probe behaviour
for both server generations.

Signed-off-by: bluetoe-99 <102478736+bluetoe-99@users.noreply.github.com>
…ired) from rejected credentials

The health probe only sends Authorization when a password is filled in.
A 401/403 in that state says nothing about the saved password — the user
may simply not have typed it yet — but classify() reported it as
"the server rejected your credentials", sending people re-typing a
perfectly good password (seen live against a self-hosted server that
protects /global/health).

- ProbeAttempt gains authProvided, set by probeConnection from the auth it sent
- classify(): 401/403 + !authProvided -> new auth-required classification
  with an "enter the password" message instead of "rejected your credentials"
- sentry-noise: auth-required joins the auth-failed drop family (user config)
- tests for all four combinations
@dzianisv

dzianisv commented Nov 7, 2026

Copy link
Copy Markdown
Owner

Owner decision (2026-11-07): closing as superseded. OpenCode v2 support shipped in v0.4.16 (2026-11-01) and v0.4.17 is current, so this branch no longer applies cleanly to the product. If specific Android stability fixes are still needed on current main, please open a fresh, narrow PR for just those. Thank you for the work.

@dzianisv dzianisv closed this Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants