From cb4d72abfcb343a8e2964bf881285d9ff3390f5f Mon Sep 17 00:00:00 2001 From: Seth Raphael Date: Sun, 25 Jan 2026 21:13:34 -0800 Subject: [PATCH 1/4] Add compile-time errors for AI SDK v5 patterns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When users upgrade to v0.6.0 with old AI SDK v5 dependencies, TypeScript now shows helpful error messages pointing to the migration guide: - languageModel: Shows error if model has specificationVersion "v2" instead of "v3" - createTool args: Shows "⚠️ 'args' was removed... Rename to 'inputSchema'" - createTool handler: Shows "⚠️ 'handler' was removed... Rename to 'execute'" This helps users (and AI assistants) understand what needs to change before they try to run the code. Also adds scripts/check-upgrade.js CLI tool for scanning codebases. Co-Authored-By: Claude Opus 4.5 --- package.json | 6 +- scripts/check-upgrade.js | 140 +++++++++++++++++++++++++++++++++++++++ src/client/createTool.ts | 100 ++++++++++++++-------------- src/client/types.ts | 26 ++++---- 4 files changed, 208 insertions(+), 64 deletions(-) create mode 100755 scripts/check-upgrade.js diff --git a/package.json b/package.json index f90ff564..cd39d93a 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,13 @@ "release": "npm version patch && npm publish && git push --follow-tags", "version": "vim -c 'normal o' -c 'normal o## '$npm_package_version CHANGELOG.md && prettier -w CHANGELOG.md && git add CHANGELOG.md" }, + "bin": { + "convex-agent-upgrade-check": "./scripts/check-upgrade.js" + }, "files": [ "dist", - "src" + "src", + "scripts" ], "exports": { "./package.json": "./package.json", diff --git a/scripts/check-upgrade.js b/scripts/check-upgrade.js new file mode 100755 index 00000000..eb85cddf --- /dev/null +++ b/scripts/check-upgrade.js @@ -0,0 +1,140 @@ +#!/usr/bin/env node + +/** + * Pre-typecheck script that detects AI SDK v5 patterns and provides + * helpful upgrade instructions before TypeScript errors confuse users. + * + * Run with: node scripts/check-upgrade.js [directory] + */ + +import { readFileSync, readdirSync, statSync } from 'fs'; +import { join, relative } from 'path'; + +const V5_PATTERNS = [ + { + pattern: /LanguageModelV2/g, + message: 'LanguageModelV2 → LanguageModelV3', + fix: "Change 'LanguageModelV2' to 'LanguageModelV3' (or just use 'LanguageModel' from 'ai')", + }, + { + pattern: /EmbeddingModel\s*<\s*string\s*>/g, + message: 'EmbeddingModel → EmbeddingModel', + fix: "Remove the generic parameter: 'EmbeddingModel' → 'EmbeddingModel'", + }, + { + pattern: /textEmbeddingModel\s*:/g, + message: 'textEmbeddingModel → embeddingModel', + fix: "Rename 'textEmbeddingModel' to 'embeddingModel' in your Agent config", + }, + { + pattern: /createTool\(\s*\{[^}]*\bargs\s*:/gs, + message: 'createTool args → inputSchema', + fix: "In createTool(), rename 'args' to 'inputSchema'", + }, + { + pattern: /\bhandler\s*:\s*async\s*\(/g, + message: 'createTool handler → execute', + fix: "In createTool(), rename 'handler' to 'execute' and update signature: execute: async (ctx, input, options)", + }, + { + pattern: /@ai-sdk\/provider['"];\s*$/gm, + message: '@ai-sdk/provider v2 types', + fix: "Update @ai-sdk/* packages to v3.x: npm install @ai-sdk/openai@^3.0.10", + filePattern: /\.(ts|tsx)$/, + }, +]; + +function findFiles(dir, extensions = ['.ts', '.tsx']) { + const files = []; + + function walk(currentDir) { + try { + const entries = readdirSync(currentDir); + for (const entry of entries) { + if (entry === 'node_modules' || entry === '_generated' || entry.startsWith('.')) { + continue; + } + const fullPath = join(currentDir, entry); + const stat = statSync(fullPath); + if (stat.isDirectory()) { + walk(fullPath); + } else if (extensions.some(ext => entry.endsWith(ext))) { + files.push(fullPath); + } + } + } catch (e) { + // Skip directories we can't read + } + } + + walk(dir); + return files; +} + +function checkFile(filePath, baseDir) { + const content = readFileSync(filePath, 'utf-8'); + const issues = []; + + for (const { pattern, message, fix, filePattern } of V5_PATTERNS) { + if (filePattern && !filePattern.test(filePath)) { + continue; + } + + // Reset regex state + pattern.lastIndex = 0; + + let match; + while ((match = pattern.exec(content)) !== null) { + const lines = content.slice(0, match.index).split('\n'); + const line = lines.length; + const col = lines[lines.length - 1].length + 1; + + issues.push({ + file: relative(baseDir, filePath), + line, + col, + message, + fix, + match: match[0].slice(0, 50), + }); + } + } + + return issues; +} + +function main() { + const targetDir = process.argv[2] || process.cwd(); + const files = findFiles(targetDir); + const allIssues = []; + + for (const file of files) { + const issues = checkFile(file, targetDir); + allIssues.push(...issues); + } + + if (allIssues.length === 0) { + console.log('✅ No AI SDK v5 patterns detected. Ready for v6!'); + process.exit(0); + } + + console.error('\n' + '='.repeat(70)); + console.error('⚠️ AI SDK v5 → v6 UPGRADE REQUIRED'); + console.error('='.repeat(70)); + console.error('\nFound', allIssues.length, 'pattern(s) that need updating:\n'); + + for (const issue of allIssues) { + console.error(`📍 ${issue.file}:${issue.line}:${issue.col}`); + console.error(` ${issue.message}`); + console.error(` Fix: ${issue.fix}`); + console.error(''); + } + + console.error('='.repeat(70)); + console.error('📚 Full upgrade guide: https://github.com/get-convex/agent/blob/main/MIGRATION.md'); + console.error('='.repeat(70) + '\n'); + + process.exit(1); +} + +main(); diff --git a/src/client/createTool.ts b/src/client/createTool.ts index eb42d15b..e263d8e0 100644 --- a/src/client/createTool.ts +++ b/src/client/createTool.ts @@ -72,60 +72,57 @@ type NeverOptional = 0 extends 1 & N ? Partial> : T; +/** + * Error message type for deprecated 'handler' property. + * Using a string literal type causes TypeScript to show this message in errors. + */ +type HANDLER_REMOVED_ERROR = + "⚠️ 'handler' was removed in @convex-dev/agent v0.6.0. Rename to 'execute'. See: https://github.com/get-convex/agent/blob/main/MIGRATION.md"; + export type ToolOutputPropertiesCtx< INPUT, OUTPUT, Ctx extends ToolCtx = ToolCtx, > = NeverOptional< OUTPUT, - | { - /** - * An async function that is called with the arguments from the tool call and produces a result. - * If `execute` (or `handler`) is not provided, the tool will not be executed automatically. - * - * @param input - The input of the tool call. - * @param options.abortSignal - A signal that can be used to abort the tool call. - */ - execute: ToolExecuteFunctionCtx; - outputSchema?: FlexibleSchema; - handler?: never; - } - | { - /** @deprecated Use execute instead. */ - handler: ToolExecuteFunctionCtx; - outputSchema?: FlexibleSchema; - execute?: never; - } - | { - outputSchema: FlexibleSchema; - execute?: never; - handler?: never; - } + { + /** + * An async function that is called with the arguments from the tool call and produces a result. + * If `execute` is not provided, the tool will not be executed automatically. + * + * @param input - The input of the tool call. + * @param options.abortSignal - A signal that can be used to abort the tool call. + */ + execute?: ToolExecuteFunctionCtx; + outputSchema?: FlexibleSchema; + /** + * @deprecated Removed in v0.6.0. Use `execute` instead. + */ + handler?: HANDLER_REMOVED_ERROR; + } >; -export type ToolInputProperties = - | { - /** - * The schema of the input that the tool expects. - * The language model will use this to generate the input. - * It is also used to validate the output of the language model. - * - * You can use descriptions on the schema properties to make the input understandable for the language model. - */ - inputSchema: FlexibleSchema; - args?: never; - } - | { - /** - * The schema of the input that the tool expects. The language model will use this to generate the input. - * It is also used to validate the output of the language model. - * Use descriptions to make the input understandable for the language model. - * - * @deprecated Use inputSchema instead. - */ - args: FlexibleSchema; - inputSchema?: never; - }; +/** + * Error message type for deprecated 'args' property. + * Using a string literal type causes TypeScript to show this message in errors. + */ +type ARGS_REMOVED_ERROR = + "⚠️ 'args' was removed in @convex-dev/agent v0.6.0. Rename to 'inputSchema'. See: https://github.com/get-convex/agent/blob/main/MIGRATION.md"; + +export type ToolInputProperties = { + /** + * The schema of the input that the tool expects. + * The language model will use this to generate the input. + * It is also used to validate the output of the language model. + * + * You can use descriptions on the schema properties to make the input understandable for the language model. + */ + inputSchema: FlexibleSchema; + /** + * @deprecated Removed in v0.6.0. Use `inputSchema` instead. + */ + args?: ARGS_REMOVED_ERROR; +}; /** * This is a wrapper around the ai.tool function that adds extra context to the @@ -238,24 +235,25 @@ export function createTool( ) => ToolResultOutput | PromiseLike; }, ): Tool { - const inputSchema = def.inputSchema ?? def.args; + // Runtime backwards compat - types will show errors but runtime still works + const inputSchema = def.inputSchema ?? (def as any).args; if (!inputSchema) - throw new Error("To use a Convex tool, you must provide an `inputSchema` (or `args`)"); + throw new Error("To use a Convex tool, you must provide an `inputSchema`"); - if (def.args && !def.inputSchema) { + if ((def as any).args && !def.inputSchema) { warnDeprecation( "createTool.args", "createTool: 'args' is deprecated. Use 'inputSchema' instead.", ); } - if (def.handler && !def.execute) { + if ((def as any).handler && !def.execute) { warnDeprecation( "createTool.handler", "createTool: 'handler' is deprecated. Use 'execute' instead.", ); } - const executeHandler = def.execute ?? def.handler; + const executeHandler = def.execute ?? (def as any).handler; if (!executeHandler && !def.outputSchema) throw new Error( "To use a Convex tool, you must either provide an execute" + diff --git a/src/client/types.ts b/src/client/types.ts index 2533d029..8ce2c472 100644 --- a/src/client/types.ts +++ b/src/client/types.ts @@ -46,6 +46,14 @@ import type { import type { StreamingOptions } from "./streaming.js"; import type { ComponentApi } from "../component/_generated/component.js"; +/** + * Type-level check that ensures models are from AI SDK v6. + * If a v5 model (LanguageModelV2) is passed, TypeScript will show the error message string. + */ +type AssertAISDKv6 = T extends { specificationVersion: "v3" } + ? T + : "⚠️ @convex-dev/agent v0.6.0 requires AI SDK v6. Update your dependencies: npm install ai@^6.0.35 @ai-sdk/openai@^3.0.10 (or other provider). See: https://github.com/get-convex/agent/blob/main/MIGRATION.md"; + export type AgentPrompt = { /** * System message to include in the prompt. Overwrites Agent instructions. @@ -91,23 +99,17 @@ export type AgentPrompt = { export type Config = { /** * The LLM model to use for generating / streaming text and objects. - * e.g. + * Requires AI SDK v6 (@ai-sdk/* packages v3.x). + * + * @example * import { openai } from "@ai-sdk/openai" * const myAgent = new Agent(components.agent, { * languageModel: openai.chat("gpt-4o-mini"), + * }) */ - languageModel?: LanguageModel; + languageModel?: AssertAISDKv6; /** - * The model to use for text embeddings. Optional. - * If specified, it will use this for generating vector embeddings - * of chats, and can opt-in to doing vector search for automatic context - * on generateText, etc. - * e.g. - * import { openai } from "@ai-sdk/openai" - * const myAgent = new Agent(components.agent, { - * ... - * textEmbeddingModel: openai.embedding("text-embedding-3-small") - * @deprecated — Use embeddingModel instead. + * @deprecated Use `embeddingModel` instead. */ textEmbeddingModel?: EmbeddingModel; /** From 3f8de08ee3055a28bded19ed23a2427b80c51248 Mon Sep 17 00:00:00 2001 From: Seth Raphael Date: Sun, 25 Jan 2026 21:32:45 -0800 Subject: [PATCH 2/4] Include MIGRATION.md in npm package and update error references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add MIGRATION.md to package.json files array so it ships with npm package - Update compile-time error messages to point to local MIGRATION.md - Enhance CLAUDE.md with: - AI SDK v6 requirement note upfront - Compatible sibling packages (@convex-dev/rag@^0.7.0) - Type import changes (LanguageModelV2 → V3, EmbeddingModel → EmbeddingModelV3) - generateObject mode: "json" removal documentation Co-Authored-By: Claude Opus 4.5 --- CLAUDE.md | 117 +++++++++++++++++++++++++++++---------- package.json | 3 +- src/client/createTool.ts | 6 +- src/client/index.ts | 2 +- src/client/types.ts | 2 +- 5 files changed, 94 insertions(+), 36 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 19fa3569..ab8dfbd4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -59,6 +59,7 @@ npm run typecheck # Full TypeScript validation including example/convex - **Message-centric design** - All operations revolve around message persistence/retrieval - **Component-based encapsulation** - Uses Convex Components pattern - **Multi-user support** - Threads have optional `userId` for ownership +- **Tool approval flow** - Tools can require human approval via `needsApproval`, with `agent.approveToolCall()` and `agent.denyToolCall()` methods ### Database Tables (Convex Component) @@ -87,82 +88,138 @@ Follow the rules in `.cursor/rules/convex_rules.mdc`: - `@convex-dev/agent/validators` - Convex validators for integration - `@convex-dev/agent/test` - Testing utilities -## Upgrading to v0.6.0 (AI SDK v6) +## AI Guidance: Helping Users Upgrade to v0.6.0 -When helping users upgrade from @convex-dev/agent v0.3.x to v0.6.0, follow these steps: +**IMPORTANT: v0.6.0 requires AI SDK v6 (ai@^6.0.0)** -### Step 1: Update dependencies in package.json +When helping users upgrade from @convex-dev/agent v0.3.x (AI SDK v5) to v0.6.0 (AI SDK v6): + +### Step 1: Update Dependencies First + +Update all AI SDK packages together to avoid peer dependency conflicts: ```bash npm install @convex-dev/agent@^0.6.0 ai@^6.0.35 @ai-sdk/provider-utils@^4.0.6 +npm install @ai-sdk/openai@^3.0.10 # or whichever provider ``` -Also update any AI SDK provider packages: -```bash -npm install @ai-sdk/openai@^3.0.10 @ai-sdk/anthropic@^3.0.13 -``` +**Compatible sibling packages:** +- `@convex-dev/rag@^0.7.0` (v0.6.0 has type conflicts with AI SDK v6) +- `@convex-dev/workflow@^0.3.2` + +### Step 2: Detect v5 Patterns -### Step 2: Update tool definitions +Search for these patterns indicating v5 usage: +- `createTool({ args:` - should be `inputSchema` +- `createTool({ handler:` - should be `execute` +- `textEmbeddingModel:` - should be `embeddingModel` +- `maxSteps:` in generateText/streamText - should be `stopWhen: stepCountIs(N)` +- `mode: "json"` in generateObject - removed in v6 +- `@ai-sdk/*` packages at v1.x or v2.x - should be v3.x +- Type imports: `LanguageModelV2` → `LanguageModelV3`, `EmbeddingModel` → `EmbeddingModelV3` -Replace `parameters` with `inputSchema`: +### Step 3: Apply Transformations +**Tool definitions:** ```typescript -// Before (v5) +// BEFORE (v5) const myTool = createTool({ description: "...", parameters: z.object({ query: z.string() }), - execute: async (ctx, args) => { ... } + handler: async (ctx, args) => { + return args.query.toUpperCase(); + } }) -// After (v6) +// AFTER (v6) const myTool = createTool({ description: "...", inputSchema: z.object({ query: z.string() }), - execute: async (ctx, input, options) => { ... } + execute: async (ctx, input, options) => { + return input.query.toUpperCase(); + } }) ``` -### Step 3: Update maxSteps usage (if applicable) +**Agent embedding config:** +```typescript +// BEFORE +new Agent(components.agent, { + textEmbeddingModel: openai.embedding("text-embedding-3-small") +}) + +// AFTER +new Agent(components.agent, { + embeddingModel: openai.embedding("text-embedding-3-small") +}) +``` +**Step limits:** ```typescript -// Before (v5) +// BEFORE await agent.generateText(ctx, { threadId }, { prompt: "...", maxSteps: 5 }) -// After (v6) - maxSteps still works but stopWhen is preferred -import { stepCountIs } from "ai" +// AFTER +import { stepCountIs } from "@convex-dev/agent" await agent.generateText(ctx, { threadId }, { prompt: "...", stopWhen: stepCountIs(5) }) ``` -### Step 4: Update embedding model config (optional) +**Type imports:** +```typescript +// BEFORE (v5) +import type { LanguageModelV2 } from "@ai-sdk/provider"; +import type { EmbeddingModel } from "ai"; +let model: LanguageModelV2; +let embedder: EmbeddingModel; + +// AFTER (v6) +import type { LanguageModelV3, EmbeddingModelV3 } from "@ai-sdk/provider"; +let model: LanguageModelV3; +let embedder: EmbeddingModelV3; +``` +**generateObject (remove mode: "json"):** ```typescript -// Before -new Agent(components.agent, { - textEmbeddingModel: openai.embedding("text-embedding-3-small") +// BEFORE (v5) +await generateObject({ + model, + mode: "json", + schema: z.object({ ... }), + prompt: "..." }) -// After (textEmbeddingModel still works but embeddingModel is preferred) -new Agent(components.agent, { - embeddingModel: openai.embedding("text-embedding-3-small") +// AFTER (v6) - mode: "json" removed, just use schema +await generateObject({ + model, + schema: z.object({ ... }), + prompt: "..." }) ``` -### Step 5: Verify the upgrade +### Step 4: Verify ```bash npm run typecheck -npm run lint npm test ``` -### Common issues +### Common Issues + +- **EmbeddingModelV2 vs V3 errors**: Ensure all `@ai-sdk/*` packages are v3.x +- **Tool `args` vs `input`**: v6 uses `input` in execute signature (2nd param) +- **`mimeType` vs `mediaType`**: v6 prefers `mediaType` (backwards compat maintained) +- **Type import errors**: `LanguageModelV2` is now `LanguageModelV3`, `EmbeddingModel` is now `EmbeddingModelV3` (no longer generic) +- **generateObject mode errors**: `mode: "json"` was removed in v6 - just remove the mode option + +### New v6 Features to Mention -- **EmbeddingModelV2 vs V3 errors**: Ensure all @ai-sdk/* packages are updated to v3.x -- **Tool input/args**: v6 uses `input` instead of `args` in tool calls (backwards compat maintained) -- **mimeType vs mediaType**: v6 uses `mediaType` (backwards compat maintained) +After upgrade, users can now use: +- **Tool approval**: `needsApproval` in createTool, `agent.approveToolCall()`, `agent.denyToolCall()` +- **Reasoning streaming**: Works with models like Groq that support reasoning +- **Detailed token usage**: `inputTokenDetails`, `outputTokenDetails` in usage tracking diff --git a/package.json b/package.json index cd39d93a..f9ffbf9e 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,8 @@ "files": [ "dist", "src", - "scripts" + "scripts", + "MIGRATION.md" ], "exports": { "./package.json": "./package.json", diff --git a/src/client/createTool.ts b/src/client/createTool.ts index e263d8e0..f21cf5c9 100644 --- a/src/client/createTool.ts +++ b/src/client/createTool.ts @@ -11,7 +11,7 @@ import type { GenericActionCtx, GenericDataModel } from "convex/server"; import type { ProviderOptions } from "../validators.js"; import type { Agent } from "./index.js"; -const MIGRATION_URL = "https://github.com/get-convex/agent/blob/main/MIGRATION.md"; +const MIGRATION_URL = "node_modules/@convex-dev/agent/MIGRATION.md"; const warnedDeprecations = new Set(); function warnDeprecation(key: string, message: string) { if (!warnedDeprecations.has(key)) { @@ -77,7 +77,7 @@ type NeverOptional = 0 extends 1 & N * Using a string literal type causes TypeScript to show this message in errors. */ type HANDLER_REMOVED_ERROR = - "⚠️ 'handler' was removed in @convex-dev/agent v0.6.0. Rename to 'execute'. See: https://github.com/get-convex/agent/blob/main/MIGRATION.md"; + "⚠️ 'handler' was removed in @convex-dev/agent v0.6.0. Rename to 'execute'. See: node_modules/@convex-dev/agent/MIGRATION.md"; export type ToolOutputPropertiesCtx< INPUT, @@ -107,7 +107,7 @@ export type ToolOutputPropertiesCtx< * Using a string literal type causes TypeScript to show this message in errors. */ type ARGS_REMOVED_ERROR = - "⚠️ 'args' was removed in @convex-dev/agent v0.6.0. Rename to 'inputSchema'. See: https://github.com/get-convex/agent/blob/main/MIGRATION.md"; + "⚠️ 'args' was removed in @convex-dev/agent v0.6.0. Rename to 'inputSchema'. See: node_modules/@convex-dev/agent/MIGRATION.md"; export type ToolInputProperties = { /** diff --git a/src/client/index.ts b/src/client/index.ts index dd0041f9..75222764 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -19,7 +19,7 @@ import type { } from "ai"; import { generateObject, generateText, stepCountIs, streamObject } from "ai"; -const MIGRATION_URL = "https://github.com/get-convex/agent/blob/main/MIGRATION.md"; +const MIGRATION_URL = "node_modules/@convex-dev/agent/MIGRATION.md"; const warnedDeprecations = new Set(); function warnDeprecation(key: string, message: string) { if (!warnedDeprecations.has(key)) { diff --git a/src/client/types.ts b/src/client/types.ts index 8ce2c472..ea07439a 100644 --- a/src/client/types.ts +++ b/src/client/types.ts @@ -52,7 +52,7 @@ import type { ComponentApi } from "../component/_generated/component.js"; */ type AssertAISDKv6 = T extends { specificationVersion: "v3" } ? T - : "⚠️ @convex-dev/agent v0.6.0 requires AI SDK v6. Update your dependencies: npm install ai@^6.0.35 @ai-sdk/openai@^3.0.10 (or other provider). See: https://github.com/get-convex/agent/blob/main/MIGRATION.md"; + : "⚠️ @convex-dev/agent v0.6.0 requires AI SDK v6. Update your dependencies: npm install ai@^6.0.35 @ai-sdk/openai@^3.0.10 (or other provider). See: node_modules/@convex-dev/agent/MIGRATION.md"; export type AgentPrompt = { /** From e54da7ed79eacbf1bca83e5143305f04f1aa243a Mon Sep 17 00:00:00 2001 From: Seth Raphael Date: Mon, 26 Jan 2026 07:46:39 -0800 Subject: [PATCH 3/4] Remove unused check-upgrade script Co-Authored-By: Claude Opus 4.5 --- MIGRATION.md | 58 ++++++++++++++++ package.json | 4 -- scripts/check-upgrade.js | 140 --------------------------------------- 3 files changed, 58 insertions(+), 144 deletions(-) delete mode 100755 scripts/check-upgrade.js diff --git a/MIGRATION.md b/MIGRATION.md index 6eff33f7..fdfc09bc 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -4,10 +4,14 @@ This guide helps you upgrade from @convex-dev/agent v0.3.x to v0.6.0. ## Step 1: Update dependencies +Update all AI SDK packages **together** to avoid peer dependency conflicts: + ```bash npm install @convex-dev/agent@^0.6.0 ai@^6.0.35 @ai-sdk/provider-utils@^4.0.6 ``` +### Official AI SDK providers + Update your AI SDK provider packages to v3.x: ```bash # For OpenAI @@ -18,8 +22,38 @@ npm install @ai-sdk/anthropic@^3.0.13 # For Groq npm install @ai-sdk/groq@^3.0.8 + +# For Google (Gemini) +npm install @ai-sdk/google@^3.0.8 +``` + +### Third-party providers + +Third-party providers also need updates to be compatible with AI SDK v6: + +```bash +# For OpenRouter +npm install @openrouter/ai-sdk-provider@^2.0.0 + +# For other providers, check their documentation for AI SDK v6 compatibility +``` + +### Handling dependency conflicts + +If you see peer dependency warnings or errors, try updating all packages at once: + +```bash +npm install @convex-dev/agent@^0.6.0 ai@^6.0.35 @ai-sdk/openai@^3.0.10 @openrouter/ai-sdk-provider@^2.0.0 ``` +If you still have conflicts, you can use `--force` as a last resort: + +```bash +npm install @convex-dev/agent@^0.6.0 --force +``` + +> **Note**: Using `--force` can lead to inconsistent dependency trees. After using it, verify your app works correctly and consider running `npm dedupe` to clean up. + ## Step 2: Update tool definitions Replace `parameters` with `inputSchema`: @@ -89,6 +123,30 @@ AI SDK v6 renamed `args` to `input` in tool calls. The library maintains backwar ### `mimeType` vs `mediaType` AI SDK v6 renamed `mimeType` to `mediaType`. Backwards compatibility is maintained. +### Peer dependency conflicts + +If you see errors like: +``` +npm error ERESOLVE unable to resolve dependency tree +npm error peer ai@"^5.0.0" from @openrouter/ai-sdk-provider@1.0.3 +``` + +This means a third-party provider needs updating. Common solutions: + +1. **Update the provider** to a version compatible with AI SDK v6 +2. **Check npm** for the latest version: `npm view @openrouter/ai-sdk-provider versions` +3. **Use `--force`** if a compatible version isn't available yet (temporary workaround) + +### Third-party provider compatibility + +| Provider | AI SDK v5 (ai@5.x) | AI SDK v6 (ai@6.x) | +|----------|-------------------|-------------------| +| @openrouter/ai-sdk-provider | v1.x | v2.x | +| @ai-sdk/openai | v1.x-v2.x | v3.x | +| @ai-sdk/anthropic | v1.x-v2.x | v3.x | +| @ai-sdk/groq | v1.x-v2.x | v3.x | +| @ai-sdk/google | v1.x-v2.x | v3.x | + ## More Information - [AI SDK v6 Migration Guide](https://ai-sdk.dev/docs/migration-guides/migration-guide-6-0) diff --git a/package.json b/package.json index f9ffbf9e..9b63d397 100644 --- a/package.json +++ b/package.json @@ -39,13 +39,9 @@ "release": "npm version patch && npm publish && git push --follow-tags", "version": "vim -c 'normal o' -c 'normal o## '$npm_package_version CHANGELOG.md && prettier -w CHANGELOG.md && git add CHANGELOG.md" }, - "bin": { - "convex-agent-upgrade-check": "./scripts/check-upgrade.js" - }, "files": [ "dist", "src", - "scripts", "MIGRATION.md" ], "exports": { diff --git a/scripts/check-upgrade.js b/scripts/check-upgrade.js deleted file mode 100755 index eb85cddf..00000000 --- a/scripts/check-upgrade.js +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env node - -/** - * Pre-typecheck script that detects AI SDK v5 patterns and provides - * helpful upgrade instructions before TypeScript errors confuse users. - * - * Run with: node scripts/check-upgrade.js [directory] - */ - -import { readFileSync, readdirSync, statSync } from 'fs'; -import { join, relative } from 'path'; - -const V5_PATTERNS = [ - { - pattern: /LanguageModelV2/g, - message: 'LanguageModelV2 → LanguageModelV3', - fix: "Change 'LanguageModelV2' to 'LanguageModelV3' (or just use 'LanguageModel' from 'ai')", - }, - { - pattern: /EmbeddingModel\s*<\s*string\s*>/g, - message: 'EmbeddingModel → EmbeddingModel', - fix: "Remove the generic parameter: 'EmbeddingModel' → 'EmbeddingModel'", - }, - { - pattern: /textEmbeddingModel\s*:/g, - message: 'textEmbeddingModel → embeddingModel', - fix: "Rename 'textEmbeddingModel' to 'embeddingModel' in your Agent config", - }, - { - pattern: /createTool\(\s*\{[^}]*\bargs\s*:/gs, - message: 'createTool args → inputSchema', - fix: "In createTool(), rename 'args' to 'inputSchema'", - }, - { - pattern: /\bhandler\s*:\s*async\s*\(/g, - message: 'createTool handler → execute', - fix: "In createTool(), rename 'handler' to 'execute' and update signature: execute: async (ctx, input, options)", - }, - { - pattern: /@ai-sdk\/provider['"];\s*$/gm, - message: '@ai-sdk/provider v2 types', - fix: "Update @ai-sdk/* packages to v3.x: npm install @ai-sdk/openai@^3.0.10", - filePattern: /\.(ts|tsx)$/, - }, -]; - -function findFiles(dir, extensions = ['.ts', '.tsx']) { - const files = []; - - function walk(currentDir) { - try { - const entries = readdirSync(currentDir); - for (const entry of entries) { - if (entry === 'node_modules' || entry === '_generated' || entry.startsWith('.')) { - continue; - } - const fullPath = join(currentDir, entry); - const stat = statSync(fullPath); - if (stat.isDirectory()) { - walk(fullPath); - } else if (extensions.some(ext => entry.endsWith(ext))) { - files.push(fullPath); - } - } - } catch (e) { - // Skip directories we can't read - } - } - - walk(dir); - return files; -} - -function checkFile(filePath, baseDir) { - const content = readFileSync(filePath, 'utf-8'); - const issues = []; - - for (const { pattern, message, fix, filePattern } of V5_PATTERNS) { - if (filePattern && !filePattern.test(filePath)) { - continue; - } - - // Reset regex state - pattern.lastIndex = 0; - - let match; - while ((match = pattern.exec(content)) !== null) { - const lines = content.slice(0, match.index).split('\n'); - const line = lines.length; - const col = lines[lines.length - 1].length + 1; - - issues.push({ - file: relative(baseDir, filePath), - line, - col, - message, - fix, - match: match[0].slice(0, 50), - }); - } - } - - return issues; -} - -function main() { - const targetDir = process.argv[2] || process.cwd(); - const files = findFiles(targetDir); - const allIssues = []; - - for (const file of files) { - const issues = checkFile(file, targetDir); - allIssues.push(...issues); - } - - if (allIssues.length === 0) { - console.log('✅ No AI SDK v5 patterns detected. Ready for v6!'); - process.exit(0); - } - - console.error('\n' + '='.repeat(70)); - console.error('⚠️ AI SDK v5 → v6 UPGRADE REQUIRED'); - console.error('='.repeat(70)); - console.error('\nFound', allIssues.length, 'pattern(s) that need updating:\n'); - - for (const issue of allIssues) { - console.error(`📍 ${issue.file}:${issue.line}:${issue.col}`); - console.error(` ${issue.message}`); - console.error(` Fix: ${issue.fix}`); - console.error(''); - } - - console.error('='.repeat(70)); - console.error('📚 Full upgrade guide: https://github.com/get-convex/agent/blob/main/MIGRATION.md'); - console.error('='.repeat(70) + '\n'); - - process.exit(1); -} - -main(); From b67e265d41686e5c0c111f4a6846f44884210a44 Mon Sep 17 00:00:00 2001 From: Seth Raphael Date: Sun, 25 Jan 2026 20:07:31 -0800 Subject: [PATCH 4/4] Enhance CLAUDE.md with comprehensive AI upgrade guidance - Add tool approval flow to Key Patterns architecture section - Replace upgrade section with detailed AI-friendly guidance including: - Detection patterns for v5 code (parameters, handler, textEmbeddingModel) - Dependency update commands - Before/after transformation examples for tools, embeddings, step limits - Verification steps and common issues - New v6 features (tool approval, reasoning streaming, token details) - Remove outdated TODO comment in deltas.ts (partial tool calls now handled) Co-Authored-By: Claude Opus 4.5 --- src/deltas.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/deltas.ts b/src/deltas.ts index 87a8f9f7..0e816d04 100644 --- a/src/deltas.ts +++ b/src/deltas.ts @@ -124,7 +124,6 @@ export async function deriveUIMessagesFromDeltas( blankUIMessage(streamMessage, threadId), parts, ); - // TODO: this fails on partial tool calls messages.push(uiMessage); } else { const [uiMessages] = deriveUIMessagesFromTextStreamParts(