Merge remote-tracking branch 'origin/dev' into reasoning-model-api
# Conflicts: # packages/opencode/src/provider/transform.ts # packages/opencode/test/provider/transform.test.ts
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.17.11",
|
||||
"version": "1.17.12",
|
||||
"name": "opencode",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -462,7 +462,9 @@ export function message(msgs: ModelMessage[], model: Provider.Model, options: Re
|
||||
if (
|
||||
options.store !== true &&
|
||||
key &&
|
||||
["@ai-sdk/openai", "@ai-sdk/azure", "@ai-sdk/amazon-bedrock/mantle"].includes(model.api.npm)
|
||||
["@ai-sdk/openai", "@ai-sdk/azure", "@ai-sdk/amazon-bedrock/mantle", "@ai-sdk/github-copilot"].includes(
|
||||
model.api.npm,
|
||||
)
|
||||
) {
|
||||
msgs = mapProviderOptions(msgs, (options) => {
|
||||
if (!options?.[key] || !("itemId" in options[key])) return options
|
||||
@@ -1141,7 +1143,8 @@ export function providerOptions(model: Provider.Model, options: { [x: string]: a
|
||||
model.api.npm === "@ai-sdk/azure" ||
|
||||
model.api.npm === "@ai-sdk/amazon-bedrock/mantle"
|
||||
const normalized =
|
||||
usesOpenAIReasoningGate && options.reasoningEffort !== undefined && options.forceReasoning === undefined
|
||||
usesOpenAIReasoningGate &&
|
||||
(model.capabilities.reasoning || options.reasoningEffort !== undefined || options.reasoningSummary !== undefined)
|
||||
? { ...options, forceReasoning: true }
|
||||
: options
|
||||
|
||||
|
||||
@@ -628,6 +628,30 @@ describe("ProviderTransform.providerOptions", () => {
|
||||
})
|
||||
})
|
||||
|
||||
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",
|
||||
@@ -659,11 +683,11 @@ describe("ProviderTransform.providerOptions", () => {
|
||||
})
|
||||
})
|
||||
|
||||
test("preserves explicit forceReasoning override", () => {
|
||||
test("overrides forceReasoning false when reasoning should be forced", () => {
|
||||
expect(
|
||||
ProviderTransform.providerOptions(createModel(), { forceReasoning: false, reasoningEffort: "xhigh" }),
|
||||
).toEqual({
|
||||
openai: { forceReasoning: false, reasoningEffort: "xhigh" },
|
||||
openai: { forceReasoning: true, reasoningEffort: "xhigh" },
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2322,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 = [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user