Skip to content

fix(opencode): sync provider model hotfixes#482

Merged
Astro-Han merged 14 commits into
devfrom
codex/i477-provider-model-plan
May 7, 2026
Merged

fix(opencode): sync provider model hotfixes#482
Astro-Han merged 14 commits into
devfrom
codex/i477-provider-model-plan

Conversation

@Astro-Han

@Astro-Han Astro-Han commented May 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • Port the narrow provider transform/model hotfix slice from the [Task] Track upstream sync after opencode 17701628bd #477 upstream sync tracker.
  • Fix provider option routing, reasoning variants, Cloudflare AI Gateway options, Codex OAuth model filtering, Copilot variant refresh, and custom DeepSeek interleaved defaults.
  • Normalize different-model Bedrock reasoning replay so reasoning text is replayed as assistant text without forwarding provider metadata.

Why

#477 tracks PawWork's upstream opencode sync after 17701628bd. This PR implements the first bounded provider/model slice while intentionally excluding auth/client credentials, runtime/session retry and serialization fixes, desktop/app work, HttpApi/Effect/listener work, generated SDK/OpenAPI files, and dependency changes.

Related Issue

Refs #477

Human Review Status

Pending. A human should make the final merge decision after reviewing the final diff and verification evidence.

Review Focus

  • Provider option key routing for dotted provider IDs and Cloudflare AI Gateway.
  • Variant generation for OpenAI, GitHub Copilot, Mistral Medium 3.5, and Cloudflare AI Gateway.
  • Codex OAuth model filtering through the provider models hook instead of mutating models in the auth loader.
  • The isolated message-v2 replay change for reasoning parts when continuing a transcript with a different model.

Risk Notes

  • Provider behavior changes are intentional and covered by focused tests, but this still affects model option routing and variant metadata.
  • No dependency or lockfile changes were made. The Cloudflare AI Gateway E2E uses the existing ai-gateway-provider dependency.
  • No app, desktop, UI, server listener, SDK/generated, HttpApi, or Effect migration files were changed.

How To Verify

Install: bun install --frozen-lockfile completed before implementation in this worktree.
Patch check: git cherry -v origin/dev aa3c99a3c0a609ea4dd485355627e3161251584a showed all 15 provider/model candidate PRs as not patch-equivalent absorbed.
Focused tests: bun --cwd packages/opencode test test/session/llm.test.ts test/provider/provider.test.ts test/provider/transform.test.ts test/plugin/codex.test.ts test/plugin/github-copilot-models.test.ts test/session/message-v2.test.ts test/provider/cf-ai-gateway-e2e.test.ts -> 346 pass, 0 fail, 712 expect() calls.
Typecheck: bun run --cwd packages/opencode typecheck -> tsgo --noEmit completed successfully.
Diff check: git diff --check -> no output.
Boundary check: changed files are limited to packages/opencode provider/plugin/session source and tests; no app/desktop/ui/server/sdk/generated, lockfile, or package manifest changes.
Review follow-up: provider.test.ts now covers plugin config-added providers receiving provider.models hooks; transform.test.ts covers Copilot Anthropic SDK provider options routing through the anthropic namespace; provider.test.ts covers Codex OAuth filtering after config-added OpenAI models, scopes post-config OAuth hook reruns to providers whose config declares models, cleans up OAuth auth state so later OpenAI session.llm tests still hit the local responses mock, and covers safe OpenAI/Azure request-body id stripping. cf-ai-gateway-e2e.test.ts now captures all gateway requests instead of only the last intercepted request. provider.test.ts now also covers multiple provider.models hooks for the same provider and verifies the built-in Codex OpenAI no-op hook does not block external OpenAI provider model hooks. provider.ts now restricts post-config provider model hook reruns to hooks that explicitly opt in, and provider.test.ts covers Codex OAuth config aliases surviving an external OpenAI hook while still receiving Codex OAuth normalization. provider.test.ts now also filters Codex-looking aliases whose API id is not Codex OAuth-allowed, and transform.test.ts covers Azure dotted GPT-5 family ids receiving minimal effort. transform.ts now shares dotted providerOptions key logic between request-level and message-level options, with regression coverage for dotted Anthropic and OpenAI-compatible message options. provider.test.ts now snapshots and restores auth.json around auth-mutating provider hook tests. transform.test.ts now covers Copilot Anthropic Opus 4.7 hyphen IDs clamping to the supported medium adaptive effort.

