diff --git a/package.json b/package.json index 3204afd..6934e2a 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,9 @@ "license": "Apache-2.0", "private": true, "packageManager": "pnpm@10.33.0", + "engines": { + "node": ">=22" + }, "scripts": { "build": "next build", "dev": "next dev", @@ -20,10 +23,10 @@ "*.{json,md,mdx}": [] }, "dependencies": { - "@ai-sdk/react": "^3.0.206", - "@openrouter/ai-sdk-provider": "^2.9.1", + "@ai-sdk/react": "^4.0.87", + "@openrouter/ai-sdk-provider": "^3.0.0", "@radix-ui/react-presence": "^1.1.10", - "ai": "^6.0.256", + "ai": "^7.0.84", "class-variance-authority": "^0.7.1", "flexsearch": "^0.8.212", "fumadocs-core": "16.14.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 091f654..b988de0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,17 +18,17 @@ importers: .: dependencies: '@ai-sdk/react': - specifier: ^3.0.206 - version: 3.0.206(react@19.2.8)(zod@4.4.3) + specifier: ^4.0.87 + version: 4.0.87(react@19.2.8)(zod@4.4.3) '@openrouter/ai-sdk-provider': - specifier: ^2.9.1 - version: 2.9.1(ai@6.0.256(zod@4.4.3))(zod@4.4.3) + specifier: ^3.0.0 + version: 3.0.0(ai@7.0.84(zod@4.4.3))(zod@4.4.3) '@radix-ui/react-presence': specifier: ^1.1.10 version: 1.1.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) ai: - specifier: ^6.0.256 - version: 6.0.256(zod@4.4.3) + specifier: ^7.0.84 + version: 7.0.84(zod@4.4.3) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -129,41 +129,31 @@ importers: packages: - '@ai-sdk/gateway@3.0.130': - resolution: {integrity: sha512-qenRdpoYM+2y8Ibj3Y7XngvfcG4NIpejaM+YqAKWXi3/N1qZYeIelrm19jxhIwQW0W/g7WUz0L2Agl7+FnwrQA==} - engines: {node: '>=18'} + '@ai-sdk/gateway@4.0.68': + resolution: {integrity: sha512-XKvZv6HFoMOWK64zXMaQatk4SxBzBDkGg7enXPWsCkxqPP4zDhFewOoBKasf3FPnZP9ceE+Yj3BgW925blAWtw==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/gateway@3.0.174': - resolution: {integrity: sha512-RXDYc+FGEuy1Y/HlM4MThtQAzG99AIs8ki4tIoVnVweOlW5HDSfaNGNLw556ZR4TifTRuPfBc6QljX4UkuGG6A==} - engines: {node: '>=18'} + '@ai-sdk/mcp@2.0.40': + resolution: {integrity: sha512-BMDJ50IHlMe/bSOQ9Pk46g/yybrN+TD3hz49ryMthBo0e+CQ54ZWOsU+x/Cl7zKYoZzRECD4CRm7iu76GVq17g==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@4.0.29': - resolution: {integrity: sha512-uhukHaCBvqkwBHkT8C2PrnqKTCoLn3pdHXqtcR9I8ErH+flbzgW4o7VHSNIup9LRu+WBvZIZDQLsx6rwl2tiOA==} - engines: {node: '>=18'} + '@ai-sdk/provider-utils@5.0.33': + resolution: {integrity: sha512-TfjJqJmRsQyxAlb+3hGmP1o1xLUIT79yhOgtJuTF4hqsB37IC3CufGsuFhU04EeTOg7R9iptQ6Bzm0MW0n/c3g==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@4.0.46': - resolution: {integrity: sha512-tEtld97plCFiYevsJuOkGkeuhQndeMWFBVrJS4AjnbD5AqrNSXRCe0p+BZ3Cju/sxDeeZ9ym3q9YUV8fASA7aQ==} - engines: {node: '>=18.17'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider@4.0.8': + resolution: {integrity: sha512-aWO7iwhFUGf347tCwNGggggfmZigaSu7TF739IZSrWWABUp7zkb4Cr3fMqvBe5EIS7ABJJu3Cadn0g/zs1G0QQ==} + engines: {node: '>=22'} - '@ai-sdk/provider@3.0.10': - resolution: {integrity: sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw==} - engines: {node: '>=18'} - - '@ai-sdk/provider@3.0.15': - resolution: {integrity: sha512-XeZW1CcDF2GMbH4wejW6xBRI2QCOgnkVYUnxoeDadB1mf85riL2bMUeDoh+6gJ/r4mjNfzUPW8OjLjvwTP0u1Q==} - engines: {node: '>=18'} - - '@ai-sdk/react@3.0.206': - resolution: {integrity: sha512-26gbPT876BZVXJlSNjqkCDOFiqfxAAhYn+a/ryV6ce5TWo6EfWQZeEiLrZOS6bxaOi7xxkB5uPZaZKFaIJndjQ==} - engines: {node: '>=18'} + '@ai-sdk/react@4.0.87': + resolution: {integrity: sha512-IvL0uz6RwxVCRveiIhsHuxoNH7DC3QXMTUEtPb2tVkB+3trL5pD63HiovJ34FAQ9YSgzhkdj5oQlbUXJ4zFpoQ==} + engines: {node: '>=22'} peerDependencies: react: ^18 || ~19.0.1 || ~19.1.2 || ^19.2.1 @@ -765,12 +755,12 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} - '@openrouter/ai-sdk-provider@2.9.1': - resolution: {integrity: sha512-okgq07Vdkro4CB5INbfhwa0e6VR1HS7sidNcfHN/MeXLJvX1JmQCff/vem6tcxwT9r1avyFrXSlfv9B28D/Pag==} - engines: {node: '>=18'} + '@openrouter/ai-sdk-provider@3.0.0': + resolution: {integrity: sha512-m9XTSWoODH2RM5OsZpaGiN7QRR8cdP5paBWq699Tu3JVmGPBKT8xF8XwV0ZBVVsjikD/JgWfak4VSsTR4wAVbg==} + engines: {node: '>=22'} peerDependencies: - ai: ^6.0.0 - zod: ^3.25.0 || ^4.0.0 + ai: ^7.0.0 + zod: ^3.25.76 || ^4.1.8 '@opentelemetry/api@1.9.1': resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} @@ -1504,6 +1494,9 @@ packages: resolution: {integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==} engines: {node: '>= 20'} + '@workflow/serde@4.1.0': + resolution: {integrity: sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ==} + '@yuku-analyzer/binding-android-arm64@0.8.7': resolution: {integrity: sha512-pzJ++UMCZEV4s6SP3Ryvj+snWP8s7aTXFkSXRyeBF4RSALftPzfqYssHdGOmOH2QnRAtyOhhg64tdjeSGJvYRg==} cpu: [arm64] @@ -1588,15 +1581,9 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - ai@6.0.204: - resolution: {integrity: sha512-SudB8rUwaVhpWF8+qTJcxUptXPIdN9rWMknzTT3WbKa2QwiGRshyepFKNkDILWm882LgqlEyRZgKhNT14j0jpQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - - ai@6.0.256: - resolution: {integrity: sha512-xYvQfvwFG1AsiLv8wSS1o1077q/494HxzI6SIw0G/5zIoirNyJUzFlh/BTZBqbHMa03Pt5EouIGAbGimldiDGg==} - engines: {node: '>=18'} + ai@7.0.84: + resolution: {integrity: sha512-znHNBWADOy79k8EK7636kDm5LmnjF4tMzegC2TfmlLDobDZbs0z0OXD2sxtH3eDTp5Re+pJQESvjinWJ6+kadQ==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -2074,10 +2061,6 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - eventsource-parser@3.1.0: - resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} - engines: {node: '>=18.0.0'} - eventsource-parser@3.1.1: resolution: {integrity: sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==} engines: {node: '>=18.0.0'} @@ -3072,6 +3055,10 @@ packages: resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -3476,9 +3463,9 @@ packages: undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} - undici@6.28.0: - resolution: {integrity: sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==} - engines: {node: '>=18.17'} + undici@7.29.0: + resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==} + engines: {node: '>=20.18.1'} unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -3614,47 +3601,40 @@ packages: snapshots: - '@ai-sdk/gateway@3.0.130(zod@4.4.3)': - dependencies: - '@ai-sdk/provider': 3.0.10 - '@ai-sdk/provider-utils': 4.0.29(zod@4.4.3) - '@vercel/oidc': 3.2.0 - zod: 4.4.3 - - '@ai-sdk/gateway@3.0.174(zod@4.4.3)': + '@ai-sdk/gateway@4.0.68(zod@4.4.3)': dependencies: - '@ai-sdk/provider': 3.0.15 - '@ai-sdk/provider-utils': 4.0.46(zod@4.4.3) + '@ai-sdk/provider': 4.0.8 + '@ai-sdk/provider-utils': 5.0.33(zod@4.4.3) '@vercel/oidc': 3.2.0 zod: 4.4.3 - '@ai-sdk/provider-utils@4.0.29(zod@4.4.3)': + '@ai-sdk/mcp@2.0.40(zod@4.4.3)': dependencies: - '@ai-sdk/provider': 3.0.10 - '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.1.0 + '@ai-sdk/provider': 4.0.8 + '@ai-sdk/provider-utils': 5.0.33(zod@4.4.3) + cross-spawn: 7.0.6 + pkce-challenge: 5.0.1 zod: 4.4.3 - '@ai-sdk/provider-utils@4.0.46(zod@4.4.3)': + '@ai-sdk/provider-utils@5.0.33(zod@4.4.3)': dependencies: - '@ai-sdk/provider': 3.0.15 + '@ai-sdk/provider': 4.0.8 '@standard-schema/spec': 1.1.0 + '@workflow/serde': 4.1.0 eventsource-parser: 3.1.1 - undici: 6.28.0 + undici: 7.29.0 zod: 4.4.3 - '@ai-sdk/provider@3.0.10': - dependencies: - json-schema: 0.4.0 - - '@ai-sdk/provider@3.0.15': + '@ai-sdk/provider@4.0.8': dependencies: json-schema: 0.4.0 - '@ai-sdk/react@3.0.206(react@19.2.8)(zod@4.4.3)': + '@ai-sdk/react@4.0.87(react@19.2.8)(zod@4.4.3)': dependencies: - '@ai-sdk/provider-utils': 4.0.29(zod@4.4.3) - ai: 6.0.204(zod@4.4.3) + '@ai-sdk/mcp': 2.0.40(zod@4.4.3) + '@ai-sdk/provider': 4.0.8 + '@ai-sdk/provider-utils': 5.0.33(zod@4.4.3) + ai: 7.0.84(zod@4.4.3) react: 19.2.8 swr: 2.4.1(react@19.2.8) throttleit: 2.1.0 @@ -4167,12 +4147,13 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@openrouter/ai-sdk-provider@2.9.1(ai@6.0.256(zod@4.4.3))(zod@4.4.3)': + '@openrouter/ai-sdk-provider@3.0.0(ai@7.0.84(zod@4.4.3))(zod@4.4.3)': dependencies: - ai: 6.0.256(zod@4.4.3) + ai: 7.0.84(zod@4.4.3) zod: 4.4.3 - '@opentelemetry/api@1.9.1': {} + '@opentelemetry/api@1.9.1': + optional: true '@radix-ui/number@1.1.3': {} @@ -4858,6 +4839,8 @@ snapshots: '@vercel/oidc@3.2.0': {} + '@workflow/serde@4.1.0': {} + '@yuku-analyzer/binding-android-arm64@0.8.7': optional: true @@ -4908,20 +4891,11 @@ snapshots: acorn@8.18.0: {} - ai@6.0.204(zod@4.4.3): - dependencies: - '@ai-sdk/gateway': 3.0.130(zod@4.4.3) - '@ai-sdk/provider': 3.0.10 - '@ai-sdk/provider-utils': 4.0.29(zod@4.4.3) - '@opentelemetry/api': 1.9.1 - zod: 4.4.3 - - ai@6.0.256(zod@4.4.3): + ai@7.0.84(zod@4.4.3): dependencies: - '@ai-sdk/gateway': 3.0.174(zod@4.4.3) - '@ai-sdk/provider': 3.0.15 - '@ai-sdk/provider-utils': 4.0.46(zod@4.4.3) - '@opentelemetry/api': 1.9.1 + '@ai-sdk/gateway': 4.0.68(zod@4.4.3) + '@ai-sdk/provider': 4.0.8 + '@ai-sdk/provider-utils': 5.0.33(zod@4.4.3) zod: 4.4.3 ajv@6.14.0: @@ -5606,8 +5580,6 @@ snapshots: esutils@2.0.3: {} - eventsource-parser@3.1.0: {} - eventsource-parser@3.1.1: {} extend@3.0.2: {} @@ -6901,6 +6873,8 @@ snapshots: picomatch@4.0.5: {} + pkce-challenge@5.0.1: {} + possible-typed-array-names@1.1.0: {} postcss@8.5.23: @@ -7444,7 +7418,7 @@ snapshots: undici-types@8.3.0: {} - undici@6.28.0: {} + undici@7.29.0: {} unified@11.0.5: dependencies: diff --git a/src/app/api/chat/route.ts b/src/app/api/chat/route.ts index 1f3dd47..f76d12d 100644 --- a/src/app/api/chat/route.ts +++ b/src/app/api/chat/route.ts @@ -1,5 +1,5 @@ import { createOpenRouter } from '@openrouter/ai-sdk-provider'; -import { convertToModelMessages, stepCountIs, streamText, tool, type UIMessage } from 'ai'; +import { convertToModelMessages, isStepCount, streamText, tool, type UIMessage } from 'ai'; import { z } from 'zod'; import { source } from '@/lib/source'; import { Document, type DocumentData } from 'flexsearch'; @@ -77,22 +77,20 @@ export async function POST(req: Request, ctx: RouteContext<"/api/chat">) { const result = streamText({ model: openrouter.chat(process.env.OPENROUTER_MODEL ?? 'anthropic/claude-3.5-sonnet'), - stopWhen: stepCountIs(5), + instructions: systemPrompt, + stopWhen: isStepCount(5), tools: { search: searchTool, }, - messages: [ - { role: 'system', content: systemPrompt }, - ...(await convertToModelMessages(reqJson.messages ?? [], { - convertDataPart(part) { - if (part.type === 'data-client') - return { - type: 'text', - text: `[Client Context: ${JSON.stringify(part.data)}]`, - }; - }, - })), - ], + messages: await convertToModelMessages(reqJson.messages ?? [], { + convertDataPart(part) { + if (part.type === 'data-client') + return { + type: 'text', + text: `[Client Context: ${JSON.stringify(part.data)}]`, + }; + }, + }), toolChoice: 'auto', }); @@ -111,4 +109,4 @@ const searchTool = tool({ const search = await searchServer; return await search.searchAsync(query, { limit, merge: true, enrich: true }); }, -}); \ No newline at end of file +});