Skip to content
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a7dda4c
chore: bump packages to v6
rekram1-node Mar 20, 2026
6c68689
chore: run v6 codemod
rekram1-node Mar 20, 2026
07ff24f
chore: bump ai gateway package
rekram1-node Mar 20, 2026
be97290
fix: get provider.ts type errors fixed
rekram1-node Mar 20, 2026
44a251a
fix: update message-v2.ts and message-v2.test.ts to v6
rekram1-node Mar 20, 2026
9e03d49
fix: update compaction.ts to v6
rekram1-node Mar 20, 2026
6c2efcb
chore: add note to message-v2 that we need to do further updates to i…
rekram1-node Mar 20, 2026
ba895b1
fix: resolve most prompt.ts v6 issues, need to fully resolve llm.ts b…
rekram1-node Mar 20, 2026
d70a6b3
fix: azure now uses azure key instead of openai in ai sdk v6: https:/…
rekram1-node Mar 20, 2026
dbd72df
fix: further adjust provider.ts, ensure that the typing for language …
rekram1-node Mar 20, 2026
1c77277
fix: add specificationVersion to middleware in llm.ts
rekram1-node Mar 20, 2026
f881bac
chore: add todo in llm.ts
rekram1-node Mar 20, 2026
357a3fc
tweak: switch @ai-sdk/google-vertex key from google to vertex see: ht…
rekram1-node Mar 20, 2026
7644c89
fix prompt.ts to be v6 compat, wrap w/ try catch since type changed a…
rekram1-node Mar 20, 2026
781cc0f
fix: migrate structured-output.test.ts to v6
rekram1-node Mar 20, 2026
9f930bd
fix: adjust imports in github copilot sdk to be v6 compat
rekram1-node Mar 20, 2026
caf7d1f
fix: remove ts ignore for gh copilot provider, this revealed further …
rekram1-node Mar 20, 2026
7088fc6
fix: almost fix transform.ts, add exclusions for tool-approval-reques…
rekram1-node Mar 20, 2026
f38b91e
fix: finish transform.ts v6 migration
rekram1-node Mar 20, 2026
cfe0fc4
fix: migrate message-v2.ts to make toModelOutput logic compliant: htt…
rekram1-node Mar 20, 2026
d6a2460
fix: update stop reason to be 'other' instead of 'unknown' as per v6 …
rekram1-node Mar 23, 2026
0c519ac
chore: rm patches now that ai sdk packages are upgraded
rekram1-node Mar 23, 2026
8c2844b
tweak: adjust stop loop logic
rekram1-node Mar 23, 2026
99889e5
feat: migrate github copilot sdk to v6
rekram1-node Mar 24, 2026
8845f1a
merge dev
rekram1-node Mar 24, 2026
6701b65
fix: missing import
rekram1-node Mar 24, 2026
b85c0b8
fix: comment out gitlab for now
rekram1-node Mar 24, 2026
2f556e0
test: comment out gitlab tests for now
rekram1-node Mar 24, 2026
414ae32
Merge branch 'dev' into ai-sdk-v6
rekram1-node Mar 24, 2026
700d0fe
tweak: use theme tokens for debug bar surface
jayair Mar 24, 2026
f9e35a3
chore: update nix node_modules hashes
opencode-agent[bot] Mar 24, 2026
680a2ff
Merge branch 'dev' into ai-sdk-v6
rekram1-node Mar 24, 2026
09a6b5f
Merge branch 'dev' into ai-sdk-v6
rekram1-node Mar 24, 2026
96646b1
fix: undo changes to debug-bar
rekram1-node Mar 24, 2026
a1dcc7a
chore: upgrade ai sdk v6 deps and patch data url validation
rekram1-node Mar 25, 2026
801a045
TESTING: re-enable gitlab provider despite incompat
rekram1-node Mar 26, 2026
193ebf1
test: add unit test for the image case that failed in the past
rekram1-node Mar 26, 2026
2ced45c
Merge branch 'dev' into ai-sdk-v6
rekram1-node Mar 26, 2026
b662e09
chore: bump gitlab to v6
rekram1-node Mar 26, 2026
306a1ce
chore: bun.lock wasnt in last commit
rekram1-node Mar 26, 2026
2c98ea9
fix: rm unnecessary promise.all in message-v2.test.ts
rekram1-node Mar 27, 2026
83fe44c
fix: add back accidentally deleted result.push call for mistral/devst…
rekram1-node Mar 27, 2026
3eb5bb2
Merge branch 'dev' into ai-sdk-v6
rekram1-node Mar 27, 2026
8f1e77d
fix: patch the ai sdk anthropic package to allow both temp and top_p …
rekram1-node Mar 27, 2026
ca73594
test: update test to use minimax model (makes more sense)
rekram1-node Mar 27, 2026
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
245 changes: 62 additions & 183 deletions bun.lock

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"drizzle-kit": "1.0.0-beta.19-d95b7a4",
"drizzle-orm": "1.0.0-beta.19-d95b7a4",
"effect": "4.0.0-beta.37",
"ai": "5.0.124",
"ai": "6.0.138",
"hono": "4.10.7",
"hono-openapi": "1.1.2",
"fuzzysort": "3.1.0",
Expand Down Expand Up @@ -112,8 +112,7 @@
},
"patchedDependencies": {
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
"@openrouter/ai-sdk-provider@1.5.4": "patches/@openrouter%2Fai-sdk-provider@1.5.4.patch",
"@ai-sdk/xai@2.0.51": "patches/@ai-sdk%2Fxai@2.0.51.patch",
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch"
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch",
"@ai-sdk/provider-utils@4.0.21": "patches/@ai-sdk%2Fprovider-utils@4.0.21.patch"
}
}
6 changes: 3 additions & 3 deletions packages/console/function/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
"@typescript/native-preview": "catalog:"
},
"dependencies": {
"@ai-sdk/anthropic": "2.0.0",
"@ai-sdk/openai": "2.0.2",
"@ai-sdk/openai-compatible": "1.0.1",
"@ai-sdk/anthropic": "3.0.64",
"@ai-sdk/openai": "3.0.48",
"@ai-sdk/openai-compatible": "2.0.37",
"@hono/zod-validator": "catalog:",
"@opencode-ai/console-core": "workspace:*",
"@opencode-ai/console-resource": "workspace:*",
Expand Down
44 changes: 22 additions & 22 deletions packages/opencode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,25 @@
"@actions/core": "1.11.1",
"@actions/github": "6.0.1",
"@agentclientprotocol/sdk": "0.14.1",
"@ai-sdk/amazon-bedrock": "3.0.82",
"@ai-sdk/anthropic": "2.0.65",
"@ai-sdk/azure": "2.0.91",
"@ai-sdk/cerebras": "1.0.36",
"@ai-sdk/cohere": "2.0.22",
"@ai-sdk/deepinfra": "1.0.36",
"@ai-sdk/gateway": "2.0.30",
"@ai-sdk/google": "2.0.54",
"@ai-sdk/google-vertex": "3.0.106",
"@ai-sdk/groq": "2.0.34",
"@ai-sdk/mistral": "2.0.27",
"@ai-sdk/openai": "2.0.89",
"@ai-sdk/openai-compatible": "1.0.32",
"@ai-sdk/perplexity": "2.0.23",
"@ai-sdk/provider": "2.0.1",
"@ai-sdk/provider-utils": "3.0.21",
"@ai-sdk/togetherai": "1.0.34",
"@ai-sdk/vercel": "1.0.33",
"@ai-sdk/xai": "2.0.51",
"@ai-sdk/amazon-bedrock": "4.0.83",
"@ai-sdk/anthropic": "3.0.64",
"@ai-sdk/azure": "3.0.49",
"@ai-sdk/cerebras": "2.0.41",
"@ai-sdk/cohere": "3.0.27",
"@ai-sdk/deepinfra": "2.0.41",
"@ai-sdk/gateway": "3.0.80",
"@ai-sdk/google": "3.0.53",
"@ai-sdk/google-vertex": "4.0.95",
"@ai-sdk/groq": "3.0.31",
"@ai-sdk/mistral": "3.0.27",
"@ai-sdk/openai": "3.0.48",
"@ai-sdk/openai-compatible": "2.0.37",
"@ai-sdk/perplexity": "3.0.26",
"@ai-sdk/provider": "3.0.8",
"@ai-sdk/provider-utils": "4.0.21",
"@ai-sdk/togetherai": "2.0.41",
"@ai-sdk/vercel": "2.0.39",
"@ai-sdk/xai": "3.0.74",
"@aws-sdk/credential-providers": "3.993.0",
"@clack/prompts": "1.0.0-alpha.1",
"@effect/platform-node": "catalog:",
Expand All @@ -100,7 +100,7 @@
"@opencode-ai/script": "workspace:*",
"@opencode-ai/sdk": "workspace:*",
"@opencode-ai/util": "workspace:*",
"@openrouter/ai-sdk-provider": "1.5.4",
"@openrouter/ai-sdk-provider": "2.3.3",
"@opentui/core": "0.1.90",
"@opentui/solid": "0.1.90",
"@parcel/watcher": "2.5.1",
Expand All @@ -110,7 +110,7 @@
"@standard-schema/spec": "1.0.0",
"@zip.js/zip.js": "2.7.62",
"ai": "catalog:",
"ai-gateway-provider": "2.3.1",
"ai-gateway-provider": "3.1.2",
"bonjour-service": "1.3.0",
"bun-pty": "0.4.8",
"chokidar": "4.0.3",
Expand All @@ -121,7 +121,7 @@
"drizzle-orm": "catalog:",
"effect": "catalog:",
"fuzzysort": "3.1.0",
"gitlab-ai-provider": "5.3.3",
"gitlab-ai-provider": "6.0.0",
"glob": "13.0.5",
"google-auth-library": "10.5.0",
"gray-matter": "4.0.3",
Expand Down
73 changes: 56 additions & 17 deletions packages/opencode/src/provider/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { BunProc } from "../bun"
import { Hash } from "../util/hash"
import { Plugin } from "../plugin"
import { NamedError } from "@opencode-ai/util/error"
import { type LanguageModelV3 } from "@ai-sdk/provider"
import { ModelsDev } from "./models"
import { Auth } from "../auth"
import { Env } from "../env"
Expand All @@ -28,7 +29,7 @@ import { createVertex } from "@ai-sdk/google-vertex"
import { createVertexAnthropic } from "@ai-sdk/google-vertex/anthropic"
import { createOpenAI } from "@ai-sdk/openai"
import { createOpenAICompatible } from "@ai-sdk/openai-compatible"
import { createOpenRouter, type LanguageModelV2 } from "@openrouter/ai-sdk-provider"
import { createOpenRouter } from "@openrouter/ai-sdk-provider"
import { createOpenaiCompatible as createGitHubCopilotOpenAICompatible } from "./sdk/copilot"
import { createXai } from "@ai-sdk/xai"
import { createMistral } from "@ai-sdk/mistral"
Expand Down Expand Up @@ -109,7 +110,11 @@ export namespace Provider {
})
}

