chore: reset opencode changes to main

This commit is contained in:
kirillk
2026-06-22 21:31:52 -04:00
parent 71dc01262b
commit c1d1d5795d
3 changed files with 326 additions and 62 deletions
+65 -20
View File
@@ -19,6 +19,11 @@ function mimeToModality(mime: string): Modality | undefined {
export const OUTPUT_TOKEN_MAX = 32_000
// OpenAI Responses `include` value that returns the encrypted reasoning state
// needed for stateless multi-turn reasoning (store: false). Hoisted so every
// branch that requests it stays in lockstep.
const INCLUDE_ENCRYPTED_REASONING = ["reasoning.encrypted_content"] as const
export function sanitizeSurrogates(content: string) {
return content.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "\uFFFD")
}
@@ -601,9 +606,17 @@ function openaiCompatibleReasoningEfforts(id: string) {
return gpt5CodexReasoningEfforts(apiId) ?? versionedGpt5ReasoningEfforts(apiId) ?? OPENAI_EFFORTS
}
function anthropicOpus47OrLater(apiId: string) {
const version = /opus-(\d+)[.-](\d+)(?:[.@-]|$)/i.exec(apiId)
if (!version) return false
const major = Number(version[1])
const minor = Number(version[2])
return major > 4 || (major === 4 && minor >= 7)
}
function anthropicAdaptiveEfforts(apiId: string): string[] | null {
// kilocode_change start - treat opus-4.8 like opus-4.7
if (["opus-4-7", "opus-4.7", "opus-4-8", "opus-4.8"].some((v) => apiId.includes(v))) {
if (anthropicOpus47OrLater(apiId)) {
return ["low", "medium", "high", "xhigh", "max"]
}
// kilocode_change end
@@ -642,7 +655,39 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
if (!model.capabilities.reasoning) return {}
const id = model.id.toLowerCase()
const glm52 = ["glm-5.2", "glm-5-2", "glm-5p2"].some(
(name) => id.includes(name) || model.api.id.toLowerCase().includes(name),
)
if (
model.api.id.toLowerCase().includes("minimax-m3") &&
["@ai-sdk/anthropic", "@ai-sdk/openai-compatible"].includes(model.api.npm)
) {
return {
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
}
}
const adaptiveOpus = anthropicOpus47OrLater(model.api.id)
const adaptiveEfforts = anthropicAdaptiveEfforts(model.api.id)
if (glm52 && model.api.npm === "@openrouter/ai-sdk-provider") {
// OpenRouter maps xhigh to GLM-5.2's native max effort.
return {
high: { reasoning: { effort: "high" } },
xhigh: { reasoning: { effort: "xhigh" } },
}
}
if (glm52 && model.api.npm === "@ai-sdk/openai-compatible") {
return {
high: { reasoningEffort: "high" },
max: { reasoningEffort: "max" },
}
}
if (glm52 && model.api.npm === "@ai-sdk/anthropic") {
return {
high: { effort: "high" },
max: { effort: "max" },
}
}
if (
id.includes("deepseek-chat") ||
@@ -723,6 +768,10 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
{
thinking: {
type: "adaptive",
// Opus 4.7+ flips the API default for `display` to "omitted", which
// returns empty thinking blocks. Force "summarized" so summaries
// survive (4.6/Sonnet 4.6 already default to "summarized").
...(adaptiveOpus ? { display: "summarized" } : {}),
},
effort,
},
@@ -796,7 +845,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
{
reasoningEffort: effort,
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
include: INCLUDE_ENCRYPTED_REASONING,
},
]),
)
@@ -832,7 +881,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
{
reasoningEffort: effort,
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
include: INCLUDE_ENCRYPTED_REASONING,
},
]),
)
@@ -845,7 +894,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
{
reasoningEffort: effort,
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
include: INCLUDE_ENCRYPTED_REASONING,
},
]),
)
@@ -880,11 +929,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
{
thinking: {
type: "adaptive",
// kilocode_change start - treat opus-4.8 like opus-4.7
...(["opus-4-7", "opus-4.7", "opus-4-8", "opus-4.8"].some((v) => model.api.id.includes(v))
? { display: "summarized" }
: {}),
// kilocode_change end
...(adaptiveOpus ? { display: "summarized" } : {}),
},
effort,
},
@@ -921,11 +966,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
reasoningConfig: {
type: "adaptive",
maxReasoningEffort: effort,
// kilocode_change start - treat opus-4.8 like opus-4.7
...(["opus-4-7", "opus-4.7", "opus-4-8", "opus-4.8"].some((v) => model.api.id.includes(v))
? { display: "summarized" }
: {}),
// kilocode_change end
...(adaptiveOpus ? { display: "summarized" } : {}),
},
},
]),
@@ -1163,9 +1204,13 @@ export function options(input: {
}
}
// kilocode_change start
// Enable thinking by default for kimi models using anthropic SDK
const modelId = input.model.api.id.toLowerCase()
// MiniMax's Anthropic interface defaults thinking off, unlike Chat Completions.
if (modelId.includes("minimax-m3") && input.model.api.npm === "@ai-sdk/anthropic") {
result["thinking"] = { type: "adaptive" }
}
// Enable thinking by default for kimi models using anthropic SDK
if (
(input.model.api.npm === "@ai-sdk/anthropic" || input.model.api.npm === "@ai-sdk/google-vertex/anthropic") &&
(modelId.includes("k2p") || modelId.includes("kimi-k2.") || modelId.includes("kimi-k2p"))
@@ -1175,9 +1220,7 @@ export function options(input: {
budgetTokens: Math.min(16_000, Math.floor(input.model.limit.output / 2 - 1)),
}
}
// kilocode_change end
// kilocode_change start
// Enable thinking for reasoning models on alibaba-cn (DashScope).
// DashScope's OpenAI-compatible API requires `enable_thinking: true` in the request body
// to return reasoning_content. Without it, models like kimi-k2.5, qwen-plus, qwen3, qwq,
@@ -1191,7 +1234,6 @@ export function options(input: {
) {
result["enable_thinking"] = true
}
// kilocode_change end
if (input.model.api.npm === "@ai-sdk/azure" && input.model.api.id.includes("gpt-5.5")) {
result["reasoningSummary"] = "auto"
@@ -1209,6 +1251,9 @@ export function options(input: {
input.model.api.npm === "@kilocode/kilo-gateway" // kilocode_change
) {
result["reasoningSummary"] = "auto"
if (input.model.api.npm === "@ai-sdk/openai") {
result["include"] = INCLUDE_ENCRYPTED_REASONING
}
}
}
@@ -1230,7 +1275,7 @@ export function options(input: {
if (input.model.providerID.startsWith("opencode")) {
result["promptCacheKey"] = input.sessionID
result["include"] = ["reasoning.encrypted_content"]
result["include"] = INCLUDE_ENCRYPTED_REASONING
result["reasoningSummary"] = "auto"
}
}
-39
View File
@@ -1,39 +0,0 @@
// kilocode_change - new file
declare module "@lydell/node-pty" {
export function spawn(file: string, args: string[] | string, opts: Opts): IPty
export interface Opts {
name?: string
cols?: number
rows?: number
cwd?: string
env?: Record<string, string | undefined>
encoding?: string | null
handleFlowControl?: boolean
flowControlPause?: string
flowControlResume?: string
uid?: number
gid?: number
useConpty?: boolean
useConptyDll?: boolean
conptyInheritCursor?: boolean
}
export interface IPty {
readonly pid: number
readonly onData: (listener: (data: string) => void) => Disp
readonly onExit: (listener: (event: Exit) => void) => Disp
write(data: string | Buffer): void
resize(cols: number, rows: number): void
kill(signal?: string): void
}
export interface Disp {
dispose(): void
}
export interface Exit {
exitCode: number
signal?: number
}
}
@@ -172,6 +172,39 @@ describe("ProviderTransform.options - zai/zhipuai thinking", () => {
}
})
describe("ProviderTransform.options - minimax m3 thinking", () => {
const createModel = (npm: string) =>
({
id: "minimax/minimax-m3",
providerID: "minimax",
api: {
id: "minimax-m3",
url: "https://api.minimax.com",
npm,
},
capabilities: { reasoning: true },
limit: { output: 64_000 },
}) as any
test("explicitly enables adaptive thinking with the anthropic SDK", () => {
expect(
ProviderTransform.options({
model: createModel("@ai-sdk/anthropic"),
sessionID: "test-session-123",
}).thinking,
).toEqual({ type: "adaptive" })
})
test("uses the native default with the openai-compatible SDK", () => {
expect(
ProviderTransform.options({
model: createModel("@ai-sdk/openai-compatible"),
sessionID: "test-session-123",
}).thinking,
).toBeUndefined()
})
})
describe("ProviderTransform.options - google thinkingConfig gating", () => {
const sessionID = "test-session-123"
@@ -271,6 +304,7 @@ describe("ProviderTransform.options - gpt-5 textVerbosity", () => {
const model = createGpt5Model("gpt-5.2")
const result = ProviderTransform.options({ model, sessionID, providerOptions: {} })
expect(result.textVerbosity).toBe("low")
expect(result.include).toEqual(["reasoning.encrypted_content"])
})
test("gpt-5.1 should have textVerbosity set to low", () => {
@@ -2410,13 +2444,46 @@ describe("ProviderTransform.variants", () => {
expect(result).toEqual({})
})
// kilocode_change start: minimax
test("minimax direct anthropic provider returns instant/thinking toggle", () => {
test("minimax m3 using anthropic returns thinking toggles", () => {
const model = createMockModel({
id: "minimax/MiniMax-M3",
id: "minimax/minimax-m3",
providerID: "minimax",
api: {
id: "MiniMax-M3",
url: "https://api.minimax.com/anthropic/v1",
npm: "@ai-sdk/anthropic",
},
})
const result = ProviderTransform.variants(model)
expect(result).toEqual({
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
})
})
test("minimax m3 using openai-compatible returns thinking toggles", () => {
const model = createMockModel({
id: "minimax/minimax-m3",
providerID: "minimax",
api: {
id: "minimax-m3",
url: "https://api.minimax.com/v1",
npm: "@ai-sdk/openai-compatible",
},
})
expect(ProviderTransform.variants(model)).toEqual({
none: { thinking: { type: "disabled" } },
thinking: { thinking: { type: "adaptive" } },
})
})
// kilocode_change start: minimax
test("minimax m2.7 direct anthropic provider returns instant/thinking toggle", () => {
const model = createMockModel({
id: "minimax/MiniMax-M2.7",
providerID: "minimax",
api: {
id: "MiniMax-M2.7",
url: "https://api.minimax.io/anthropic/v1",
npm: "@ai-sdk/anthropic",
},
@@ -2461,6 +2528,102 @@ describe("ProviderTransform.variants", () => {
expect(result.low).toEqual({ reasoningEffort: "low" })
})
test("glm-5.2 returns native effort variants for openai-compatible providers", () => {
const model = createMockModel({
id: "zhipuai/glm-5.2",
providerID: "zhipuai",
api: {
id: "glm-5.2",
url: "https://open.bigmodel.cn/api/paas/v4",
npm: "@ai-sdk/openai-compatible",
},
})
expect(ProviderTransform.variants(model)).toEqual({
high: { reasoningEffort: "high" },
max: { reasoningEffort: "max" },
})
})
test("recognizes GLM-5.2 provider model IDs", () => {
for (const id of ["accounts/fireworks/models/glm-5p2", "zai-org-glm-5-2", "umans-glm-5.2"]) {
const model = createMockModel({
id: `test/${id}`,
api: {
id,
url: "https://api.test.com",
npm: "@ai-sdk/openai-compatible",
},
})
expect(ProviderTransform.variants(model)).toEqual({
high: { reasoningEffort: "high" },
max: { reasoningEffort: "max" },
})
}
})
test("recognizes GLM-5.2 from the API ID when the configured model ID is an alias", () => {
const model = createMockModel({
id: "custom/my-glm",
api: {
id: "accounts/fireworks/models/glm-5p2",
url: "https://api.fireworks.ai/inference/v1",
npm: "@ai-sdk/openai-compatible",
},
})
expect(ProviderTransform.variants(model)).toEqual({
high: { reasoningEffort: "high" },
max: { reasoningEffort: "max" },
})
})
test("glm-5.2 returns openrouter effort variants for openrouter", () => {
const model = createMockModel({
id: "openrouter/z-ai/glm-5.2",
providerID: "openrouter",
api: {
id: "z-ai/glm-5.2",
url: "https://openrouter.ai/api/v1",
npm: "@openrouter/ai-sdk-provider",
},
})
expect(ProviderTransform.variants(model)).toEqual({
high: { reasoning: { effort: "high" } },
xhigh: { reasoning: { effort: "xhigh" } },
})
})
test("glm-5.2 returns effort variants for anthropic-compatible providers", () => {
const model = createMockModel({
id: "zai-coding-plan/glm-5.2",
providerID: "zai-coding-plan",
api: {
id: "glm-5.2",
url: "https://api.z.ai/api/anthropic",
npm: "@ai-sdk/anthropic",
},
})
expect(ProviderTransform.variants(model)).toEqual({
high: { effort: "high" },
max: { effort: "max" },
})
})
test("glm-5.2 falls back to provider defaults for other packages", () => {
const model = createMockModel({
id: "test/glm-5.2",
api: {
id: "glm-5.2",
url: "https://api.test.com",
npm: "@ai-sdk/amazon-bedrock",
},
})
expect(ProviderTransform.variants(model)).toEqual({
low: { reasoningConfig: { type: "enabled", maxReasoningEffort: "low" } },
medium: { reasoningConfig: { type: "enabled", maxReasoningEffort: "medium" } },
high: { reasoningConfig: { type: "enabled", maxReasoningEffort: "high" } },
})
})
test("mistral models with reasoning support return variants", () => {
const model = createMockModel({
id: "mistral/mistral-small-latest",
@@ -2854,12 +3017,14 @@ describe("ProviderTransform.variants", () => {
expect(result.xhigh).toEqual({
thinking: {
type: "adaptive",
display: "summarized",
},
effort: "xhigh",
})
expect(result.max).toEqual({
thinking: {
type: "adaptive",
display: "summarized",
},
effort: "max",
})
@@ -2879,6 +3044,47 @@ describe("ProviderTransform.variants", () => {
expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"])
})
test("anthropic opus 4.8 forces display summarized for adaptive reasoning", () => {
const model = createMockModel({
id: "anthropic/claude-opus-4-8",
providerID: "gateway",
api: {
id: "anthropic/claude-opus-4-8",
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",
providerID: "gateway",
api: {
id: "anthropic/claude-opus-4-6",
url: "https://gateway.ai",
npm: "@ai-sdk/gateway",
},
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["low", "medium", "high", "max"])
expect(result.high).toEqual({
thinking: {
type: "adaptive",
},
effort: "high",
})
})
test("anthropic models return anthropic thinking options", () => {
const model = createMockModel({
id: "anthropic/claude-sonnet-4",
@@ -3438,6 +3644,12 @@ describe("ProviderTransform.variants", () => {
efforts: ["low", "medium", "high", "xhigh", "max"],
expectedHigh: { thinking: { type: "adaptive", display: "summarized" }, effort: "high" },
},
{
name: "opus 4.8",
apiIds: ["claude-opus-4-8", "claude-opus-4.8"],
efforts: ["low", "medium", "high", "xhigh", "max"],
expectedHigh: { thinking: { type: "adaptive", display: "summarized" }, effort: "high" },
},
]) {
for (const apiId of testCase.apiIds) {
test(`${testCase.name} ${apiId} returns supported reasoning efforts`, () => {
@@ -3507,6 +3719,30 @@ describe("ProviderTransform.variants", () => {
})
})
describe("@ai-sdk/google-vertex/anthropic", () => {
test("opus 4.8 uses adaptive reasoning for Vertex model IDs", () => {
const result = ProviderTransform.variants(
createMockModel({
id: "google-vertex-anthropic/claude-opus-4-8@default",
providerID: "google-vertex-anthropic",
api: {
id: "claude-opus-4-8@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", () => {
test("anthropic sonnet 4.6 returns adaptive reasoning options", () => {
const model = createMockModel({
@@ -3556,6 +3792,28 @@ describe("ProviderTransform.variants", () => {
})
})
test("anthropic opus 4.8 returns adaptive reasoning options with xhigh", () => {
const result = ProviderTransform.variants(
createMockModel({
id: "bedrock/anthropic-claude-opus-4.8",
providerID: "bedrock",
api: {
id: "anthropic.claude-opus-4.8",
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",