Screenshots or Recordings

Not applicable. This PR has no visible UI changes.

Checklist

  • Human review status is stated above as pending, approved, or not required
  • I linked the related issue, or stated why there is no issue
  • This PR has type, primary area, and priority labels, or I requested maintainer labeling
  • I described the review focus and any meaningful risks
  • I listed the relevant verification steps and the key result for each
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for platform, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant
  • I reviewed the final diff for unrelated changes and suspicious dependency changes
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English

Maintainer labeling requested: type fix, area provider/opencode, priority appropriate for #477 sync slice.

Summary by CodeRabbit

  • New Features

    • Added GPT-5.3 Codex Spark support
    • Improved Azure-aware model selection and dot-split provider routing
    • Expanded reasoning-effort handling across Mistral, Anthropic, Copilot and gateway providers
    • Provider hooks can opt into post-config re-running
  • Bug Fixes

    • Better handling of reasoning content for cross-model compatibility
  • Tests

    • Added and expanded provider, Codex, Copilot, gateway and message-handling tests

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds Azure-aware model selection, provider-model hook machinery (including post-config rerun), OpenAI/Azure POST-body sanitization, expanded reasoning-effort/variant logic (OpenAI/Codex/GPT-5/Mistral), Copilot variant refactor, Codex OAuth allowlist update, reasoning-part emission change, and corresponding tests and wiring.

Changes

Provider model, transform, and message flow

