chore: merge dev into v2 (#34788)

Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Affan Ali <93028901+affanali2k3@users.noreply.github.com>
Co-authored-by: affanali2k3 <affanalikhanxx@gmail.com>
Co-authored-by: Frank <frank@anoma.ly>
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Jay V <air@live.ca>
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com>
Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com>
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Co-authored-by: Ben Guthrie <benjee.012@gmail.com>
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: Filip <34747899+neriousy@users.noreply.github.com>
Co-authored-by: Max Anderson <max.a.anderson95@gmail.com>
Co-authored-by: Brendan Allan <git@brendonovich.dev>
Co-authored-by: Jack <jack@anoma.ly>
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
Co-authored-by: Dustin Deus <deusdustin@gmail.com>
Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com>
Co-authored-by: Jay <53023+jayair@users.noreply.github.com>
Co-authored-by: runvip <164729189+runvip@users.noreply.github.com>
Co-authored-by: opencode <opencode@sst.dev>
Co-authored-by: Julian Coy <julian@ex-machina.co>
Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com>
This commit is contained in:
James Long
2026-07-01 17:12:00 -04:00
committed by GitHub
co-authored by Brendan Allan Kit Langton opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Affan Ali affanali2k3 Frank opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com> 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 Aiden Cline Jay V Dax Raad Aarav Sareen OpeOginni Luke Parker Ben Guthrie Dax Filip Max Anderson Brendan Allan Jack Shoubhit Dash Dustin Deus starptech Aiden Cline usrnk1 Jay runvip opencode Julian Coy Vladimir Glafirov
parent 932a40cfd9
commit 8c94e9005f
590 changed files with 15772 additions and 5530 deletions
@@ -613,6 +613,84 @@ describe("ProviderTransform.providerOptions", () => {
})
})
test("forces reasoning for custom OpenAI package models with explicit effort", () => {
const model = createModel({
providerID: "meta",
api: {
id: "muse-spark",
url: "https://api.ai.meta.com/v1",
npm: "@ai-sdk/openai",
},
})
expect(ProviderTransform.providerOptions(model, { reasoningEffort: "xhigh", reasoningSummary: "auto" })).toEqual({
openai: { forceReasoning: true, reasoningEffort: "xhigh", reasoningSummary: "auto" },
})
})
test("forces reasoning for OpenAI package models marked reasoning-capable", () => {
expect(ProviderTransform.providerOptions(createModel(), { store: false })).toEqual({
openai: { forceReasoning: true, store: false },
})
})
test("forces reasoning for explicit effort even when model is not marked reasoning-capable", () => {
const model = createModel({
capabilities: {
temperature: true,
reasoning: false,
attachment: true,
toolcall: true,
input: { text: true, audio: false, image: true, video: false, pdf: false },
output: { text: true, audio: false, image: false, video: false, pdf: false },
interleaved: false,
},
})
expect(ProviderTransform.providerOptions(model, { reasoningEffort: "xhigh" })).toEqual({
openai: { forceReasoning: true, reasoningEffort: "xhigh" },
})
})
test("forces reasoning for Azure OpenAI models with explicit effort", () => {
const model = createModel({
providerID: "azure",
api: {
id: "custom-gpt-5-deployment",
url: "https://azure.openai.example.com/openai/v1",
npm: "@ai-sdk/azure",
},
})
expect(ProviderTransform.providerOptions(model, { reasoningEffort: "xhigh" })).toEqual({
openai: { forceReasoning: true, reasoningEffort: "xhigh" },
azure: { forceReasoning: true, reasoningEffort: "xhigh" },
})
})
test("forces reasoning for Bedrock Mantle OpenAI models with explicit effort", () => {
const model = createModel({
providerID: "amazon-bedrock",
api: {
id: "openai.gpt-5-custom",
url: "https://bedrock-mantle.us-east-2.api.aws/openai/v1",
npm: "@ai-sdk/amazon-bedrock/mantle",
},
})
expect(ProviderTransform.providerOptions(model, { reasoningEffort: "xhigh" })).toEqual({
openai: { forceReasoning: true, reasoningEffort: "xhigh" },
})
})
test("overrides forceReasoning false when reasoning should be forced", () => {
expect(
ProviderTransform.providerOptions(createModel(), { forceReasoning: false, reasoningEffort: "xhigh" }),
).toEqual({
openai: { forceReasoning: true, reasoningEffort: "xhigh" },
})
})
test("uses gateway model provider slug for gateway models", () => {
const model = createModel({
providerID: "vercel",
@@ -707,7 +785,7 @@ describe("ProviderTransform.providerOptions", () => {
})
expect(ProviderTransform.providerOptions(model, { reasoningEffort: "medium" })).toEqual({
openai: { reasoningEffort: "medium" },
openai: { forceReasoning: true, reasoningEffort: "medium" },
})
})
@@ -2268,6 +2346,82 @@ describe("ProviderTransform.message - strip openai metadata when store=false", (
expect(result[0].content[0].providerOptions?.openai?.reasoningEncryptedContent).toBe("encrypted")
})
test("strips GitHub Copilot itemId from the copilot namespace, preserving other copilot options", () => {
const copilotModel = {
...openaiModel,
id: "github-copilot/gpt-5.5",
providerID: "github-copilot",
api: {
id: "gpt-5.5",
url: "https://api.githubcopilot.com",
npm: "@ai-sdk/github-copilot",
},
}
const msgs = [
{
role: "assistant",
content: [
{
type: "reasoning",
text: "thinking...",
providerOptions: {
copilot: { itemId: "rs_123", reasoningEncryptedContent: "encrypted" },
},
},
{
// The stale itemId on tool-call parts is what Copilot echoes back as the
// `function_call` item `id`, which is what the upstream connection rejects.
type: "tool-call",
toolCallId: "call_1",
toolName: "bash",
input: { command: "ls" },
providerOptions: {
copilot: { itemId: "fc_456", reasoningEffort: "medium" },
},
},
],
},
] as any[]
const result = ProviderTransform.message(msgs, copilotModel, { store: false }) as any[]
expect(result[0].content[0].providerOptions?.copilot?.itemId).toBeUndefined()
expect(result[0].content[0].providerOptions?.copilot?.reasoningEncryptedContent).toBe("encrypted")
expect(result[0].content[1].providerOptions?.copilot?.itemId).toBeUndefined()
expect(result[0].content[1].providerOptions?.copilot?.reasoningEffort).toBe("medium")
})
test("leaves a stray openai namespace on a Copilot model untouched, since Copilot's Responses model only reads the copilot namespace", () => {
const copilotModel = {
...openaiModel,
id: "github-copilot/gpt-5.5",
providerID: "github-copilot",
api: {
id: "gpt-5.5",
url: "https://api.githubcopilot.com",
npm: "@ai-sdk/github-copilot",
},
}
const msgs = [
{
role: "assistant",
content: [
{
type: "text",
text: "Hello",
providerOptions: {
openai: { itemId: "msg_456" },
},
},
],
},
] as any[]
const result = ProviderTransform.message(msgs, copilotModel, { store: false }) as any[]
expect(result[0].content[0].providerOptions?.openai?.itemId).toBe("msg_456")
})
test("preserves metadata for openai package when store is true", () => {
const msgs = [
{
@@ -3290,6 +3444,27 @@ describe("ProviderTransform.variants", () => {
})
})
test("anthropic sonnet 5 returns adaptive thinking options with xhigh", () => {
const model = createMockModel({
id: "anthropic/claude-sonnet-5",
providerID: "gateway",
api: {
id: "anthropic/claude-sonnet-5",
url: "https://gateway.ai",
npm: "@ai-sdk/gateway",
},
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"])
expect(result.high).toEqual({
thinking: {
type: "adaptive",
display: "summarized",
},
effort: "high",
})
})
test("anthropic opus 4.6 omits display so it keeps the summarized default", () => {
const model = createMockModel({
id: "anthropic/claude-opus-4-6",
@@ -3877,6 +4052,12 @@ describe("ProviderTransform.variants", () => {
efforts: ["low", "medium", "high", "xhigh", "max"],
expectedHigh: { thinking: { type: "adaptive", display: "summarized" }, effort: "high" },
},
{
name: "sonnet 5",
apiIds: ["claude-sonnet-5", "claude-sonnet-5-20260630"],
efforts: ["low", "medium", "high", "xhigh", "max"],
expectedHigh: { thinking: { type: "adaptive", display: "summarized" }, effort: "high" },
},
{
name: "fable 5",
apiIds: ["claude-fable-5"],
@@ -3974,6 +4155,28 @@ describe("ProviderTransform.variants", () => {
effort: "high",
})
})
test("sonnet 5 uses adaptive reasoning for Vertex model IDs", () => {
const result = ProviderTransform.variants(
createMockModel({
id: "google-vertex-anthropic/claude-sonnet-5@default",
providerID: "google-vertex-anthropic",
api: {
id: "claude-sonnet-5@default",
url: "https://us-central1-aiplatform.googleapis.com",
npm: "@ai-sdk/google-vertex/anthropic",
},
}),
)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"])
expect(result.high).toEqual({
thinking: {
type: "adaptive",
display: "summarized",
},
effort: "high",
})
})
})
describe("@ai-sdk/amazon-bedrock", () => {
@@ -4047,6 +4250,28 @@ describe("ProviderTransform.variants", () => {
})
})
test("anthropic sonnet 5 returns adaptive reasoning options with xhigh", () => {
const result = ProviderTransform.variants(
createMockModel({
id: "bedrock/anthropic-claude-sonnet-5",
providerID: "bedrock",
api: {
id: "anthropic.claude-sonnet-5",
url: "https://bedrock.amazonaws.com",
npm: "@ai-sdk/amazon-bedrock",
},
}),
)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"])
expect(result.high).toEqual({
reasoningConfig: {
type: "adaptive",
maxReasoningEffort: "high",
display: "summarized",
},
})
})
test("returns WIDELY_SUPPORTED_EFFORTS with reasoningConfig", () => {
const model = createMockModel({
id: "bedrock/llama-4",
@@ -4229,6 +4454,12 @@ describe("ProviderTransform.variants", () => {
efforts: ["low", "medium", "high", "xhigh", "max"],
thinking: { type: "adaptive", display: "summarized" },
},
{
name: "sonnet 5",
apiIds: ["anthropic--claude-sonnet-5", "anthropic--claude-5-sonnet"],
efforts: ["low", "medium", "high", "xhigh", "max"],
thinking: { type: "adaptive", display: "summarized" },
},
]) {
for (const apiId of testCase.apiIds) {
test(`${testCase.name} ${apiId} returns adaptive thinking variants under modelParams`, () => {