const BUNDLED_PROVIDERS: Record<string, (options: any) => SDK> = {
type BundledSDK = {
languageModel(modelId: string): LanguageModelV3
}

const BUNDLED_PROVIDERS: Record<string, (options: any) => BundledSDK> = {
"@ai-sdk/amazon-bedrock": createAmazonBedrock,
"@ai-sdk/anthropic": createAnthropic,
"@ai-sdk/azure": createAzure,
Expand All @@ -130,7 +135,6 @@ export namespace Provider {
"@ai-sdk/perplexity": createPerplexity,
"@ai-sdk/vercel": createVercel,
"gitlab-ai-provider": createGitLab,
// @ts-ignore (TODO: kill this code so we dont have to maintain it)
"@ai-sdk/github-copilot": createGitHubCopilotOpenAICompatible,
}

Expand Down Expand Up @@ -591,7 +595,12 @@ export namespace Provider {

if (!result.models.length) {
log.info("gitlab model discovery skipped: no models found", {
project: result.project ? { id: result.project.id, path: result.project.pathWithNamespace } : null,
project: result.project
? {
id: result.project.id,
path: result.project.pathWithNamespace,
}
: null,
})
return {}
}
Expand Down Expand Up @@ -619,8 +628,20 @@ export namespace Provider {
reasoning: true,
attachment: true,
toolcall: true,
input: { text: true, audio: false, image: true, video: false, pdf: true },
output: { text: true, audio: false, image: false, video: false, pdf: false },
input: {
text: true,
audio: false,
image: true,
video: false,
pdf: true,
},
output: {
text: true,
audio: false,
image: false,
video: false,
pdf: false,
},
interleaved: false,
},
release_date: "",
Expand Down Expand Up @@ -930,17 +951,17 @@ export namespace Provider {
}

const providers: Record<ProviderID, Info> = {} as Record<ProviderID, Info>
const languages = new Map<string, LanguageModelV2>()
const languages = new Map<string, LanguageModelV3>()
const modelLoaders: {
[providerID: string]: CustomModelLoader
} = {}
const varsLoaders: {
[providerID: string]: CustomVarsLoader
} = {}
const sdk = new Map<string, BundledSDK>()
const discoveryLoaders: {
[providerID: string]: CustomDiscoverModels
} = {}
const sdk = new Map<string, SDK>()

log.info("init")

Expand Down Expand Up @@ -1232,7 +1253,13 @@ export namespace Provider {
...model.headers,
}

const key = Hash.fast(JSON.stringify({ providerID: model.providerID, npm: model.api.npm, options }))
const key = Hash.fast(
JSON.stringify({
providerID: model.providerID,
npm: model.api.npm,
options,
}),
)
const existing = s.sdk.get(key)
if (existing) return existing

Expand Down Expand Up @@ -1285,7 +1312,10 @@ export namespace Provider {

const bundledFn = BUNDLED_PROVIDERS[model.api.npm]
if (bundledFn) {
log.info("using bundled provider", { providerID: model.providerID, pkg: model.api.npm })
log.info("using bundled provider", {
providerID: model.providerID,
pkg: model.api.npm,
})
const loaded = bundledFn({
name: model.providerID,
...options,
Expand Down Expand Up @@ -1325,22 +1355,28 @@ export namespace Provider {
const provider = s.providers[providerID]
if (!provider) {
const availableProviders = Object.keys(s.providers)
const matches = fuzzysort.go(providerID, availableProviders, { limit: 3, threshold: -10000 })
const matches = fuzzysort.go(providerID, availableProviders, {
limit: 3,
threshold: -10000,
})
const suggestions = matches.map((m) => m.target)
throw new ModelNotFoundError({ providerID, modelID, suggestions })
}

const info = provider.models[modelID]
if (!info) {
const availableModels = Object.keys(provider.models)
const matches = fuzzysort.go(modelID, availableModels, { limit: 3, threshold: -10000 })
const matches = fuzzysort.go(modelID, availableModels, {
limit: 3,
threshold: -10000,
})
const suggestions = matches.map((m) => m.target)
throw new ModelNotFoundError({ providerID, modelID, suggestions })
}
return info
}

export async function getLanguage(model: Model): Promise<LanguageModelV2> {
export async function getLanguage(model: Model): Promise<LanguageModelV3> {
const s = await state()
const key = `${model.providerID}/${model.id}`
if (s.models.has(key)) return s.models.get(key)!
Expand All @@ -1350,7 +1386,10 @@ export namespace Provider {

try {
const language = s.modelLoaders[model.providerID]
? await s.modelLoaders[model.providerID](sdk, model.api.id, { ...provider.options, ...model.options })
? await s.modelLoaders[model.providerID](sdk, model.api.id, {
...provider.options,
...model.options,
})
: sdk.languageModel(model.api.id)
s.models.set(key, language)
return language
Expand Down Expand Up @@ -1457,9 +1496,9 @@ export namespace Provider {
if (cfg.model) return parseModel(cfg.model)

const providers = await list()
const recent = (await Filesystem.readJson<{ recent?: { providerID: ProviderID; modelID: ModelID }[] }>(
path.join(Global.Path.state, "model.json"),
)
const recent = (await Filesystem.readJson<{
recent?: { providerID: ProviderID; modelID: ModelID }[]
}>(path.join(Global.Path.state, "model.json"))
.then((x) => (Array.isArray(x.recent) ? x.recent : []))
.catch(() => [])) as { providerID: ProviderID; modelID: ModelID }[]
for (const entry of recent) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {
type LanguageModelV2Prompt,
type SharedV2ProviderMetadata,
type LanguageModelV3Prompt,
type SharedV3ProviderOptions,
UnsupportedFunctionalityError,
} from "@ai-sdk/provider"
import type { OpenAICompatibleChatPrompt } from "./openai-compatible-api-types"
import { convertToBase64 } from "@ai-sdk/provider-utils"

function getOpenAIMetadata(message: { providerOptions?: SharedV2ProviderMetadata }) {
function getOpenAIMetadata(message: { providerOptions?: SharedV3ProviderOptions }) {
return message?.providerOptions?.copilot ?? {}
}

export function convertToOpenAICompatibleChatMessages(prompt: LanguageModelV2Prompt): OpenAICompatibleChatPrompt {
export function convertToOpenAICompatibleChatMessages(prompt: LanguageModelV3Prompt): OpenAICompatibleChatPrompt {
const messages: OpenAICompatibleChatPrompt = []
for (const { role, content, ...message } of prompt) {
const metadata = getOpenAIMetadata({ ...message })
Expand Down Expand Up @@ -127,6 +127,9 @@ export function convertToOpenAICompatibleChatMessages(prompt: LanguageModelV2Pro

case "tool": {
for (const toolResponse of content) {
if (toolResponse.type === "tool-approval-response") {
continue
}
const output = toolResponse.output

let contentValue: string
Expand All @@ -135,6 +138,9 @@ export function convertToOpenAICompatibleChatMessages(prompt: LanguageModelV2Pro
case "error-text":
contentValue = output.value
break
case "execution-denied":
contentValue = output.reason ?? "Tool execution denied."
break
case "content":
case "json":
case "error-json":
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { LanguageModelV2FinishReason } from "@ai-sdk/provider"
import type { LanguageModelV3FinishReason } from "@ai-sdk/provider"

export function mapOpenAICompatibleFinishReason(finishReason: string | null | undefined): LanguageModelV2FinishReason {
export function mapOpenAICompatibleFinishReason(
finishReason: string | null | undefined,
): LanguageModelV3FinishReason["unified"] {
switch (finishReason) {
case "stop":
return "stop"
Expand All @@ -12,6 +14,6 @@ export function mapOpenAICompatibleFinishReason(finishReason: string | null | un
case "tool_calls":
return "tool-calls"
default:
return "unknown"
return "other"
}
}
Loading
Loading