Skip to content
Open
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
66 changes: 55 additions & 11 deletions packages/opencode/src/provider/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,34 @@ function normalizeMessages(
.filter((msg): msg is ModelMessage => msg !== undefined && msg.content !== "")
}

// Bedrock Z.ai GLM: coerce any string toolUse.input back into a JSON
// object. When we replay the history, GLM streams tool-call args as
// partial strings; if a prior assistant turn stored a not-yet-parsed
// string, Bedrock Converse rejects the next turn with
// "The format of the value at messages.N.content.K.toolUse.input
// is invalid. Provide a json object for the field and try again."
if (
model.api.npm === "@ai-sdk/amazon-bedrock" &&
(model.api.id.toLowerCase().includes("glm") ||
model.api.id.toLowerCase().includes("zai_glm"))
) {
msgs = msgs.map((msg) => {
if (msg.role !== "assistant" || !Array.isArray(msg.content)) return msg
return {
...msg,
content: msg.content.map((part: any) => {
if (part?.type !== "tool-call") return part
if (part.input == null) return { ...part, input: {} }
try {
return { ...part, input: JSON.parse(part.input || "{}") }
} catch {
return { ...part, input: {} }
}
}),
}
})
}

if (model.api.id.includes("claude")) {
const scrub = (id: string) => id.replace(/[^a-zA-Z0-9_-]/g, "_")
msgs = msgs.map((msg) => {
Expand Down Expand Up @@ -494,6 +522,7 @@ export function temperature(model: Provider.Model) {
export function topP(model: Provider.Model) {
const id = model.id.toLowerCase()
if (id.includes("qwen")) return 1
if (id.includes("glm") || id.includes("zai_glm")) return 0.95
if (["minimax-m2", "gemini", "kimi-k2.5", "kimi-k2p5", "kimi-k2-5"].some((s) => id.includes(s))) {
return 0.95
}
Expand Down Expand Up @@ -627,7 +656,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
id.includes("deepseek-r1") ||
id.includes("deepseek-v3") ||
id.includes("minimax") ||
id.includes("glm") ||
(id.includes("glm") && model.api.npm !== "@ai-sdk/amazon-bedrock") ||
id.includes("kimi") ||
id.includes("k2p") ||
id.includes("qwen") ||
Expand Down Expand Up @@ -894,17 +923,32 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
}

// For Amazon Nova models, use reasoningConfig with maxReasoningEffort
return Object.fromEntries(
WIDELY_SUPPORTED_EFFORTS.map((effort) => [
effort,
{
reasoningConfig: {
type: "enabled",
maxReasoningEffort: effort,
if (id.includes("nova")) {
return Object.fromEntries(
WIDELY_SUPPORTED_EFFORTS.map((effort) => [
effort,
{
reasoningConfig: {
type: "enabled",
maxReasoningEffort: effort,
},
},
},
]),
)
]),
)
}

// GLM models only support a binary thinking toggle (not graduated
// effort levels), so we expose a single "high" variant — following
// the same convention as Anthropic/Nova on Bedrock where selecting
// an effort level enables reasoning. Omitting the variant keeps
// reasoning off.
if (id.includes("glm") && model.api.npm === "@ai-sdk/amazon-bedrock") {
return {
high: { additionalModelRequestFields: { reasoning_config: "high" } },
}
}

return {}

case "@ai-sdk/google-vertex":
// https://v5.ai-sdk.dev/providers/ai-sdk-providers/google-vertex
Expand Down
Loading