fix(ai): packaged app crashes on open from @ai-sdk provider-utils split

v0.21.0 ships a TypeError at require time:
  (0, import_provider_utils6.createProviderToolFactoryWithOutputSchema)
  is not a function

Cause: PR #158 added @ai-sdk/xai, @ai-sdk/mistral, @ai-sdk/deepseek.
All three pull @ai-sdk/provider-utils@4, while core ai@5 is pinned to
@ai-sdk/provider-utils@3. pnpm hoisting + electron-builder's asar pack
pick the wrong version at runtime and the app refuses to open.

Fix: drop the three SDK packages. All three services expose
OpenAI-compatible endpoints, so route them through createOpenAI with
the matching base URL — same pattern GLM and Ollama already use. User-
facing provider list is unchanged.

Also extract the provider switch into ai-providers.ts so it can be
unit-tested without pulling in Electron, and:

- ai-providers.test.ts smoke-tests createProviderClient for every
  AIProvider. Catches any future require-time crash from an @ai-sdk
  package.
- ai-deps.test.ts walks node_modules/@ai-sdk and asserts every package
  agrees on the provider-utils major version. This is the invariant
  that #158 violated; the suite now fails fast if it breaks again.

CI guardrails:

- New ci.yml runs typecheck + tests on every push/PR to main. There
  was no PR check before, which is how #158 landed green.
- build.yml and build-artifacts.yml gate all platform builds behind
  a new `verify` job running the same checks, so a broken main can
  never produce a release artifact.
- Artifact workflow now uses --frozen-lockfile like the release one.
This commit is contained in:
Rohith Gilla 2026-04-20 14:14:22 +05:30
parent 40e7b446a8
commit 1d7183e648
No known key found for this signature in database
9 changed files with 397 additions and 172 deletions

View file

@ -15,7 +15,24 @@ on:
- linux
jobs:
# Gate every manual artifact build behind tests + typecheck. No more
# shipping a bad dep split into an artifact that ends up on someone's
# machine.
verify:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
- uses: pnpm/action-setup@v4
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @data-peek/desktop test
- run: pnpm --filter @data-peek/desktop typecheck
build-mac:
needs: verify
if: ${{ github.event.inputs.platform == 'all' || github.event.inputs.platform == 'mac' }}
runs-on: macos-latest
steps:
@ -31,7 +48,7 @@ jobs:
uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install
run: pnpm install --frozen-lockfile
- name: Build for macOS
working-directory: apps/desktop
@ -49,6 +66,7 @@ jobs:
if-no-files-found: error
build-windows:
needs: verify
if: ${{ github.event.inputs.platform == 'all' || github.event.inputs.platform == 'windows' }}
runs-on: windows-latest
steps:
@ -64,7 +82,7 @@ jobs:
uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install
run: pnpm install --frozen-lockfile
- name: Build for Windows
working-directory: apps/desktop
@ -81,6 +99,7 @@ jobs:
if-no-files-found: error
build-linux:
needs: verify
if: ${{ github.event.inputs.platform == 'all' || github.event.inputs.platform == 'linux' }}
runs-on: ubuntu-latest
steps:
@ -96,7 +115,7 @@ jobs:
uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install
run: pnpm install --frozen-lockfile
- name: Build for Linux
working-directory: apps/desktop

View file

@ -10,7 +10,48 @@ permissions:
contents: write
jobs:
# Fast verification gate. Platform builds don't start until this passes,
# so we don't burn 30min on three macOS/Windows/Linux runners just to
# ship a broken release. This is what would have caught v0.21.0.
verify:
name: verify (typecheck · test)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 24
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Get pnpm store directory
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache
uses: actions/cache@v4
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run desktop tests
run: pnpm --filter @data-peek/desktop test
- name: Typecheck desktop
run: pnpm --filter @data-peek/desktop typecheck
build-mac:
needs: verify
runs-on: macos-latest
steps:
- name: Checkout
@ -22,7 +63,7 @@ jobs:
node-version: 24
- name: Setup pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v4
- name: Get pnpm store directory
shell: bash
@ -86,6 +127,7 @@ jobs:
if-no-files-found: error
build-windows:
needs: verify
runs-on: windows-latest
steps:
- name: Checkout
@ -132,6 +174,7 @@ jobs:
if-no-files-found: error
build-linux:
needs: verify
runs-on: ubuntu-latest
steps:
- name: Checkout

