diff --git a/package-lock.json b/package-lock.json index 3174d20..e02ef02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,24 +9,26 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@ai-sdk/openai": "^0.0.9", - "@mfng/core": "^4.1.2", + "@ai-sdk/openai": "^0.0.40", + "@ai-sdk/react": "^0.0.36", + "@ai-sdk/ui-utils": "^0.0.24", + "@mfng/core": "^4.1.4", "@upstash/ratelimit": "^1.0.1", "@upstash/redis": "^1.28.4", - "ai": "^3.1.1", + "ai": "^3.2.45", "clsx": "^1.2.1", - "openai": "^4.40.1", - "react": "0.0.0-experimental-73bcdfbae5-20240502", - "react-dom": "0.0.0-experimental-73bcdfbae5-20240502", + "openai": "4.52.6", + "react": "19.0.0-rc-06d0b89e-20240801", + "react-dom": "19.0.0-rc-06d0b89e-20240801", "react-markdown": "^9.0.1", - "react-server-dom-webpack": "0.0.0-experimental-73bcdfbae5-20240502", + "react-server-dom-webpack": "19.0.0-rc-06d0b89e-20240801", "react-textarea-autosize": "^8.5.3", "server-only": "^0.0.1", "zod": "^3.22.4" }, "devDependencies": { "@hono/node-server": "^1.8.2", - "@mfng/webpack-rsc": "^4.0.1", + "@mfng/webpack-rsc": "^4.2.1", "@swc/core": "^1.3.22", "@types/aws-lambda": "^8.10.136", "@types/node": "^20.11.26", @@ -78,29 +80,24 @@ } }, "node_modules/@ai-sdk/openai": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-0.0.9.tgz", - "integrity": "sha512-SSZGtX4KFDXWYmQ9JuhVumo1XOx1JAdHybYy08iwVXuCud9xdjZjjxgZkNPytQK9gRxFsYDOw1h0V/WXO7XgfQ==", + "version": "0.0.40", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-0.0.40.tgz", + "integrity": "sha512-9Iq1UaBHA5ZzNv6j3govuKGXrbrjuWvZIgWNJv4xzXlDMHu9P9hnqlBr/Aiay54WwCuTVNhTzAUTfFgnTs2kbQ==", "dependencies": { - "@ai-sdk/provider": "0.0.3", - "@ai-sdk/provider-utils": "0.0.5" + "@ai-sdk/provider": "0.0.14", + "@ai-sdk/provider-utils": "1.0.5" }, "engines": { "node": ">=18" }, "peerDependencies": { "zod": "^3.0.0" - }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } } }, "node_modules/@ai-sdk/provider": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-0.0.3.tgz", - "integrity": "sha512-0B8P6VZpJ6F9yS9BpmJBYSqIaIfeRtL5tD5SP+qgR8y0pPwalIbRMUFiLz9YUT6g70MJsCLpm/2/fX3cfAYCJw==", + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-0.0.14.tgz", + "integrity": "sha512-gaQ5Y033nro9iX1YUjEDFDRhmMcEiCk56LJdIUbX5ozEiCNCfpiBpEqrjSp/Gp5RzBS2W0BVxfG7UGW6Ezcrzg==", "dependencies": { "json-schema": "0.4.0" }, @@ -109,11 +106,11 @@ } }, "node_modules/@ai-sdk/provider-utils": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-0.0.5.tgz", - "integrity": "sha512-VVy9eQS+vS2j6cqTEQ9htMHz2nW/HFAkDXLvNFPoi1pZkviknJZEzb+DZUna6Od+jBf/TVA0HZwYnyGDaeI9cQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-1.0.5.tgz", + "integrity": "sha512-XfOawxk95X3S43arn2iQIFyWGMi0DTxsf9ETc6t7bh91RPWOOPYN1tsmS5MTKD33OGJeaDQ/gnVRzXUCRBrckQ==", "dependencies": { - "@ai-sdk/provider": "0.0.3", + "@ai-sdk/provider": "0.0.14", "eventsource-parser": "1.1.2", "nanoid": "3.3.6", "secure-json-parse": "2.7.0" @@ -130,6 +127,114 @@ } } }, + "node_modules/@ai-sdk/react": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-0.0.36.tgz", + "integrity": "sha512-LAxFLtHKN1BajTNP8YzyVIwXn45LSunmvm2Svrfq5oPOyJ2gUEjtaONnbme4mwRXJ1kk6b63SLrgOIXbz6XF/g==", + "dependencies": { + "@ai-sdk/provider-utils": "1.0.5", + "@ai-sdk/ui-utils": "0.0.24", + "swr": "2.2.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18 || ^19", + "zod": "^3.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/@ai-sdk/solid": { + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/@ai-sdk/solid/-/solid-0.0.27.tgz", + "integrity": "sha512-uEvlT7MBkRRZxk7teDgtrGe7G3U9tspgSJUvupdOE2d0a4vLlHrMqHb07ao97/Xo1aVHh7oBF9XIgRzKnFtbIQ==", + "dependencies": { + "@ai-sdk/provider-utils": "1.0.5", + "@ai-sdk/ui-utils": "0.0.24" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "solid-js": "^1.7.7" + }, + "peerDependenciesMeta": { + "solid-js": { + "optional": true + } + } + }, + "node_modules/@ai-sdk/svelte": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@ai-sdk/svelte/-/svelte-0.0.29.tgz", + "integrity": "sha512-7vrh61wXPVfy19nS4CqyAC3UWjsOgj/b94PCccVTGFoqbmVSa0VptXPYoFfgPTP/W71v7TjXqeq1ygLc4noTZw==", + "dependencies": { + "@ai-sdk/provider-utils": "1.0.5", + "@ai-sdk/ui-utils": "0.0.24", + "sswr": "2.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "svelte": "^3.0.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/@ai-sdk/ui-utils": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-0.0.24.tgz", + "integrity": "sha512-NBhhICWJ5vAkN4BJnP/MyT+fOB6rTlGlsKGQwvjlhNxdrY1/jXqe2ikNkCbCSEz20IDk82bmg2JJBM96g1O3Ig==", + "dependencies": { + "@ai-sdk/provider": "0.0.14", + "@ai-sdk/provider-utils": "1.0.5", + "secure-json-parse": "2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@ai-sdk/vue": { + "version": "0.0.28", + "resolved": "https://registry.npmjs.org/@ai-sdk/vue/-/vue-0.0.28.tgz", + "integrity": "sha512-ZnDjkkUH/9xoXqJEmyrG9Z8z7DKBnp2uyCd9ZVI8QSqKOaP0jOwhv8THUXlIqDEF+ULLGMWm0XeY/L7i3CMYTA==", + "dependencies": { + "@ai-sdk/provider-utils": "1.0.5", + "@ai-sdk/ui-utils": "0.0.24", + "swrv": "1.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "vue": "^3.3.4" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -1131,22 +1236,22 @@ } }, "node_modules/@mfng/core": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@mfng/core/-/core-4.1.2.tgz", - "integrity": "sha512-5dxxCivOdQCXaW4uGP/2rSOeNgjD/DQWRtSoG16twf/k0MKs0QMRDhftKMydpDTmqgl10kqdoLXDv5EsggoC2Q==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@mfng/core/-/core-4.1.4.tgz", + "integrity": "sha512-wrrly8h1Ahf3NkLRIDjSdV1FRY9Z15sif65yAWgJWppozNHTMgE1hCR9eu+n4b6gQFBXZdW1f0DjEQPHIacNCw==", "dependencies": { "htmlescape": "^1.1.1" }, "peerDependencies": { + "react": "*", "react-dom": "*", - "react-react": "*", "react-server-dom-webpack": "*" } }, "node_modules/@mfng/webpack-rsc": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@mfng/webpack-rsc/-/webpack-rsc-4.0.1.tgz", - "integrity": "sha512-ueObgKTlNqHbR6FllipITAha7fVzOMHDvyK59h2WU6u3DIBs0+Lwz0cSiU7PKnrBhxxTApRaL5zS5krrYy9aog==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@mfng/webpack-rsc/-/webpack-rsc-4.2.1.tgz", + "integrity": "sha512-A7zKJpeTG38eR8wL+qWJr3o3Llw2OtC0PeTTlfWIQdUssD5KUd89sUC8APZb4R+Q8/vi129HZ7faJ7LfC5tm+w==", "dev": true, "dependencies": { "@babel/core": "^7.21.3", @@ -1195,6 +1300,14 @@ "node": ">= 8" } }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2162,45 +2275,46 @@ } }, "node_modules/ai": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/ai/-/ai-3.1.1.tgz", - "integrity": "sha512-pJZc6q7SLd2/NenxN62iagMw9HHQ4Q8FyKqkrZUJntupRTHHgN3fL7exzJU/ICHDAbtn/EcJXOau6P61QgUtKQ==", - "dependencies": { - "@ai-sdk/provider": "0.0.3", - "@ai-sdk/provider-utils": "0.0.5", + "version": "3.2.45", + "resolved": "https://registry.npmjs.org/ai/-/ai-3.2.45.tgz", + "integrity": "sha512-FRsxS9ydMMTT851aNE8uyyXZ86IjJigOe5mYdhbpSsz8okTPJPFo0bSlZULvNKttonU7UvU4hCzZV0qAMMZm+w==", + "dependencies": { + "@ai-sdk/provider": "0.0.14", + "@ai-sdk/provider-utils": "1.0.5", + "@ai-sdk/react": "0.0.36", + "@ai-sdk/solid": "0.0.27", + "@ai-sdk/svelte": "0.0.29", + "@ai-sdk/ui-utils": "0.0.24", + "@ai-sdk/vue": "0.0.28", + "@opentelemetry/api": "1.9.0", "eventsource-parser": "1.1.2", "json-schema": "0.4.0", "jsondiffpatch": "0.6.0", "nanoid": "3.3.6", "secure-json-parse": "2.7.0", - "solid-swr-store": "0.10.7", - "sswr": "2.0.0", - "swr": "2.2.0", - "swr-store": "0.10.6", - "swrv": "1.0.4", "zod-to-json-schema": "3.22.5" }, "engines": { "node": ">=18" }, "peerDependencies": { - "react": "^18.2.0", - "solid-js": "^1.7.7", + "openai": "^4.42.0", + "react": "^18 || ^19", + "sswr": "^2.1.0", "svelte": "^3.0.0 || ^4.0.0", - "vue": "^3.3.4", "zod": "^3.0.0" }, "peerDependenciesMeta": { - "react": { + "openai": { "optional": true }, - "solid-js": { + "react": { "optional": true }, - "svelte": { + "sswr": { "optional": true }, - "vue": { + "svelte": { "optional": true }, "zod": { @@ -3024,6 +3138,11 @@ "node": ">=6.0" } }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -6571,9 +6690,9 @@ } }, "node_modules/openai": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.40.1.tgz", - "integrity": "sha512-mS7LerF4fY1/we0aKGGwIWtosTJFLKuNbBWMBR/G1TAZUHoktAdod0dqIrlQvSD39uS6jNEEbT7jRsXmzfEPBw==", + "version": "4.52.6", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.52.6.tgz", + "integrity": "sha512-mT4SblnPXkzgiGY/cByU57sDDCqNUt3GQV8mzt4rL/xP6PHIQyTqwJ/WxwGhHRQ9okxgsDNgKQ6asdq8Dynw+g==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", @@ -7694,22 +7813,22 @@ } }, "node_modules/react": { - "version": "0.0.0-experimental-73bcdfbae5-20240502", - "resolved": "https://registry.npmjs.org/react/-/react-0.0.0-experimental-73bcdfbae5-20240502.tgz", - "integrity": "sha512-V/IJUwAFh/qxOPARkBNjtt7ohchHxNhNCyUdnbfDgBMdkEtwTFdI/btpsg881hfHCsYGC9wfDFPPH8ni+8f8Hg==", + "version": "19.0.0-rc-06d0b89e-20240801", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0-rc-06d0b89e-20240801.tgz", + "integrity": "sha512-moBKIME1GBgs8onH1xCs+gzPWyLF62m+2XbD4GpirxeRDca7GLA8UQZO9IuQvf1uxCpVWCG8FrpU/D2x7Plknw==", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "0.0.0-experimental-73bcdfbae5-20240502", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-0.0.0-experimental-73bcdfbae5-20240502.tgz", - "integrity": "sha512-BsZ+1jtUoy/mwbr87km72xr63N1UUAMbyA99ZU0ZL99os+1r1NjAAQzk1isvlC0U41fDmkdq28ASZI09m3XT3A==", + "version": "19.0.0-rc-06d0b89e-20240801", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0-rc-06d0b89e-20240801.tgz", + "integrity": "sha512-6JIbEXFwsRkI3gLKhcmjvQ3GKsP4NR/BjPyTKyp7xYeQEeiH01TypGVbc/K6nU1/y4jNGFGkxH3ZFbKKZwCecw==", "dependencies": { - "scheduler": "0.0.0-experimental-73bcdfbae5-20240502" + "scheduler": "0.25.0-rc-06d0b89e-20240801" }, "peerDependencies": { - "react": "0.0.0-experimental-73bcdfbae5-20240502" + "react": "19.0.0-rc-06d0b89e-20240801" } }, "node_modules/react-markdown": { @@ -7738,9 +7857,9 @@ } }, "node_modules/react-server-dom-webpack": { - "version": "0.0.0-experimental-73bcdfbae5-20240502", - "resolved": "https://registry.npmjs.org/react-server-dom-webpack/-/react-server-dom-webpack-0.0.0-experimental-73bcdfbae5-20240502.tgz", - "integrity": "sha512-jscvySId+xf9Y0o2jkA7zdJOOZBH+dPOLGO5Ay+w/4kcqey8zPp+mqHCfh1hdNjKcVnfb50FcUDAnj3M2Y52sQ==", + "version": "19.0.0-rc-06d0b89e-20240801", + "resolved": "https://registry.npmjs.org/react-server-dom-webpack/-/react-server-dom-webpack-19.0.0-rc-06d0b89e-20240801.tgz", + "integrity": "sha512-vtmADrM6fkwEt4wjfS1NX3IU7g+RcIfl8a9WmuI3mhrQ0o6eYUccCQxzn7vMPcTqtiSsD3Cou/09hJoFiqxR/Q==", "dependencies": { "acorn-loose": "^8.3.0", "neo-async": "^2.6.1" @@ -7749,8 +7868,8 @@ "node": ">=0.10.0" }, "peerDependencies": { - "react": "0.0.0-experimental-73bcdfbae5-20240502", - "react-dom": "0.0.0-experimental-73bcdfbae5-20240502", + "react": "19.0.0-rc-06d0b89e-20240801", + "react-dom": "19.0.0-rc-06d0b89e-20240801", "webpack": "^5.59.0" } }, @@ -8099,9 +8218,9 @@ "dev": true }, "node_modules/scheduler": { - "version": "0.0.0-experimental-73bcdfbae5-20240502", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.0.0-experimental-73bcdfbae5-20240502.tgz", - "integrity": "sha512-lUQnRZCoEAyKNPE9UWkx8c8+EHfjtMLw5L9E+at8QBCzvlC2aCZ9f3qhuJJb5pna659KpATGo+tEaJxmImLTiw==" + "version": "0.25.0-rc-06d0b89e-20240801", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc-06d0b89e-20240801.tgz", + "integrity": "sha512-5RF+494IBigvBHUPYId9MhAWyN0cZZq3o82oAbYvZuc2IFc4mZYHS3z2MuJ5Lwm39zGWDEzB404X6BO47zbt5w==" }, "node_modules/schema-utils": { "version": "4.2.0", @@ -8204,18 +8323,6 @@ "node": ">=8" } }, - "node_modules/solid-swr-store": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/solid-swr-store/-/solid-swr-store-0.10.7.tgz", - "integrity": "sha512-A6d68aJmRP471aWqKKPE2tpgOiR5fH4qXQNfKIec+Vap+MGQm3tvXlT8n0I8UgJSlNAsSAUuw2VTviH2h3Vv5g==", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "solid-js": "^1.2", - "swr-store": "^0.10" - } - }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -8280,14 +8387,14 @@ } }, "node_modules/sswr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sswr/-/sswr-2.0.0.tgz", - "integrity": "sha512-mV0kkeBHcjcb0M5NqKtKVg/uTIYNlIIniyDfSGrSfxpEdM9C365jK0z55pl9K0xAkNTJi2OAOVFQpgMPUk+V0w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sswr/-/sswr-2.1.0.tgz", + "integrity": "sha512-Cqc355SYlTAaUt8iDPaC/4DPPXK925PePLMxyBKuWd5kKc5mwsG3nT9+Mq2tyguL5s7b4Jg+IRMpTRsNTAfpSQ==", "dependencies": { "swrev": "^4.0.0" }, "peerDependencies": { - "svelte": "^4.0.0" + "svelte": "^4.0.0 || ^5.0.0-next.0" } }, "node_modules/string-width": { @@ -8563,27 +8670,17 @@ } }, "node_modules/swr": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.0.tgz", - "integrity": "sha512-AjqHOv2lAhkuUdIiBu9xbuettzAzWXmCEcLONNKJRba87WAefz8Ca9d6ds/SzrPc235n1IxWYdhJ2zF3MNUaoQ==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz", + "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==", "dependencies": { + "client-only": "^0.0.1", "use-sync-external-store": "^1.2.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/swr-store": { - "version": "0.10.6", - "resolved": "https://registry.npmjs.org/swr-store/-/swr-store-0.10.6.tgz", - "integrity": "sha512-xPjB1hARSiRaNNlUQvWSVrG5SirCjk2TmaUyzzvk69SZQan9hCJqw/5rG9iL7xElHU784GxRPISClq4488/XVw==", - "dependencies": { - "dequal": "^2.0.3" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/swrev": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/swrev/-/swrev-4.0.0.tgz", diff --git a/package.json b/package.json index 21bff60..e8e6704 100644 --- a/package.json +++ b/package.json @@ -26,24 +26,26 @@ "watch:dev": "webpack --mode development --watch" }, "dependencies": { - "@ai-sdk/openai": "^0.0.9", - "@mfng/core": "^4.1.2", + "@ai-sdk/openai": "^0.0.40", + "@ai-sdk/react": "^0.0.36", + "@ai-sdk/ui-utils": "^0.0.24", + "@mfng/core": "^4.1.4", "@upstash/ratelimit": "^1.0.1", "@upstash/redis": "^1.28.4", - "ai": "^3.1.1", + "ai": "^3.2.45", "clsx": "^1.2.1", - "openai": "^4.40.1", - "react": "0.0.0-experimental-73bcdfbae5-20240502", - "react-dom": "0.0.0-experimental-73bcdfbae5-20240502", + "openai": "4.52.6", + "react": "19.0.0-rc-06d0b89e-20240801", + "react-dom": "19.0.0-rc-06d0b89e-20240801", "react-markdown": "^9.0.1", - "react-server-dom-webpack": "0.0.0-experimental-73bcdfbae5-20240502", + "react-server-dom-webpack": "19.0.0-rc-06d0b89e-20240801", "react-textarea-autosize": "^8.5.3", "server-only": "^0.0.1", "zod": "^3.22.4" }, "devDependencies": { "@hono/node-server": "^1.8.2", - "@mfng/webpack-rsc": "^4.0.1", + "@mfng/webpack-rsc": "^4.2.1", "@swc/core": "^1.3.22", "@types/aws-lambda": "^8.10.136", "@types/node": "^20.11.26", diff --git a/src/app/actions.tsx b/src/app/actions.tsx new file mode 100644 index 0000000..7002515 --- /dev/null +++ b/src/app/actions.tsx @@ -0,0 +1,124 @@ +import {openai} from '@ai-sdk/openai'; +import type {CoreMessage} from 'ai'; +import {generateId} from 'ai'; +import { + getMutableAIState as $getMutableAIState, + createAI, + createStreamableValue, + streamUI, +} from 'ai/rsc'; +import * as React from 'react'; +import {z} from 'zod'; +import {BotMessage, Message} from './message.js'; + +type AIProviderNoActions = ReturnType>; +// typed wrapper *without* actions defined to avoid circular dependencies +const getMutableAIState = $getMutableAIState; + +// mock function to fetch weather data +const fetchWeatherData = async (_location: string) => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + return {temperature: `72°F`}; +}; + +export async function submitUserMessage(userInput: string): Promise<{ + id: string; + display: React.ReactNode; +}> { + 'use server'; + + const aiState = getMutableAIState(); + + aiState.update({ + ...aiState.get(), + messages: [ + ...aiState.get().messages, + {id: generateId(), role: `user`, content: userInput}, + ], + }); + + let textStream: undefined | ReturnType>; + let textNode: React.ReactNode; + + const result = await streamUI({ + model: openai(`gpt-4-turbo`), + initial: Working on that..., + system: `You are a weather assistant.`, + messages: aiState + .get() + .messages.map(({role, content}) => ({role, content} as CoreMessage)), + + text: async ({content, done, delta}) => { + if (!textStream) { + textStream = createStreamableValue(``); + textNode = ; + } + + if (done) { + textStream.done(); + aiState.update({ + ...aiState.get(), + messages: [ + ...aiState.get().messages, + {id: generateId(), role: `assistant`, content}, + ], + }); + } else { + textStream.append(delta); + } + + return textNode; + }, + tools: { + get_current_weather: { + description: `Get the current weather`, + parameters: z.object({ + location: z.string(), + }), + async *generate({location}) { + yield ( + Loading weather for {location} + ); + const {temperature} = await fetchWeatherData(location); + return ( + + + The temperature in {location} is{` `} + {temperature} + + + ); + }, + }, + }, + onFinish: (event) => { + // your own logic, e.g. for saving the chat history or recording usage + console.log(`[onFinish]: ${JSON.stringify(event, null, 2)}`); + }, + }); + + return { + id: generateId(), + display: result.value, + }; +} + +export type ClientMessage = CoreMessage & { + id: string; +}; + +export type AIState = { + chatId: string; + messages: ClientMessage[]; +}; + +export type UIState = { + id: string; + display: React.ReactNode; +}[]; + +export const AI = createAI({ + actions: {submitUserMessage}, + initialUIState: [] as UIState, + initialAIState: {chatId: generateId(), messages: []} as AIState, +}); diff --git a/src/app/ai-state.ts b/src/app/ai-state.ts deleted file mode 100644 index a98aaf5..0000000 --- a/src/app/ai-state.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type {CoreMessage} from 'ai'; - -export type UserInputAction = 'choose-option' | 'message' | 'select-image'; - -export interface UserInput { - readonly action: UserInputAction; - readonly content: string; -} - -export function fromUserInput(userInput: UserInput): CoreMessage { - const {action, content} = userInput; - - if (action === `message`) { - return {role: `user`, content}; - } - - return { - role: `user`, - content: getUserActionContent(action, content), - }; -} - -function getUserActionContent( - action: 'choose-option' | 'select-image', - content: string, -): string { - switch (action) { - case `choose-option`: - return `I choose: ${content}`; - case `select-image`: - return `I want to know more about the image ${content}. Keep it short.`; - } -} diff --git a/src/app/ai.tsx b/src/app/ai.tsx deleted file mode 100644 index 46cea10..0000000 --- a/src/app/ai.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import type {CoreMessage} from 'ai'; -import {createAI} from 'ai/rsc'; -import type * as React from 'react'; -import {submitUserMessage} from './submit-user-message.js'; - -export interface UIStateItem { - readonly id: number; - readonly role: 'user' | 'assistant' | 'error'; - readonly display: React.ReactNode; -} - -const initialAIState: CoreMessage[] = []; -const initialUIState: UIStateItem[] = []; - -export const AI = createAI({ - actions: {submitUserMessage}, - initialUIState, - initialAIState, -}); diff --git a/src/app/app.tsx b/src/app/app.tsx index 686ebc4..44a24e8 100644 --- a/src/app/app.tsx +++ b/src/app/app.tsx @@ -1,8 +1,6 @@ import * as React from 'react'; -import {AI} from './ai.js'; -import {Chat} from './chat.js'; -import {Header} from './header.js'; -import {Welcome} from './welcome.js'; +import {AI} from './actions.js'; +import Page from './page.js'; export function App(): JSX.Element { return ( @@ -14,19 +12,14 @@ export function App(): JSX.Element { -
-
- - - - - -
+ + + ); diff --git a/src/app/chat-message.tsx b/src/app/chat-message.tsx deleted file mode 100644 index a16e650..0000000 --- a/src/app/chat-message.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import {clsx} from 'clsx'; -import * as React from 'react'; - -export type ChatMessageProps = React.PropsWithChildren<{ - readonly role: 'assistant' | 'user' | 'error'; -}>; - -export function ChatMessage({ - children, - role, -}: ChatMessageProps): React.ReactNode { - return ( -
- {children} -
- ); -} diff --git a/src/app/chat.tsx b/src/app/chat.tsx deleted file mode 100644 index 2e32799..0000000 --- a/src/app/chat.tsx +++ /dev/null @@ -1,117 +0,0 @@ -'use client'; - -import {useActions, useUIState} from 'ai/rsc'; -import * as React from 'react'; -import Textarea from 'react-textarea-autosize'; -import type {AI} from './ai.js'; -import {ChatMessage} from './chat-message.js'; -import {getErrorMessage} from './get-error-message.js'; -import {LoadingIndicator} from './loading-indicator.js'; -import {useEnterSubmit} from './use-enter-submit.js'; - -export function Chat({children}: React.PropsWithChildren): React.ReactNode { - const textareaRef = React.useRef(null); - const [inputValue, setInputValue] = React.useState(``); - const [isPending, startTransition] = React.useTransition(); - const [messages, setMessages] = useUIState(); - const {submitUserMessage} = useActions(); - const {formRef, handleKeyDown} = useEnterSubmit(); - - const [optimisticMessages, setOptimisticMessages] = - React.useOptimistic(messages); - - const handleSubmit = ( - event: React.SyntheticEvent, - ) => { - event.preventDefault(); - - const {submitter} = event.nativeEvent; - - const examplePrompt = - submitter instanceof HTMLButtonElement && - submitter.name === `example-prompt` - ? submitter.value - : undefined; - - if (examplePrompt && textareaRef.current) { - setInputValue(examplePrompt); - } - - const userInput = examplePrompt ?? inputValue; - - if (!userInput || isPending) { - return; - } - - setMessages((prevMessages) => [ - ...prevMessages, - {id: Date.now(), role: `user`, display:
{userInput}
}, - ]); - - setInputValue(``); - document.body.scrollIntoView({block: `end`, behavior: `smooth`}); - - startTransition(async () => { - setOptimisticMessages((prevMessages) => [ - ...prevMessages, - {id: 0, role: `assistant`, display: }, - ]); - - try { - const message = await submitUserMessage({ - action: `message`, - content: userInput, - }); - - setMessages((prevMessages) => [...prevMessages, message]); - } catch (error) { - console.error(error); - const errorMessage = getErrorMessage(error); - - setMessages((prevMessages) => [ - ...prevMessages, - {id: Date.now(), role: `error`, display:

{errorMessage}

}, - ]); - } - - textareaRef.current?.focus(); - }); - }; - - return ( -
- {optimisticMessages.length === 0 && children} - - {optimisticMessages.map((message) => ( - - {message.display} - - ))} - -
-
-