Layer / File(s) Summary
Core provider helpers / request sanitization
packages/opencode/src/provider/provider.ts
Adds exported stripOpenAIResponseInputIDs to sanitize OpenAI/Azure POST bodies and integrates it into POST request formation; adds selectAzureLanguageModel helper used by Azure providers.
Config & plugin hook machinery
packages/opencode/src/provider/provider.ts, packages/plugin/src/index.ts
Introduces configModelProviderIDs, appliedProviderModelHooks, and applyProviderModelHooks to run provider-model transformation hooks; adds postConfig?: boolean to ProviderHook and triggers post-config reruns for applicable hooks.
Model loading / normalization
packages/opencode/src/provider/provider.ts
Extends apiID/apiNpm fallbacks when merging config providers; uses computed apiID for model.api.id; infers interleaved capability from apiNpm; initializes model.variants from ProviderTransform when missing; runs provider-model hooks after config merge.
Provider transform & variant logic
packages/opencode/src/provider/transform.ts
Adds ai-gateway-provider mapping, dot-split-aware providerOptionsKey, allows _ in DeepSeek regex, introduces openaiReasoningEfforts (Codex/GPT-5 handling), broadens Mistral eligibility, changes Azure options().store default to false, and ensures Azure providerOptions return both openai and azure namespaces.
Codex OAuth model handling
packages/opencode/src/plugin/codex.ts
Adds gpt-5.3-codex-spark to CODEX_OAUTH_ALLOWED_MODELS; refactors Codex OAuth filtering to return a new provider object (functional transform), zero costs, and conditionally apply GPT-5.5-specific limit logic.
Copilot model construction
packages/opencode/src/plugin/github-copilot/models.ts
Refactors CopilotModels.build to create a typed model then compute and attach variants post-construction based on reasoning_effort/adaptive budgets.
Message emission for reasoning parts
packages/opencode/src/session/message-v2.ts
When the target model differs, emits reasoning text as a normal text part instead of a dedicated reasoning-type part; retains reasoning-type emission for identical model targets.
Provider request wiring
packages/opencode/src/provider/provider.ts, packages/opencode/src/provider/transform.ts
Applies stripOpenAIResponseInputIDs for OpenAI/Azure POST bodies and adapts providerOptions routing to use dot-split-derived keys and gateway mappings.
Tests / E2E
packages/opencode/test/*
Adds and updates tests: Codex OAuth allowlist/provider-hook filtering, Copilot variant construction, Cloudflare AI Gateway e2e, provider transform dotted-ID and mistral variants, stripOpenAIResponseInputIDs unit tests, provider integration and post-config hook tests, and session message tests for reasoning part behavior.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant Loader as Provider.Loader
  participant Config as ConfigStore
  participant Plugin as Plugin.Hooks
  participant Upstream as Upstream(Azure/OpenAI/Gateway)
  Client->>Loader: request generation
  Loader->>Config: load providers & models
  Config->>Plugin: provide config models/hooks
  Plugin->>Loader: apply provider-model hooks (postConfig when flagged) rgba(120,180,60,0.5)
  Loader->>Loader: sanitize POST via stripOpenAIResponseInputIDs
  Loader->>Upstream: selectAzureLanguageModel / send request
  Upstream-->>Loader: response
  Loader-->>Client: normalized result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

bug

Poem

A rabbit nibbles code at night,
Hooks and variants gleam in light 🐇
Codex, Azure, models sing,
Sanitized payloads take to wing.
Hops of tests ensure it's right.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(opencode): sync provider model hotfixes' clearly describes the main change—syncing provider model hotfixes into the opencode package following conventional commit format.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description comprehensively follows the template with all required sections completed: Summary, Why, Related Issue, Human Review Status, Review Focus, Risk Notes, How To Verify (with detailed test results), Screenshots/Recordings (N/A noted), and Checklist (all items checked).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/i477-provider-model-plan

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors model and provider handling, notably moving Codex model filtering to a provider hook and enhancing GitHub Copilot's variant detection for reasoning and adaptive thinking. It introduces support for the Cloudflare AI Gateway, defaults interleaved reasoning fields for DeepSeek models, and updates Azure provider settings to disable storage by default. Additionally, the logic for handling reasoning message parts during model transitions has been improved. I have no feedback to provide.

@Astro-Han Astro-Han added upstream Tracked upstream or vendor behavior P1 High priority harness Model harness, prompts, tool descriptions, and session mechanics labels May 6, 2026
@Astro-Han

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/opencode/src/provider/transform.ts (1)

688-701: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Wrap the @ai-sdk/openai switch clause in braces.

Line 688 declares a lexical variable directly under the case statement, triggering Biome's noSwitchDeclarations error rule. Add braces to block-scope the clause.

Suggested fix
-    case "@ai-sdk/openai":
-      // https://v5.ai-sdk.dev/providers/ai-sdk-providers/openai
-      const openaiEfforts = openaiReasoningEfforts(model.api.id, model.release_date)
-      if (!openaiEfforts) return {}
-      return Object.fromEntries(
-        openaiEfforts.map((effort) => [
-          effort,
-          {
-            reasoningEffort: effort,
-            reasoningSummary: "auto",
-            include: ["reasoning.encrypted_content"],
-          },
-        ]),
-      )
+    case "@ai-sdk/openai": {
+      // https://v5.ai-sdk.dev/providers/ai-sdk-providers/openai
+      const openaiEfforts = openaiReasoningEfforts(model.api.id, model.release_date)
+      if (!openaiEfforts) return {}
+      return Object.fromEntries(
+        openaiEfforts.map((effort) => [
+          effort,
+          {
+            reasoningEffort: effort,
+            reasoningSummary: "auto",
+            include: ["reasoning.encrypted_content"],
+          },
+        ]),
+      )
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/provider/transform.ts` around lines 688 - 701, The
switch clause for case "@ai-sdk/openai" declares lexical variables
(openaiEfforts) directly under the case which triggers the noSwitchDeclarations
error; wrap the entire case body in a block (add { ... } after the case) so
openaiEfforts and any other const/let declarations are block-scoped, preserving
the existing logic that calls openaiReasoningEfforts(model.api.id,
model.release_date), guards on !openaiEfforts, and returns the
Object.fromEntries(...) mapping.
packages/opencode/src/provider/provider.ts (1)

1530-1544: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard the OpenAI/Azure body rewrite against non-string payloads.

At line 1535, the code uses JSON.parse(opts.body as string) without verifying that opts.body is actually a string—it could be FormData, a stream, or another BodyInit type from the Fetch API. Similarly, line 1539 assumes every item in body.input is an object with an in check that could fail on primitives. In this generic fetch wrapper, either condition failing will throw before the request is sent, converting an otherwise valid provider call into a hard failure.

Suggested fix
           if (
             (model.api.npm === "@ai-sdk/openai" || model.api.npm === "@ai-sdk/azure") &&
-            opts.body &&
+            typeof opts.body === "string" &&
             opts.method === "POST"
           ) {
-            const body = JSON.parse(opts.body as string)
-            const keepIds = body.store === true
-            if (!keepIds && Array.isArray(body.input)) {
-              for (const item of body.input) {
-                if ("id" in item) {
-                  delete item.id
-                }
-              }
-              opts.body = JSON.stringify(body)
-            }
+            try {
+              const body = JSON.parse(opts.body) as Record<string, unknown>
+              const keepIds = body.store === true
+              if (!keepIds && Array.isArray(body.input)) {
+                for (const item of body.input) {
+                  if (item && typeof item === "object" && "id" in item) {
+                    delete (item as Record<string, unknown>).id
+                  }
+                }
+                opts.body = JSON.stringify(body)
+              }
+            } catch {
+              // leave non-JSON payloads untouched
+            }
           }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/provider/provider.ts` around lines 1530 - 1544, The
body-rewrite for OpenAI/Azure requests in provider.ts is unsafe because it
unconditionally JSON.parse(opts.body as string) and assumes body.input contains
objects; change the logic in the block that checks model.api.npm (the code
creating keepIds and parsing body) to first verify opts.body is a string (typeof
opts.body === "string") before JSON.parse, and only proceed if parsing yields an
object with Array.isArray(body.input); when iterating body.input ensure each
item is an object (typeof item === "object" && item !== null) before checking or
deleting the "id" property; if any guard fails, leave opts.body untouched so
non-string BodyInit types (FormData/streams/primitives) are not mutated.
🧹 Nitpick comments (1)
packages/opencode/test/provider/cf-ai-gateway-e2e.test.ts (1)

13-15: ⚡ Quick win

Capture all intercepted gateway requests to avoid retry-order flakiness

captured is overwritten per request, so a multi-call flow can make assertions depend on last-call ordering rather than the relevant upstream payload.

Suggested refactor
-type Captured = { url: string; outerBody: unknown }
+type Captured = { url: string; outerBody: unknown }

 const realFetch = globalThis.fetch
-let captured: Captured | null = null
+let captured: Captured[] = []

 beforeEach(() => {
-  captured = null
+  captured = []
   const handle = async (
@@
-      captured = { url, outerBody: bodyText ? JSON.parse(bodyText) : null }
+      captured.push({ url, outerBody: bodyText ? JSON.parse(bodyText) : null })
@@
 async function callThroughGateway(apiId: string, providerOptions: ProviderOptions) {
   const aigateway = createAiGateway({ accountId: "test", gateway: "test", apiKey: "test" })
   const unified = createUnified()
   await generateText({ model: aigateway(unified(apiId)), prompt: "hi", providerOptions })
-  return extractUpstreamQuery(captured?.outerBody)
+  return captured.map((entry) => extractUpstreamQuery(entry.outerBody)).find((query) => query !== undefined)
 }

Also applies to: 29-30, 81-86

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/test/provider/cf-ai-gateway-e2e.test.ts` around lines 13 -
15, The test currently overwrites the single variable captured for each
intercepted fetch, causing flakiness; change captured from a single Captured |
null to an array (e.g., let captured: Captured[] = []) and in the fetch
interception handler push each new captured object instead of assigning it, then
update all places that read captured (including the other occurrences in this
test around the fetch stubs and assertions) to index into the array (e.g.,
captured[0], captured[1]) or assert on array contents/length to make multi-call
flows stable; ensure type signatures and any teardown that referenced the old
captured are adjusted accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/opencode/src/provider/provider.ts`:
- Around line 1530-1544: The body-rewrite for OpenAI/Azure requests in
provider.ts is unsafe because it unconditionally JSON.parse(opts.body as string)
and assumes body.input contains objects; change the logic in the block that
checks model.api.npm (the code creating keepIds and parsing body) to first
verify opts.body is a string (typeof opts.body === "string") before JSON.parse,
and only proceed if parsing yields an object with Array.isArray(body.input);
when iterating body.input ensure each item is an object (typeof item ===
"object" && item !== null) before checking or deleting the "id" property; if any
guard fails, leave opts.body untouched so non-string BodyInit types
(FormData/streams/primitives) are not mutated.

In `@packages/opencode/src/provider/transform.ts`:
- Around line 688-701: The switch clause for case "@ai-sdk/openai" declares
lexical variables (openaiEfforts) directly under the case which triggers the
noSwitchDeclarations error; wrap the entire case body in a block (add { ... }
after the case) so openaiEfforts and any other const/let declarations are
block-scoped, preserving the existing logic that calls
openaiReasoningEfforts(model.api.id, model.release_date), guards on
!openaiEfforts, and returns the Object.fromEntries(...) mapping.

---

Nitpick comments:
In `@packages/opencode/test/provider/cf-ai-gateway-e2e.test.ts`:
- Around line 13-15: The test currently overwrites the single variable captured
for each intercepted fetch, causing flakiness; change captured from a single
Captured | null to an array (e.g., let captured: Captured[] = []) and in the
fetch interception handler push each new captured object instead of assigning
it, then update all places that read captured (including the other occurrences
in this test around the fetch stubs and assertions) to index into the array
(e.g., captured[0], captured[1]) or assert on array contents/length to make
multi-call flows stable; ensure type signatures and any teardown that referenced
the old captured are adjusted accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 919de33f-256d-4439-adad-27abe41e57e1

📥 Commits

Reviewing files that changed from the base of the PR and between b917193 and c64ada9.

📒 Files selected for processing (11)
  • packages/opencode/src/plugin/codex.ts
  • packages/opencode/src/plugin/github-copilot/models.ts
  • packages/opencode/src/provider/provider.ts
  • packages/opencode/src/provider/transform.ts
  • packages/opencode/src/session/message-v2.ts
  • packages/opencode/test/plugin/codex.test.ts
  • packages/opencode/test/plugin/github-copilot-models.test.ts
  • packages/opencode/test/provider/cf-ai-gateway-e2e.test.ts
  • packages/opencode/test/provider/provider.test.ts
  • packages/opencode/test/provider/transform.test.ts
  • packages/opencode/test/session/message-v2.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/opencode/src/provider/transform.ts (1)

675-677: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the shared GPT-5 matcher for Azure reasoning variants.

This branch only recognizes gpt-5 and gpt-5-*, so versioned Azure IDs like gpt-5.4 never get the minimal variant. That makes Azure GPT-5.x variants diverge from the OpenAI path in the same file.

Proposed fix
-      if (id.includes("gpt-5-") || id === "gpt-5") {
+      if (GPT5_FAMILY_RE.test(id)) {
         azureEfforts.unshift("minimal")
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/opencode/src/provider/transform.ts` around lines 675 - 677, The
branch that adds "minimal" to azureEfforts currently checks
id.includes("gpt-5-") || id === "gpt-5" and misses versioned Azure names like
"gpt-5.4"; replace that ad-hoc check with the project's shared GPT-5 matcher
used elsewhere (e.g., the helper function named isGpt5Model or matchesGpt5) so
the condition becomes "if (sharedGpt5Matcher(id)) {
azureEfforts.unshift('minimal') }", ensuring all GPT-5 variants (including
gpt-5.x) get the minimal Azure variant.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/opencode/src/plugin/codex.ts`:
- Around line 445-447: The filter is using the alias key (modelId) to decide
Codex OAuth allowlist status, letting aliases like "my-codex-alias" bypass
rules; update the predicate to use the upstream id instead: call
shouldKeepCodexOAuthModel with model.api.id (instead of modelId) so the check is
based on the real API id (e.g., change shouldKeepCodexOAuthModel(modelId,
model.api.id) to shouldKeepCodexOAuthModel(model.api.id) or otherwise pass
model.api.id as the identifier argument), referencing provider.models, modelId,
model.api.id and shouldKeepCodexOAuthModel to locate the change.

---

Outside diff comments:
In `@packages/opencode/src/provider/transform.ts`:
- Around line 675-677: The branch that adds "minimal" to azureEfforts currently
checks id.includes("gpt-5-") || id === "gpt-5" and misses versioned Azure names
like "gpt-5.4"; replace that ad-hoc check with the project's shared GPT-5
matcher used elsewhere (e.g., the helper function named isGpt5Model or
matchesGpt5) so the condition becomes "if (sharedGpt5Matcher(id)) {
azureEfforts.unshift('minimal') }", ensuring all GPT-5 variants (including
gpt-5.x) get the minimal Azure variant.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e747d60d-ea0e-4225-b42a-20759fc36d66

📥 Commits

Reviewing files that changed from the base of the PR and between c64ada9 and 93f22bc.

📒 Files selected for processing (6)
  • packages/opencode/src/plugin/codex.ts
  • packages/opencode/src/provider/provider.ts
  • packages/opencode/src/provider/transform.ts
  • packages/opencode/test/provider/cf-ai-gateway-e2e.test.ts
  • packages/opencode/test/provider/provider.test.ts
  • packages/plugin/src/index.ts

Comment thread packages/opencode/src/plugin/codex.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/opencode/src/provider/transform.ts`:
- Around line 1145-1151: The message-level provider remapping in message() is
out of sync with providerOptions(): update message() so it uses the same
dotted-key logic as providerOptions() — detect if model.providerID.includes(".")
and use model.providerID.split(".")[0] as the remap key for dotted providers,
otherwise fall back to sdkKey(model.api.npm) ?? model.providerID — this ensures
request-level and message-level options are serialized under the same provider
namespace (match the logic used in providerOptions()).

In `@packages/opencode/test/provider/provider.test.ts`:
- Around line 2958-3006: Before mutating global auth with Auth.remove or
Auth.set in the test, capture the current auth state (e.g., read/auth-export the
existing auth.json via the Auth API or filesystem) and save it to a local
variable; after the test (in the finally block) restore the original state by
re-applying the saved snapshot (using Auth.set or writing back the saved
auth.json) so pre-existing credentials are preserved and tests cannot clobber
global auth or leak across parallel runs; apply this snapshot/restore pattern
around the Auth.remove call in this test (and the similar tests noted) inside
the Instance.provide/init/finally flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e4cbe1a0-5ad3-4e4b-85ae-e7a20a054e7f

📥 Commits

Reviewing files that changed from the base of the PR and between 93f22bc and 57c79bd.

📒 Files selected for processing (5)
  • packages/opencode/src/plugin/codex.ts
  • packages/opencode/src/provider/transform.ts
  • packages/opencode/test/plugin/codex.test.ts
  • packages/opencode/test/provider/provider.test.ts
  • packages/opencode/test/provider/transform.test.ts

Comment thread packages/opencode/src/provider/transform.ts Outdated
Comment thread packages/opencode/test/provider/provider.test.ts
@Astro-Han

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Astro-Han

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/opencode/src/provider/transform.ts`:
- Around line 721-724: The Copilot adaptive-effort clamp only checks
model.api.id.includes("opus-4.7") and misses the alternate spelling "opus-4-7";
update the conditional in the block that handles model.providerID ===
"github-copilot" to accept both spellings (e.g., check model.api.id for
includes("opus-4.7") OR includes("opus-4-7") or normalize the id string before
checking) so efforts = ["medium"] runs for either form, then continue filtering
out "max" and "xhigh" as before.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f0df2e59-0309-4570-a26d-752326160b69

📥 Commits

Reviewing files that changed from the base of the PR and between 57c79bd and 41d2e2b.

📒 Files selected for processing (3)
  • packages/opencode/src/provider/transform.ts
  • packages/opencode/test/provider/provider.test.ts
  • packages/opencode/test/provider/transform.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/opencode/test/provider/transform.test.ts
  • packages/opencode/test/provider/provider.test.ts

Comment thread packages/opencode/src/provider/transform.ts
@Astro-Han Astro-Han merged commit d216ec0 into dev May 7, 2026
22 checks passed
@Astro-Han Astro-Han deleted the codex/i477-provider-model-plan branch May 7, 2026 03:20
Astro-Han added a commit that referenced this pull request May 7, 2026
Refs #477.

Port PR Slice 2 from the upstream opencode sync range after 17701628bd. This slice covers auth/client credential hotfixes only; provider/model work already landed in #482 and this PR intentionally excludes runtime/session/tool safety, desktop packaging, HttpApi listener migration, generated SDK/OpenAPI, dependency, and lockfile work.

Upstream behavior covered:
- #25529: provider auth login inherits stderr so child-command failures are visible.
- #25591: ACP internal SDK client sends server auth.
- #25592: SDK/CLI error formatting no longer surfaces bare `{}` for empty or opaque server errors.
- #25596: internal clients respect `OPENCODE_SERVER_USERNAME`.
- #25600: `opencode run --attach` supports explicit `--username/-u`.
- #25636: app startup captures `auth_token` credentials, removes the token from URL/history, and keeps terminal websocket auth working when credentials came from a startup token.

Implementation summary:
- Added `ServerAuth` as the shared Basic auth helper for header construction and credential validation.
- Rewired server middleware, ACP, plugin-internal clients, and `run --attach` to use shared auth behavior.
- Preserved Basic Auth browser challenge behavior with `WWW-Authenticate: Basic realm="opencode"`.
- Avoided mutating incoming Fetch/Bun request headers; `auth_token` query credentials are parsed as local auth candidates.
- Added app helpers for auth token encode/decode and startup token server resolution.
- Preserved startup-token credentials over same-URL persisted servers while keeping display names and preventing the runtime `authToken` marker from entering persisted server records.
- Moved terminal websocket URL construction into a helper with explicit tests for non-same-origin saved credentials, same-origin saved credentials, and same-origin startup-token credentials.
- Wrapped empty generated SDK error payloads into readable `Error` objects while passing non-empty parsed errors through.

Review follow-up:
- Fixed Gemini's request-header mutation finding by removing `c.req.raw.headers.set(...)` from auth middleware.
- Restored Basic Auth challenge headers after switching away from `hono/basic-auth`.
- Hardened server persistence types so `authToken` remains runtime-only.
- Preserved stored display names when startup token credentials override a same-URL server.

Verification:
- `bun test test/server/auth.test.ts test/util/error.test.ts`: 13 passed.
- `bun test --preload ./happydom.ts src/utils/server.test.ts src/context/server.test.ts src/utils/terminal-websocket-url.test.ts`: 10 passed.
- `bun run typecheck` in `packages/opencode`: passed.
- `bun run typecheck` in `packages/app`: passed.
- `bun run typecheck` in `packages/sdk/js`: passed.
- `git diff --check`: clean.
- PR CI before merge: ci, codeql, desktop-smoke, e2e-artifacts, dependency-review, commit-lint, CodeRabbit, and semantic PR title all success.
@coderabbitai coderabbitai Bot mentioned this pull request May 8, 2026
11 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

harness Model harness, prompts, tool descriptions, and session mechanics P1 High priority upstream Tracked upstream or vendor behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant