Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/opencode/src/plugin/github-copilot/models.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Model } from "@opencode-ai/sdk/v2"
import { Option, Schema } from "effect"
import { anthropicUsesModernAdaptiveThinking } from "@/provider/transform"

const item = Schema.Struct({
model_picker_enabled: Schema.Boolean,
Expand Down Expand Up @@ -176,7 +177,9 @@ function build(key: string, remote: SelectableItem, url: string, prev?: Model):
variants[effort] = {
thinking: {
type: "adaptive",
...(model.api.id.includes("opus-4.7") ? { display: "summarized" } : {}),
// Anthropic omits thinking content by default for adaptive-only
// models newer than opus-4.7; force a summary so it survives.
...(anthropicUsesModernAdaptiveThinking(model.api.id) ? { display: "summarized" } : {}),
},
effort,
}
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/src/provider/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ function openaiCompatibleReasoningEfforts(id: string) {
return gpt5CodexReasoningEfforts(apiId) ?? versionedGpt5ReasoningEfforts(apiId) ?? OPENAI_EFFORTS
}

function anthropicUsesModernAdaptiveThinking(apiId: string) {
export function anthropicUsesModernAdaptiveThinking(apiId: string) {
if (!apiId.toLowerCase().includes("claude-")) return false
// Covers family-first IDs such as claude-opus-4.7 and version-first IDs such as claude-4.7-opus.
// Limit minors to two digits so release dates in IDs such as claude-opus-4-20250514 are not versions.
Expand Down
43 changes: 43 additions & 0 deletions packages/opencode/test/plugin/github-copilot-models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,49 @@ test("clears existing variants so refreshed models calculate provider-specific v
expect(models["claude-opus-4.7"].variants).toBeUndefined()
})

test("summarizes adaptive thinking display for modern claude models beyond opus-4.7", async () => {
globalThis.fetch = mock(() =>
Promise.resolve(
new Response(
JSON.stringify({
data: [
{
model_picker_enabled: true,
id: "claude-sonnet-5",
name: "Claude Sonnet 5",
version: "claude-sonnet-5-2026-06-01",
supported_endpoints: ["/v1/messages"],
capabilities: {
family: "claude-sonnet",
limits: {
max_context_window_tokens: 200000,
max_output_tokens: 64000,
max_prompt_tokens: 176000,
},
supports: {
adaptive_thinking: true,
reasoning_effort: ["low", "medium", "high"],
streaming: true,
tool_calls: true,
},
},
},
],
}),
{ status: 200 },
),
),
) as unknown as typeof fetch

const model = (await CopilotModels.get("https://api.githubcopilot.com")).models["claude-sonnet-5"]
const variant = model.variants?.high as { thinking?: { display?: string } } | undefined

// Anthropic omits thinking content by default for adaptive-only models newer
// than opus-4.7. Without display: "summarized" the API returns no thinking
// text, so it never reaches opencode's UI even though thinking is enabled.
expect(variant?.thinking?.display).toBe("summarized")
})

test("remaps fallback oauth model urls to the enterprise host", async () => {
globalThis.fetch = mock(() => Promise.reject(new Error("timeout"))) as unknown as typeof fetch

Expand Down
Loading