Skip to content

feat(server): add native OpenCode 2 support on orchestrator v2 - #12643

Draft
Hoodgail wants to merge 614 commits into
pingdotgg:t3code/codex-turn-mappingfrom
Hoodgail:fix/opencode-2-native-client
Draft

Hoodgail wants to merge 614 commits into
pingdotgg:t3code/codex-turn-mappingfrom
Hoodgail:fix/opencode-2-native-client

Conversation

@Hoodgail

@Hoodgail Hoodgail commented Sep 19, 2026 •

Copy link
Copy Markdown

Problem

Released OpenCode 2 uses the opencode executable but changed its startup banner, authentication and HTTP API. The current integration waits for the V1 banner and then calls V1 SDK endpoints, causing the timeout and empty catalog reported in #11790.

Changes

Add a native @opencode/client@2.0.10 adapter at the new orchestrator boundary while preserving the V1 adapter and existing provider identity/settings. Local sessions share the provider instance's owned server; external servers retain their ownership. Inventory, chat and generation use the selected API generation.

The native path enforces permissions on the server session, reconciles messages and pending requests after stream reconnection, preserves whitespace, follows pagination cursors correctly, restores the selected agent after plan mode, and cancels prompt-hook questions before waiting for Stop admission. Background generation uses a workspace-scoped temporary session with server-enforced tool denial. Generated passwords are redacted from startup failures; only explicitly configured credentials are used for external servers.

Draft scope

Stacked on #2829; base is t3code/codex-turn-mapping. Keep this draft pending the orchestrator rewrite and maintainer agreement on the remaining provider scope, per the closing comments on #8207/#12084/#12284.

This is an initial native integration, not full feature parity:

  • Provider-native subagents are disabled and T3's per-thread MCP injection remains unimplemented.
  • Active steering uses T3's interrupt/restart capability instead of concurrent native prompts.
  • Conditional, hidden and external forms are explicitly declined. Ordinary typed questions are supported.
  • Only /compact is advertised from the native command path.
  • OpenCode 2.0.10 is the minimum supported native version. Earlier OpenCode 2 versions receive an upgrade error.

Validation

Local macOS validation against the pinned rewrite base:

  • 153 focused tests: OpenCode V1 regressions, native-client contracts and adapter lifecycle tests.
  • Opt-in released-CLI tests with OpenCode 2.0.10 and a local mock model: authenticated inventory, policy evaluation, pagination, forks/workspace moves, a complete native T3 adapter turn, tool-free text generation, and image delivery.
  • Server typecheck; lint and formatting for changed files.
  • Production server bundle and bundled CLI --help smoke test.
  • Server-scoped Knip check for files, dependencies and exports.
  • Frozen dependency install and generation of MIT notices for all three new OpenCode packages.

Run the live contract suite with:

OPENCODE_TEST_BINARY=/absolute/path/to/opencode vp test run apps/server/src/provider/OpenCode2.live.test.ts

The CLI tests use isolated state and a local mock model. Cross-platform execution and the upstream CI/review gates remain required before promotion from draft. No frontend source changes.

At publication, GitHub marked the upstream CI run action_required before any jobs started: https://github.com/pingdotgg/t3code/actions/runs/35473766485. Maintainer authorization is needed for those fork-PR workflows; the local checks above are complete.

Model: GPT 6 Astra (Strata). Harness: OpenCode.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Sep 19, 2026
@juliusmarminge
juliusmarminge force-pushed the t3code/codex-turn-mapping branch from 61a3501 to 619623f Compare September 21, 2026 03:05
- Re-route steering that races completion into idempotent follow-up dispatches
- Preserve scheduled-task attribution and provider ownership history across clients
Port main's pull-request discovery, active thread ordering, async question dismissal, settlement fixes, provider-session import, attachment context, and provider correctness changes into orchestration v2.

Keep the branch's intentional composer and subagent behavior while adopting main's web and mobile fixes. Prevent headless setup terminals from hanging on the color probe, and move the v2 migration block to 050-061 after main claimed 048-049.
Restore the failed-before-start timer guard, align two server fixtures with the reconciled behavior, and remove dead files, exports, and dependencies surfaced by Knip.