57
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,57 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
# Cancel in-progress CI runs on the same branch when a new commit lands —
# the most recent commit is the only one whose result matters.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
verify:
name: typecheck · test · lint
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 24
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Get pnpm store directory
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache
uses: actions/cache@v4
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
# --frozen-lockfile ensures package.json and pnpm-lock.yaml agree —
# this alone catches half of the "works on my machine" class of bug.
- name: Install dependencies
run: pnpm install --frozen-lockfile
# The dependency-consistency test (src/main/__tests__/ai-deps.test.ts)
# runs here. If two @ai-sdk/* packages resolve conflicting
# provider-utils majors, the suite fails before any build happens.
- name: Run desktop tests
run: pnpm --filter @data-peek/desktop test
- name: Typecheck desktop
run: pnpm --filter @data-peek/desktop typecheck

View file

@ -25,12 +25,9 @@
},
"dependencies": {
"@ai-sdk/anthropic": "^2.0.17",
"@ai-sdk/deepseek": "^2.0.29",
"@ai-sdk/google": "^2.0.12",
"@ai-sdk/groq": "^2.0.8",
"@ai-sdk/mistral": "^3.0.30",
"@ai-sdk/openai": "^2.0.24",
"@ai-sdk/xai": "^3.0.82",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",

View file

@ -0,0 +1,126 @@
/**
* AI SDK dependency consistency guard.
*
* The @ai-sdk/* packages all depend on @ai-sdk/provider-utils. If two
* installed @ai-sdk packages resolve different major versions of
* provider-utils, Electron's asar packaging can pick the wrong one at
* runtime and the app crashes with errors like:
*
* TypeError: (0 , import_provider_utils6.createProviderToolFactoryWithOutputSchema)
* is not a function
*
* This is exactly what shipped in v0.21.0 when @ai-sdk/xai (needing
* provider-utils@4) was installed alongside ai@5 (pinned to
* provider-utils@3). This test fails fast in CI if the same split
* recurs before anyone packages a release.
*
* The check runs against the real on-disk node_modules rather than a
* parsed lockfile so it keeps working regardless of pnpm's hoisting
* strategy.
*/
import fs from 'fs'
import path from 'path'
import { describe, expect, it } from 'vitest'
interface PackageJson {
name?: string
version?: string
dependencies?: Record<string, string>
peerDependencies?: Record<string, string>
}
function readPackageJson(pkgDir: string): PackageJson | null {
const file = path.join(pkgDir, 'package.json')
if (!fs.existsSync(file)) return null
try {
return JSON.parse(fs.readFileSync(file, 'utf8')) as PackageJson
} catch {
return null
}
}
// node_modules is hoisted at the monorepo root.
const REPO_ROOT = path.resolve(__dirname, '../../../../../')
const AI_SDK_DIR = path.join(REPO_ROOT, 'node_modules/@ai-sdk')
function collectProviderUtilsRequirements(): Array<{
package: string
version: string
requires: string
}> {
if (!fs.existsSync(AI_SDK_DIR)) return []
const entries = fs.readdirSync(AI_SDK_DIR, { withFileTypes: true })
const results: Array<{ package: string; version: string; requires: string }> = []
for (const entry of entries) {
if (!entry.isDirectory()) continue
if (entry.name === 'provider-utils' || entry.name === 'provider') continue
const pkg = readPackageJson(path.join(AI_SDK_DIR, entry.name))
if (!pkg) continue
const requires = pkg.dependencies?.['@ai-sdk/provider-utils']
if (!requires) continue
results.push({
package: `@ai-sdk/${entry.name}`,
version: pkg.version ?? 'unknown',
requires
})
}
return results
}
function majorOf(range: string): string {
// Strip leading ^ ~ >= <= =, take everything up to the first dot.
const cleaned = range.replace(/^[^\d]*/, '')
return cleaned.split('.')[0] ?? range
}
describe('@ai-sdk dependency consistency', () => {
it('all @ai-sdk/* packages agree on the major version of provider-utils', () => {
const requirements = collectProviderUtilsRequirements()
expect(requirements.length).toBeGreaterThan(0)
const majors = new Map<string, Array<{ package: string; version: string; requires: string }>>()
for (const r of requirements) {
const major = majorOf(r.requires)
if (!majors.has(major)) majors.set(major, [])
majors.get(major)!.push(r)
}
if (majors.size > 1) {
const summary = [...majors.entries()]
.map(
([major, pkgs]) =>
` provider-utils@${major}.x (${pkgs.length}):\n` +
pkgs.map((p) => ` - ${p.package}@${p.version} needs ${p.requires}`).join('\n')
)
.join('\n')
throw new Error(
`Multiple major versions of @ai-sdk/provider-utils are installed.\n` +
`This crashes the packaged Electron app at require-time.\n` +
`Either downgrade the offending package or remove it:\n\n${summary}\n`
)
}
expect(majors.size).toBe(1)
})
it('the resolved ai package pins a provider-utils version and matches', () => {
const aiPkg = readPackageJson(path.join(REPO_ROOT, 'node_modules/ai'))
expect(aiPkg).toBeTruthy()
const aiRequires = aiPkg!.dependencies?.['@ai-sdk/provider-utils']
expect(aiRequires).toBeTruthy()
const requirements = collectProviderUtilsRequirements()
for (const r of requirements) {
expect(
majorOf(r.requires),
`${r.package}@${r.version} requires provider-utils ${r.requires}, but ai requires ${aiRequires}`
).toBe(majorOf(aiRequires!))
}
})
})

View file

@ -0,0 +1,53 @@
/**
* AI provider factory smoke test.
*
* Exercises createProviderClient for every declared AIProvider.
* Catches the class of bug where an @ai-sdk/* package throws at
* require-time (e.g. missing export in a transitive dependency)
* this is what blew up v0.21.0 when @ai-sdk/xai was installed against
* a provider-utils version that lacked createProviderToolFactoryWithOutputSchema.
*
* If you add a provider to AIProvider in packages/shared, the
* "covers every AIProvider" assertion below will fail until the switch
* in ai-providers.ts is extended.
*/
import { describe, expect, it } from 'vitest'
import { AI_PROVIDERS, type AIConfig, type AIProvider } from '@shared/index'
import { createProviderClient } from '../ai-providers'
function configFor(provider: AIProvider): AIConfig {
return {
provider,
apiKey: 'test-key-not-used',
model: provider === 'ollama' ? 'llama3' : 'test-model',
baseUrl: undefined
}
}
describe('createProviderClient', () => {
for (const info of AI_PROVIDERS) {
it(`instantiates ${info.id} without throwing`, () => {
const model = createProviderClient(configFor(info.id))
expect(model).toBeTruthy()
})
}
it('covers every AIProvider enumerated in AI_PROVIDERS', () => {
// If someone adds a provider to the shared union but forgets to
// extend AI_PROVIDERS or the switch, at least one of these explodes.
for (const info of AI_PROVIDERS) {
expect(() => createProviderClient(configFor(info.id))).not.toThrow()
}
})
it('throws on an unknown provider (defensive)', () => {
expect(() =>
createProviderClient({
provider: 'definitely-not-a-provider' as AIProvider,
apiKey: 'x',
model: 'y'
})
).toThrow()
})
})

View file

@ -0,0 +1,90 @@
/**
* AI Provider Factory Pure Module
*
* Instantiates AI SDK clients for every supported provider. Kept free of
* Electron imports so it can be unit-tested in plain node.
*
* If you add a provider here, extend the AIProvider type in
* packages/shared, and the ai-providers.test.ts suite will fail until
* the switch is complete.
*
* We deliberately avoid @ai-sdk/deepseek, @ai-sdk/mistral, and
* @ai-sdk/xai: all three currently depend on @ai-sdk/provider-utils@4
* while the core `ai` package is on provider-utils@3, which crashes
* the packaged app at require-time. See ai-deps.test.ts.
*/
import { createOpenAI } from '@ai-sdk/openai'
import { createAnthropic } from '@ai-sdk/anthropic'
import { createGoogleGenerativeAI } from '@ai-sdk/google'
import { createGroq } from '@ai-sdk/groq'
import type { AIConfig } from '@shared/index'
export function createProviderClient(config: AIConfig) {
switch (config.provider) {
case 'openai': {
const openai = createOpenAI({ apiKey: config.apiKey, baseURL: config.baseUrl })
return openai(config.model)
}
case 'anthropic': {
const anthropic = createAnthropic({ apiKey: config.apiKey, baseURL: config.baseUrl })
return anthropic(config.model)
}
case 'google': {
const google = createGoogleGenerativeAI({ apiKey: config.apiKey, baseURL: config.baseUrl })
return google(config.model)
}
case 'groq': {
const groq = createGroq({ apiKey: config.apiKey, baseURL: config.baseUrl })
return groq(config.model)
}
case 'deepseek': {
const deepseek = createOpenAI({
apiKey: config.apiKey,
baseURL: config.baseUrl || 'https://api.deepseek.com/v1'
})
return deepseek(config.model)
}
case 'mistral': {
const mistral = createOpenAI({
apiKey: config.apiKey,
baseURL: config.baseUrl || 'https://api.mistral.ai/v1'
})
return mistral(config.model)
}
case 'xai': {
const xai = createOpenAI({
apiKey: config.apiKey,
baseURL: config.baseUrl || 'https://api.x.ai/v1'
})
return xai(config.model)
}
case 'glm': {
const glm = createOpenAI({
apiKey: config.apiKey,
baseURL: config.baseUrl || 'https://open.bigmodel.cn/api/paas/v4'
})
return glm(config.model)
}
case 'ollama': {
const ollama = createOpenAI({
baseURL: config.baseUrl || 'http://localhost:11434/v1',
apiKey: 'ollama'
})
return ollama(config.model)
}
default: {
const _exhaustive: never = config.provider
throw new Error(`Unknown provider: ${String(_exhaustive)}`)
}
}
}

View file

@ -5,14 +5,8 @@
* Uses AI SDK's generateObject for typed JSON output.
*/
import { createOpenAI } from '@ai-sdk/openai'
import { createAnthropic } from '@ai-sdk/anthropic'
import { createGoogleGenerativeAI } from '@ai-sdk/google'
import { createGroq } from '@ai-sdk/groq'
import { createDeepSeek } from '@ai-sdk/deepseek'
import { createMistral } from '@ai-sdk/mistral'
import { createXai } from '@ai-sdk/xai'
import { generateObject, generateText } from 'ai'
import { createProviderClient } from './ai-providers'
import { z } from 'zod'
import type {
SchemaInfo,
@ -292,87 +286,12 @@ export function clearAIConfig(): void {
}
/**
* Get the AI model instance based on provider
* Get the AI model instance based on provider.
* Thin wrapper around the pure factory in ai-providers.ts (kept as a
* separate module so it can be unit-tested without Electron).
*/
function getModel(config: AIConfig) {
switch (config.provider) {
case 'openai': {
const openai = createOpenAI({
apiKey: config.apiKey,
baseURL: config.baseUrl
})
return openai(config.model)
}
case 'anthropic': {
const anthropic = createAnthropic({
apiKey: config.apiKey,
baseURL: config.baseUrl
})
return anthropic(config.model)
}
case 'google': {
const google = createGoogleGenerativeAI({
apiKey: config.apiKey,
baseURL: config.baseUrl
})
return google(config.model)
}
case 'groq': {
const groq = createGroq({
apiKey: config.apiKey,
baseURL: config.baseUrl
})
return groq(config.model)
}
case 'deepseek': {
const deepseek = createDeepSeek({
apiKey: config.apiKey,
baseURL: config.baseUrl
})
return deepseek(config.model)
}
case 'mistral': {
const mistral = createMistral({
apiKey: config.apiKey,
baseURL: config.baseUrl
})
return mistral(config.model)
}
case 'xai': {
const xai = createXai({
apiKey: config.apiKey,
baseURL: config.baseUrl
})
return xai(config.model)
}
case 'glm': {
// GLM (Zhipu AI) uses OpenAI-compatible API
const glm = createOpenAI({
apiKey: config.apiKey,
baseURL: config.baseUrl || 'https://open.bigmodel.cn/api/paas/v4'
})
return glm(config.model)
}
case 'ollama': {
// Ollama uses OpenAI-compatible API
const ollama = createOpenAI({
baseURL: config.baseUrl || 'http://localhost:11434/v1',
apiKey: 'ollama' // Ollama doesn't need a real key
})
return ollama(config.model)
}
default:
throw new Error(`Unknown provider: ${config.provider}`)
}
return createProviderClient(config)
}
/**

View file

@ -33,24 +33,15 @@ importers:
'@ai-sdk/anthropic':
specifier: ^2.0.17
version: 2.0.50(zod@3.25.76)
'@ai-sdk/deepseek':
specifier: ^2.0.29
version: 2.0.29(zod@3.25.76)
'@ai-sdk/google':
specifier: ^2.0.12
version: 2.0.44(zod@3.25.76)
'@ai-sdk/groq':
specifier: ^2.0.8
version: 2.0.32(zod@3.25.76)
'@ai-sdk/mistral':
specifier: ^3.0.30
version: 3.0.30(zod@3.25.76)
'@ai-sdk/openai':
specifier: ^2.0.24
version: 2.0.74(zod@3.25.76)
'@ai-sdk/xai':
specifier: ^3.0.82
version: 3.0.82(zod@3.25.76)
'@dnd-kit/core':
specifier: ^6.3.1
version: 6.3.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@ -794,12 +785,6 @@ packages:
peerDependencies:
zod: ^3.25.76 || ^4.1.8
'@ai-sdk/deepseek@2.0.29':
resolution: {integrity: sha512-cn4+xV0menm/4JKEDElnVGiUilHvi6AD4ZK/sY7DXP/Wb7Yb3Vr86NyYM6mGBE/Shk3mWHoHbzggVnF5x0uMEA==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.76 || ^4.1.8
'@ai-sdk/gateway@2.0.17':
resolution: {integrity: sha512-oVAG6q72KsjKlrYdLhWjRO7rcqAR8CjokAbYuyVZoCO4Uh2PH/VzZoxZav71w2ipwlXhHCNaInGYWNs889MMDA==}
engines: {node: '>=18'}
@ -818,18 +803,6 @@ packages:
peerDependencies:
zod: ^3.25.76 || ^4.1.8
'@ai-sdk/mistral@3.0.30':
resolution: {integrity: sha512-+j4IXRSk9E661cFSafmIr+XHOzwjFagawwzMOlSqwL6U4Sq4PCFLDF+oHbX5NUqNjUL7FD1zi/9lBIfa41pUvw==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.76 || ^4.1.8
'@ai-sdk/openai-compatible@2.0.41':
resolution: {integrity: sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.76 || ^4.1.8
'@ai-sdk/openai@2.0.74':
resolution: {integrity: sha512-vvsL7rGoBEyQIePs630p31ebLeF+xxwLOrRKeIArHko8w7Wh9Kj3wL4Ns+PCzrEpAij31OKKDcxLQ1dSIg/qMw==}
engines: {node: '>=18'}
@ -842,26 +815,10 @@ packages:
peerDependencies:
zod: ^3.25.76 || ^4.1.8
'@ai-sdk/provider-utils@4.0.23':
resolution: {integrity: sha512-z8GlDaCmRSDlqkMF2f4/RFgWxdarvIbyuk+m6WXT1LYgsnGiXRJGTD2Z1+SDl3LqtFuRtGX1aghYvQLoHL/9pg==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.76 || ^4.1.8
'@ai-sdk/provider@2.0.0':
resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==}
engines: {node: '>=18'}
'@ai-sdk/provider@3.0.8':
resolution: {integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==}
engines: {node: '>=18'}
'@ai-sdk/xai@3.0.82':
resolution: {integrity: sha512-A0VFMufnVf4wODcT3SPQUUzvYXiIO1VhFuXj9r6z/vP4rlo+QRDPw3WSTchcz93ROQWSfBE3I6Szqz342OHi5w==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.76 || ^4.1.8
'@alloc/quick-lru@5.2.0':
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
@ -10619,12 +10576,6 @@ snapshots:
'@ai-sdk/provider-utils': 3.0.18(zod@3.25.76)
zod: 3.25.76
'@ai-sdk/deepseek@2.0.29(zod@3.25.76)':
dependencies:
'@ai-sdk/provider': 3.0.8
'@ai-sdk/provider-utils': 4.0.23(zod@3.25.76)
zod: 3.25.76
'@ai-sdk/gateway@2.0.17(zod@3.25.76)':
dependencies:
'@ai-sdk/provider': 2.0.0
@ -10644,18 +10595,6 @@ snapshots:
'@ai-sdk/provider-utils': 3.0.18(zod@3.25.76)
zod: 3.25.76
'@ai-sdk/mistral@3.0.30(zod@3.25.76)':
dependencies:
'@ai-sdk/provider': 3.0.8
'@ai-sdk/provider-utils': 4.0.23(zod@3.25.76)
zod: 3.25.76
'@ai-sdk/openai-compatible@2.0.41(zod@3.25.76)':
dependencies:
'@ai-sdk/provider': 3.0.8
'@ai-sdk/provider-utils': 4.0.23(zod@3.25.76)
zod: 3.25.76
'@ai-sdk/openai@2.0.74(zod@3.25.76)':
dependencies:
'@ai-sdk/provider': 2.0.0
@ -10669,28 +10608,10 @@ snapshots:
eventsource-parser: 3.0.6
zod: 3.25.76
'@ai-sdk/provider-utils@4.0.23(zod@3.25.76)':
dependencies:
'@ai-sdk/provider': 3.0.8
'@standard-schema/spec': 1.1.0
eventsource-parser: 3.0.6
zod: 3.25.76
'@ai-sdk/provider@2.0.0':
dependencies:
json-schema: 0.4.0
'@ai-sdk/provider@3.0.8':
dependencies:
json-schema: 0.4.0
'@ai-sdk/xai@3.0.82(zod@3.25.76)':
dependencies:
'@ai-sdk/openai-compatible': 2.0.41(zod@3.25.76)
'@ai-sdk/provider': 3.0.8
'@ai-sdk/provider-utils': 4.0.23(zod@3.25.76)
zod: 3.25.76
'@alloc/quick-lru@5.2.0': {}
'@azure-rest/core-client@2.5.1':