diff --git a/package-lock.json b/package-lock.json index f7931b0..3174d20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,16 +9,17 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@ai-sdk/openai": "^0.0.9", "@mfng/core": "^4.1.2", "@upstash/ratelimit": "^1.0.1", "@upstash/redis": "^1.28.4", - "ai": "^3.0.13", + "ai": "^3.1.1", "clsx": "^1.2.1", - "openai": "^4.29.0", - "react": "^19.0.0-canary-7a2609eed-20240403", - "react-dom": "^19.0.0-canary-7a2609eed-20240403", + "openai": "^4.40.1", + "react": "0.0.0-experimental-73bcdfbae5-20240502", + "react-dom": "0.0.0-experimental-73bcdfbae5-20240502", "react-markdown": "^9.0.1", - "react-server-dom-webpack": "^19.0.0-canary-7a2609eed-20240403", + "react-server-dom-webpack": "0.0.0-experimental-73bcdfbae5-20240502", "react-textarea-autosize": "^8.5.3", "server-only": "^0.0.1", "zod": "^3.22.4" @@ -76,6 +77,59 @@ "node": ">=0.10.0" } }, + "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==", + "dependencies": { + "@ai-sdk/provider": "0.0.3", + "@ai-sdk/provider-utils": "0.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==", + "dependencies": { + "json-schema": "0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "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==", + "dependencies": { + "@ai-sdk/provider": "0.0.3", + "eventsource-parser": "1.1.2", + "nanoid": "3.3.6", + "secure-json-parse": "2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "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", @@ -1463,9 +1517,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.11.28", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz", - "integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==", + "version": "20.12.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.8.tgz", + "integrity": "sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==", "dependencies": { "undici-types": "~5.26.4" } @@ -2108,22 +2162,26 @@ } }, "node_modules/ai": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/ai/-/ai-3.0.13.tgz", - "integrity": "sha512-fDrYnVTdMJuS/qYUq0T/CX3WDuTfcZFie9LkgnoQ2layfUG2Wzh/mpfkfYXFEq/mqnpep3xUtECOB1weyyvwUg==", - "dependencies": { - "eventsource-parser": "1.0.0", - "jsondiffpatch": "^0.6.0", + "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", + "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.4" + "zod-to-json-schema": "3.22.5" }, "engines": { - "node": ">=14.6" + "node": ">=18" }, "peerDependencies": { "react": "^18.2.0", @@ -2151,15 +2209,15 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -2726,11 +2784,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/base-64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", - "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" - }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -2926,14 +2979,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", - "engines": { - "node": "*" - } - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -3195,14 +3240,6 @@ "node": ">= 8" } }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", - "engines": { - "node": "*" - } - }, "node_modules/crypto-js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", @@ -3538,15 +3575,6 @@ "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" }, - "node_modules/digest-fetch": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", - "integrity": "sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==", - "dependencies": { - "base-64": "^0.1.0", - "md5": "^2.3.0" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -4247,9 +4275,9 @@ } }, "node_modules/eventsource-parser": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.0.0.tgz", - "integrity": "sha512-9jgfSCa3dmEme2ES3mPByGXfgZ87VbP97tng1G2nWwWx6bV2nYxm2AWCrbQjXToSe+yYlqaZNtxffR9IeQr95g==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.1.2.tgz", + "integrity": "sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==", "engines": { "node": ">=14.18" } @@ -4932,11 +4960,6 @@ "node": ">=8" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "node_modules/is-core-module": { "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", @@ -5162,6 +5185,11 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -5328,16 +5356,6 @@ "yallist": "^3.0.2" } }, - "node_modules/md5": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", - "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", - "dependencies": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "~1.1.6" - } - }, "node_modules/mdast-util-from-markdown": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", @@ -6553,15 +6571,14 @@ } }, "node_modules/openai": { - "version": "4.29.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.29.0.tgz", - "integrity": "sha512-ic6C681bSow1XQdKhADthM/OOKqNL05M1gCFLx1mRqLJ+yH49v6qnvaWQ76kwqI/IieCuVTXfRfTk3sz4cB45w==", + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.40.1.tgz", + "integrity": "sha512-mS7LerF4fY1/we0aKGGwIWtosTJFLKuNbBWMBR/G1TAZUHoktAdod0dqIrlQvSD39uS6jNEEbT7jRsXmzfEPBw==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", - "digest-fetch": "^1.3.0", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7", @@ -6572,9 +6589,9 @@ } }, "node_modules/openai/node_modules/@types/node": { - "version": "18.19.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.24.tgz", - "integrity": "sha512-eghAz3gnbQbvnHqB+mgB2ZR3aH6RhdEmHGS48BnV75KceQPHqabkxKI0BbUSsqhqy2Ddhc2xD/VAR9ySZd57Lw==", + "version": "18.19.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", + "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", "dependencies": { "undici-types": "~5.26.4" } @@ -6717,12 +6734,12 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "dev": true, "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", + "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { @@ -6733,9 +6750,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -7677,22 +7694,22 @@ } }, "node_modules/react": { - "version": "19.0.0-canary-7a2609eed-20240403", - "resolved": "https://registry.npmjs.org/react/-/react-19.0.0-canary-7a2609eed-20240403.tgz", - "integrity": "sha512-v3YYaKzyYTki2NbM5Xs/1XPy/XRGtC2ljiqL97Zgo0Iu3jBTsH0k8pJ3h2gFP8F6hudik32mb3l4fG4GfVKieA==", + "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==", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.0.0-canary-7a2609eed-20240403", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0-canary-7a2609eed-20240403.tgz", - "integrity": "sha512-8bn+CmtnyFNFBOATBwmQRm/6G8iu2/RT0AYoTJZNPLof7MggHPHh9USpbEqEozc3M/KnDC7ebR21q9E6GEQX0A==", + "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==", "dependencies": { - "scheduler": "0.25.0-canary-7a2609eed-20240403" + "scheduler": "0.0.0-experimental-73bcdfbae5-20240502" }, "peerDependencies": { - "react": "19.0.0-canary-7a2609eed-20240403" + "react": "0.0.0-experimental-73bcdfbae5-20240502" } }, "node_modules/react-markdown": { @@ -7721,9 +7738,9 @@ } }, "node_modules/react-server-dom-webpack": { - "version": "19.0.0-canary-7a2609eed-20240403", - "resolved": "https://registry.npmjs.org/react-server-dom-webpack/-/react-server-dom-webpack-19.0.0-canary-7a2609eed-20240403.tgz", - "integrity": "sha512-1PkUQ1BwYd5GfYRL4taJ0QgzENZTjcbcnJAcUVtNWIrjmkF792h/w12NiJ1frCa346EYlGjJ4VVaaDKiMHbeug==", + "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==", "dependencies": { "acorn-loose": "^8.3.0", "neo-async": "^2.6.1" @@ -7732,8 +7749,8 @@ "node": ">=0.10.0" }, "peerDependencies": { - "react": "19.0.0-canary-7a2609eed-20240403", - "react-dom": "19.0.0-canary-7a2609eed-20240403", + "react": "0.0.0-experimental-73bcdfbae5-20240502", + "react-dom": "0.0.0-experimental-73bcdfbae5-20240502", "webpack": "^5.59.0" } }, @@ -8082,9 +8099,9 @@ "dev": true }, "node_modules/scheduler": { - "version": "0.25.0-canary-7a2609eed-20240403", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-canary-7a2609eed-20240403.tgz", - "integrity": "sha512-c2LhVLIPFxw4/jY0ImVp+fsP70gak7wFm93DzHDW7c0ifaXwixShs63VjblRLhsjAmRFQeBWKyOAHCAY44XAgw==" + "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==" }, "node_modules/schema-utils": { "version": "4.2.0", @@ -8105,6 +8122,11 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -8448,16 +8470,16 @@ } }, "node_modules/sucrase/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", + "jackspeak": "^2.3.6", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -9247,9 +9269,9 @@ } }, "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } @@ -9754,9 +9776,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", - "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", "dev": true, "bin": { "yaml": "bin.mjs" @@ -9786,9 +9808,9 @@ } }, "node_modules/zod-to-json-schema": { - "version": "3.22.4", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.4.tgz", - "integrity": "sha512-2Ed5dJ+n/O3cU383xSY28cuVi0BCQhF8nYqWU5paEpl7fVdqdAmiLdqLyfblbNdfOFwFfi/mqU4O1pwc60iBhQ==", + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.5.tgz", + "integrity": "sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q==", "peerDependencies": { "zod": "^3.22.4" } diff --git a/package.json b/package.json index 994ebc3..21bff60 100644 --- a/package.json +++ b/package.json @@ -26,16 +26,17 @@ "watch:dev": "webpack --mode development --watch" }, "dependencies": { + "@ai-sdk/openai": "^0.0.9", "@mfng/core": "^4.1.2", "@upstash/ratelimit": "^1.0.1", "@upstash/redis": "^1.28.4", - "ai": "^3.0.13", + "ai": "^3.1.1", "clsx": "^1.2.1", - "openai": "^4.29.0", - "react": "^19.0.0-canary-7a2609eed-20240403", - "react-dom": "^19.0.0-canary-7a2609eed-20240403", + "openai": "^4.40.1", + "react": "0.0.0-experimental-73bcdfbae5-20240502", + "react-dom": "0.0.0-experimental-73bcdfbae5-20240502", "react-markdown": "^9.0.1", - "react-server-dom-webpack": "^19.0.0-canary-7a2609eed-20240403", + "react-server-dom-webpack": "0.0.0-experimental-73bcdfbae5-20240502", "react-textarea-autosize": "^8.5.3", "server-only": "^0.0.1", "zod": "^3.22.4" diff --git a/src/app/ai-state.ts b/src/app/ai-state.ts index 286039e..a98aaf5 100644 --- a/src/app/ai-state.ts +++ b/src/app/ai-state.ts @@ -1,13 +1,4 @@ -export type AIStateItem = - | { - readonly role: 'user' | 'assistant' | 'system'; - readonly content: string; - } - | { - readonly role: 'function'; - readonly content: string; - readonly name: string; - }; +import type {CoreMessage} from 'ai'; export type UserInputAction = 'choose-option' | 'message' | 'select-image'; @@ -16,7 +7,7 @@ export interface UserInput { readonly content: string; } -export function fromUserInput(userInput: UserInput): AIStateItem { +export function fromUserInput(userInput: UserInput): CoreMessage { const {action, content} = userInput; if (action === `message`) { @@ -24,19 +15,19 @@ export function fromUserInput(userInput: UserInput): AIStateItem { } return { - role: `assistant`, - content: getAssistantStateContent(action, content), + role: `user`, + content: getUserActionContent(action, content), }; } -function getAssistantStateContent( +function getUserActionContent( action: 'choose-option' | 'select-image', content: string, ): string { switch (action) { case `choose-option`: - return `[user has chosen: ${content}]`; + return `I choose: ${content}`; case `select-image`: - return `[user wants to know more about the image ${content}. keep it short.]`; + 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 index 0266df5..46cea10 100644 --- a/src/app/ai.tsx +++ b/src/app/ai.tsx @@ -1,6 +1,6 @@ +import type {CoreMessage} from 'ai'; import {createAI} from 'ai/rsc'; import type * as React from 'react'; -import type {AIStateItem} from './ai-state.js'; import {submitUserMessage} from './submit-user-message.js'; export interface UIStateItem { @@ -9,7 +9,7 @@ export interface UIStateItem { readonly display: React.ReactNode; } -const initialAIState: AIStateItem[] = []; +const initialAIState: CoreMessage[] = []; const initialUIState: UIStateItem[] = []; export const AI = createAI({ diff --git a/src/app/submit-user-message.tsx b/src/app/submit-user-message.tsx index f1c2d7c..01c5a99 100644 --- a/src/app/submit-user-message.tsx +++ b/src/app/submit-user-message.tsx @@ -1,7 +1,8 @@ 'use server'; -import {getMutableAIState, render} from 'ai/rsc'; -import {OpenAI} from 'openai'; +import {createOpenAI} from '@ai-sdk/openai'; +import type {AssistantContent} from 'ai'; +import {getMutableAIState, streamUI} from 'ai/rsc'; import * as React from 'react'; import {z} from 'zod'; import {type UserInput, fromUserInput} from './ai-state.js'; @@ -12,9 +13,6 @@ import {LoadingIndicator} from './loading-indicator.js'; import {Markdown} from './markdown.js'; import {UserChoiceButton} from './user-choice-button.js'; -const openai = new OpenAI({apiKey: process.env.OPENAI_API_KEY}); - -// eslint-disable-next-line @typescript-eslint/require-await export async function submitUserMessage( userInput: UserInput, ): Promise { @@ -24,38 +22,32 @@ export async function submitUserMessage( let lastTextContent: string | undefined; - const ui = render({ - model: `gpt-4-turbo-preview`, - provider: openai, + const ui = await streamUI({ + model: createOpenAI({baseURL: process.env.OPENAI_BASE_URL})(`gpt-4-turbo`), initial: , - messages: [ - { - role: `system`, - content: `You are a chat assistant with a focus on images (photos, paintings, cliparts, animated gifs, etc.). + system: `You are a chat assistant with a focus on images (photos, paintings, cliparts, animated gifs, etc.). - A user might ask for images of any kind (only safe for work, though!) and you search for them and show them, using the input of the user for the various search parameters. + A user might ask for images of any kind (only safe for work, though!) and you search for them and show them, using the input of the user for the various search parameters. - Always prefer to show specific titled art pieces. If in doubt, just pick some that you know. + Always prefer to show specific titled art pieces. If in doubt, just pick some that you know. - When it comes to art, try to show known images to the user with their title. Think about it step by step to come up with specific search queries. E.g. first select a style, then select an artist for that style, and then search for the specific painting (e.g. surrealism -> Dalí -> The Persistence of Memory -> query terms: ["Salvador Dalí", "The Persistence of Memory"]). Do this process a couple of times to come up with a diverse set of images in one single message. + When it comes to art, try to show known images to the user with their title. Think about it step by step to come up with specific search queries. E.g. first select a style, then select an artist for that style, and then search for the specific painting (e.g. surrealism -> Dalí -> The Persistence of Memory -> query terms: ["Salvador Dalí", "The Persistence of Memory"]). Do this process a couple of times to come up with a diverse set of images in one single message. - Use markdown in your messages if it improves how you can structure a response, highlight certain parts (especially the discussed subject's name/title should be strong), or to add links to other websites. + Use markdown in your messages if it improves how you can structure a response, highlight certain parts (especially the discussed subject's name/title should be strong), or to add links to other websites. - Don't include images in markdown, use the dedicated tool instead. + Don't include images in markdown, use the dedicated tool instead. - Never ask the user whether they want to see images of the discussed subject, always show them unprompted. + Never ask the user whether they want to see images of the discussed subject, always show them unprompted. - Before showing images of a certain artist it might make sense to introduce them to the user first, with a couple of words. + Before showing images of a certain artist it might make sense to introduce them to the user first, with a couple of words. - The user can also select an image if they want to know more about it. + The user can also select an image if they want to know more about it. - When asking the user a question, you may present them with options to choose from. + When asking the user a question, you may present them with options to choose from. - Use the provided tools to show an interactive UI, along with your textual messages. - `, - }, - ...aiState.get(), - ], + Use the provided tools to show an interactive UI, along with your textual messages. + `, + messages: aiState.get(), text: ({content, done}) => { lastTextContent = content; @@ -88,22 +80,33 @@ export async function submitUserMessage( }), ), }), - render({intro, options}) { + generate({intro, options}, {toolName, toolCallId}) { console.log(`get_choice_from_user`, options); + const assistentContent: AssistantContent = [ + { + type: `tool-call`, + args: {intro, options}, + toolName, + toolCallId, + }, + ]; + if (lastTextContent) { - aiState.update((prevAiState) => [ - ...prevAiState, - {role: `assistant`, content: lastTextContent!}, - ]); + assistentContent.unshift({type: `text`, text: lastTextContent}); } aiState.done([ ...aiState.get(), { - role: `function`, - name: `get_choice_from_user`, - content: JSON.stringify({options}), + role: `assistant`, + content: assistentContent, + }, + { + role: `tool`, + content: [ + {type: `tool-result`, toolName, toolCallId, result: {options}}, + ], }, ]); @@ -168,7 +171,7 @@ export async function submitUserMessage( ) .describe(`Use multiple sets of search parameters if needed.`), }), - async *render({loadingText, searches}) { + async *generate({loadingText, searches}, {toolName, toolCallId}) { console.log(`search_and_show_images`, searches); const text = lastTextContent ? ( @@ -184,13 +187,24 @@ export async function submitUserMessage( ); + const assistentContent: AssistantContent = [ + { + type: `tool-call`, + args: {loadingText, searches}, + toolName, + toolCallId, + }, + ]; + if (lastTextContent) { - aiState.update((prevAiState) => [ - ...prevAiState, - {role: `assistant`, content: lastTextContent!}, - ]); + assistentContent.unshift({type: `text`, text: lastTextContent}); } + aiState.update((prevAiState) => [ + ...prevAiState, + {role: `assistant`, content: assistentContent}, + ]); + const elementsWithData = searches.map( ({title, notFoundMessage, errorMessage, searchParams}) => { let resolveDataPromise: (data: unknown) => void; @@ -225,15 +239,16 @@ export async function submitUserMessage( yield finalUi; const dataItems = await Promise.all( - elementsWithData.map(async ({dataPromise}) => dataPromise), + elementsWithData.map(({dataPromise}) => dataPromise), ); aiState.done([ ...aiState.get(), { - role: `function`, - name: `search_and_show_images`, - content: JSON.stringify(dataItems), + role: `tool`, + content: [ + {type: `tool-result`, toolName, toolCallId, result: dataItems}, + ], }, ]); @@ -243,5 +258,5 @@ export async function submitUserMessage( }, }); - return {id: Date.now(), role: `assistant`, display: ui}; + return {id: Date.now(), role: `assistant`, display: ui.value}; }