Drop the temporary branch push trigger now that the PR is mergeable, so each update runs the pull-request workflow once.
Keep main's batch machine-update banner and update action while preserving the v2 runtime-based environment lock used by draft load balancing.
Adopt TypeScript 7 and Effect rc.112 across orchestration v2, including the TaggedError API migration and updated Effect-aware tests. Restore main's composer-aware scroll-to-end clearance while retaining selected-model settings sync, preview recording transfer, image galleries, desktop context menus, and layout hit targets. Regenerate the lockfile on the upgraded dependency baseline.
Advertise bounded socket snapshots and authoritative dispatch validation, omit raw command output and inline file bodies at the wire boundary, and preserve compact status metadata across web and mobile. Add transport-budget coverage for snapshots, resume, commands, legacy import, and projection maintenance.
Restore pinned-thread shelf classification, server-owned unread state, hidden-subagent-safe project ordering, guarded jump hints, draft upload cleanup, and active-provider archive guards across the current and legacy sidebars.

Bring the surrounding current-main sidebar work forward as well: canonical project favicons, stable row layout, thread file drops, account-aware mobile provider badges, and deferred desktop keyring loading.
Keep collapsed model controls in a strip, contain transition overflow, and preserve timeline spacing. Render approval requests as regular grouped worklog entries.

Implemented with GPT-6-Astra via Codex.
Adapt question attachments and Android push verification to V2 requests and shell events. Preserve composer transitions and compact worklogs while integrating upstream loading, navigation, and mobile changes. Release consumed application replay pages without retaining earlier batches.
@juliusmarminge
juliusmarminge force-pushed the t3code/codex-turn-mapping branch from a1f8051 to 0337dd6 Compare September 21, 2026 05:40
Read selected control records for commands, provider cleanup, thread polling, and MCP tools. Select timeline pages before loading payloads, query attachment IDs separately, and restrict handoff and delegated-result reads to relevant runs. Cover unreadable unrelated history, paging across forks, and control behavior with focused regressions.
@juliusmarminge
juliusmarminge force-pushed the fix/opencode-2-native-client branch from 1389b7b to 2373e79 Compare September 21, 2026 20:36
@juliusmarminge

Copy link
Copy Markdown
Member

Rebased this PR onto the current t3code/codex-turn-mapping at 4a4c22b29c. Your single commit applied cleanly; no conflicts. The PR stays a draft.

One fix on top (2373e79f16)

  • In OpenCodeDriver.ts, the API-generation probe (server.version.startsWith("2.")) was an unmemoized effect, so every adapter call (getCapabilities, planSelectionTransition, openSession) and every resolveMaintenance re-ran connectExternal (an extra server.info round-trip, or a legacy health check) against the external server. The generation is fixed for the life of a driver instance, since settings changes rebuild the driver, so the probe result is now stored in a Ref after the first success and reused. A failed probe is not cached, so a server that is temporarily unreachable can still be picked up on the next call. I kept it on the driver rather than the server handle, since the handle is per-connection and this is per-instance state.

Deliberately left alone

  • resolveMaintenance still uses Effect.orElseSucceed(() => true) when the probe fails. ServerProviderShape["resolveMaintenance"] is typed as Effect<ProviderMaintenanceCapabilities> with no error channel, and makeManagedServerProvider and every other driver rely on that, so surfacing the failure would widen the contract across the provider layer. Worth a follow-up if you want it, but out of scope for a touch-up. Note the defaulting to "native" means a legacy server behind a flaky connection can briefly show manual-only maintenance capabilities.

Verified

  • vp test run in apps/server for OpenCode2Adapter.test.ts, OpenCode2Client.test.ts, OpenCodeServerOwner.test.ts, opencodeRuntime.environment.test.ts, Layers/OpenCodeProvider.test.ts, textGeneration/OpenCodeTextGeneration.test.ts: 65 passed. OpenCode2.live.test.ts was skipped (needs OPENCODE_TEST_BINARY).
  • vpr typecheck in apps/server: clean.

Rebased and touched up by a maintainer's agent; a human will re-review.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants