Skip to content

feat: opencode v2 server support with v1 compatibility - #209

Closed
bluetoe-99 wants to merge 1 commit into
dzianisv:mainfrom
bluetoe-99:feat/opencode-v2
Closed

bluetoe-99 wants to merge 1 commit into
dzianisv:mainfrom
bluetoe-99:feat/opencode-v2

Conversation

@bluetoe-99

@bluetoe-99 bluetoe-99 commented Sep 25, 2026 •

Copy link
Copy Markdown

What

Fixes #194 (Android: chat input hidden behind keyboard).
Fixes #205 (opencode2 support?).
Fixes #156 (Unable to see the input box — same composer-behind-keyboard report as #194).

Adds opencode v2 server support while keeping every opencode 1.x (≤ 1.18.x) server working. npm install -g opencode-ai still installs the 1.x line (latest = 1.18.32 as of 2026-09-25), so both APIs are common in the wild and the client now speaks whichever the server speaks.

v2 (src/lib/sdk.ts, src/lib/v2-shape.ts)

  • /api/... endpoints, the v2 SSE envelope ({id, type, data}), the renamed message/part shapes, interrupt, staged revert, session diff.
  • The question tool arrives as a server-side form nested under data.form on form.created. Reading it flat silently dropped every prompt, so questions never appeared in the app.
  • Session-scoped permission and form replies.

v1 (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 — never status code, because unknown routes on both server generations fall through to the web SPA with 200 text/html:

probe v2.0.16 1.18.32
GET /api/info 200 application/json, or 401 unauthenticated 200 text/html (SPA)
GET /global/health 200 text/html (SPA) 200 application/json {healthy, version}

The detected api and serverVersion are stored on the connection, reused across screens, and invalidated when the URL changes; createClient() dispatches on them.

Selection and copying

  • MessageTextSheet + src/lib/message-text.ts: Select text and 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 actually works, with Copy all as the whole-message fallback. The bubble itself has no press at all: a press whose movement stays inside its bounds is kept by the touchable, which is what opened the message menu mid-scroll.
  • Inline selection is now iOS-only for user message text, message error text, code lines and diff lines. selectable <Text> inside FlatList rows is react-native#46999 (still open, no linked PR) and Markdown.tsx already works around it. 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 to what the server sent.
  • Keyboard avoidance via react-native-keyboard-controller, including system-bar insets, so the composer is never hidden behind the keyboard (Android: chat input hidden behind keyboard #194); the SSE stream reconnects on app foreground.

Screenshots

Wrapped code block with the header buttons and the reasoning block:

wrapped code block

Composer visible above the keyboard (#194):

composer above keyboard

Select text sheet with Copy all:

select text sheet

Verification

  • v2: live opencode 2.0.16 server; the question path was verified by replaying a captured form.created stream.
  • v1: live opencode serve on 1.18.32 — 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.
  • tsc --noEmit clean; npm test 363/363, including new suites for the probe classifier, the v2 shape translator, message-text assembly, and two component regression files.

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

Notes

DCO signed off.

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>
@bluetoe-99 bluetoe-99 mentioned this pull request Sep 25, 2026
bariscodefxy added a commit to bariscodefxy/opencode-mobile that referenced this pull request Oct 25, 2026
Ports the protocol layer of upstream PR dzianisv#209 (bluetoe-99) onto the fork:

- src/lib/api-detect.ts: classify a server by response content type, never
  status code. Unknown routes on both generations answer 200 text/html via
  the web SPA, which is why v1 servers used to "pass" a status-only health
  probe and then fail every later request.
- src/lib/v2-shape.ts: v2 envelope/typed-message/part shapes translated to
  the shapes the app already renders (messages, parts, sessions, providers,
  agents, commands, permissions, forms, SSE events).
- src/lib/sdk-v1.ts: the pre-existing v1 transport, unchanged, so
  opencode <= 1.18.x servers keep working.
- src/lib/sdk.ts: probe once at connect, then dispatch on the recorded api.
- connections store: persists api + serverVersion on the connection, drops
  the record when the URL changes, probes before testConnection.
- events store: session-scoped permission/form lists, foreground reconnect.
- docs/v2-api-map.md: the verified v1 -> v2 route/shape map.

Verified: typecheck clean, 363 tests pass. Not yet exercised against a live
v2 server from this machine.
dzianisv added a commit that referenced this pull request Oct 26, 2026
Merged #217 + #216. Sunset paused. #209 is the v2 candidate, #218 blocked
(.test app ID, needs rebase, no live v2 testing). Next agent: use gh CLI,
one batch, one push.
dzianisv added a commit that referenced this pull request Oct 26, 2026
Replaces the closed $10k MRR / Connect goal. Goal: free, reliable Android client for opencode v1 + v2, community PRs with regular owner merges. KPIs: #205/#219 closed, one release shipped, PR queue triaged, gates green, docs honest, merge cadence <60 days. Records #209 merge attempt failure (conflicts, stale mergeable=true) and #218 blocked status.
dzianisv added a commit that referenced this pull request Oct 26, 2026
NOW (P0): rebase/merge #209, verify #219, decide #218, live v2 check, triage green, next release. LATER (P1/P2): keyboard dedupe, #198/#197/#189/#186/#187, honesty cleanup, #162/#95/#134/#65. No other content changes to Goal/KPIs.
dzianisv added a commit that referenced this pull request Nov 1, 2026
Adopt the v2 API client from PR #209 onto current main, keeping the
#216 keyboard/permission work: /api/ routes with envelope responses,
/api/info probe with v1 fallback (sdk-v1 legacy client), V2 event
translator feeding the existing stores, api detection per connection.

Fixes: #198 messages lost on directory switch (clientForDirectory now
passes the probed api), #219 tunnel detection no longer throws on HTML
401/403 and sends tunnel-bypass headers.

Adds MessageTextSheet + Select text message action. Version 0.4.16,
versionCode 43. Typecheck clean, 380/380 tests pass.
@dzianisv

dzianisv commented Nov 7, 2026

Copy link
Copy Markdown
Owner

Owner decision (2026-11-07): closing as superseded. OpenCode v2 server support with v1 compatibility shipped in v0.4.16 (2026-11-01) from our own implementation, and v0.4.17 is current. Thank you for the contribution — if you hit v2 issues on the current release, please open an issue against it.

@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.

opencode2 support? Android: chat input hidden behind keyboard Unable to see the input box

2 participants