diff --git a/py-langchain/README.md b/py-langchain/README.md index 112ebea..7a4375e 100644 --- a/py-langchain/README.md +++ b/py-langchain/README.md @@ -35,7 +35,7 @@ Next, you'll need to set up environment variables in your repo's `.env` file. Co To start with the basic examples, you'll just need to add your OpenAI API key and Auth0 credentials. - To start with the examples, you'll just need to add your OpenAI API key and Auth0 credentials for the Web app. - - You can setup a new Auth0 tenant with an Auth0 Web App and Token Vault following the Prerequisites instructions [here](https://auth0.com/ai/docs/call-others-apis-on-users-behalf). + - You can set up a new Auth0 tenant with an Auth0 Web App and Token Vault following the Prerequisites instructions [here](https://auth0.com/ai/docs/get-started/call-others-apis-on-users-behalf). - An Auth0 FGA account, you can create one [here](https://dashboard.fga.dev). Add the FGA store ID, client ID, client secret, and API URL to the `.env` file. Next, install the required packages using your preferred package manager, e.g. uv: diff --git a/py-langchain/backend/README.md b/py-langchain/backend/README.md index 7a6421c..de0922f 100644 --- a/py-langchain/backend/README.md +++ b/py-langchain/backend/README.md @@ -9,7 +9,7 @@ You'll need to set up environment variables in your repo's `.env` file. Copy the To start with the basic examples, you'll just need to add your OpenAI API key and Auth0 credentials. - To start with the examples, you'll just need to add your OpenAI API key and Auth0 credentials for the Web app. - - You can setup a new Auth0 tenant with an Auth0 Web App and Token Vault following the Prerequisites instructions [here](https://auth0.com/ai/docs/call-others-apis-on-users-behalf). + - You can set up a new Auth0 tenant with an Auth0 Web App and Token Vault following the Prerequisites instructions [here](https://auth0.com/ai/docs/get-started/call-others-apis-on-users-behalf). - An Auth0 FGA account, you can create one [here](https://dashboard.fga.dev). Add the FGA store ID, client ID, client secret, and API URL to the `.env` file. Next, install the required packages using your preferred package manager, e.g. uv: diff --git a/py-langchain/frontend/package-lock.json b/py-langchain/frontend/package-lock.json index eafc600..8399dfc 100644 --- a/py-langchain/frontend/package-lock.json +++ b/py-langchain/frontend/package-lock.json @@ -8,7 +8,7 @@ "name": "frontend", "version": "0.0.0", "dependencies": { - "@auth0/ai": "^5.0.1", + "@auth0/ai": "^5.1.1", "@langchain/core": "^0.3.66", "@langchain/langgraph-sdk": "^0.0.109", "@radix-ui/react-avatar": "^1.1.10", @@ -55,9 +55,9 @@ } }, "node_modules/@auth0/ai": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@auth0/ai/-/ai-5.0.1.tgz", - "integrity": "sha512-l5lGBOlV6nRBPsevIZli0GGAjfQwrwhCFp0NvK3RcGmwbzOqua2gDvulhr6JHIAF3LFi2xcyq4/GY3l7btxzfQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@auth0/ai/-/ai-5.1.1.tgz", + "integrity": "sha512-KxemZNtL3+nMm0EQpqs2AGJsQIOVcJm7XkJqP1OvkxioqRiyTjj8psNfidTK0xn9Y9s3Yps8gdAAu1J8R02wlQ==", "license": "Apache-2.0", "dependencies": { "@openfga/sdk": "^0.8.0", @@ -2997,9 +2997,9 @@ "license": "MIT" }, "node_modules/auth0": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/auth0/-/auth0-4.33.0.tgz", - "integrity": "sha512-+zRMFXakIpKudDJKGzwlsYp6LC91J9w7hMz9k9d/qRmGbfqkJeqp3wPmKV7GqAcprfUr9fWCJH3XFFxzJV2jow==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/auth0/-/auth0-4.36.0.tgz", + "integrity": "sha512-n/eqshTNXY9HY+KaHbxLNHr5iOqg4PztMczNQXOIrHcyUsi6zB6uQphP25tbKiy7+A1pwgX/ZkAOnTzFUoBroA==", "license": "MIT", "dependencies": { "jose": "^4.13.2", @@ -5647,9 +5647,9 @@ } }, "node_modules/openid-client/node_modules/jose": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.0.tgz", - "integrity": "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.2.tgz", + "integrity": "sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" diff --git a/py-langchain/frontend/package.json b/py-langchain/frontend/package.json index 7b8153d..bc2d8df 100644 --- a/py-langchain/frontend/package.json +++ b/py-langchain/frontend/package.json @@ -10,7 +10,7 @@ "preview": "vite preview" }, "dependencies": { - "@auth0/ai": "^5.0.1", + "@auth0/ai": "^5.1.1", "@langchain/core": "^0.3.66", "@langchain/langgraph-sdk": "^0.0.109", "@radix-ui/react-avatar": "^1.1.10", diff --git a/py-langchain/frontend/src/components/auth0-ai/TokenVault/TokenVaultInterruptHandler.tsx b/py-langchain/frontend/src/components/TokenVaultInterruptHandler.tsx similarity index 100% rename from py-langchain/frontend/src/components/auth0-ai/TokenVault/TokenVaultInterruptHandler.tsx rename to py-langchain/frontend/src/components/TokenVaultInterruptHandler.tsx diff --git a/py-langchain/frontend/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx b/py-langchain/frontend/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx index 900339a..59fbad1 100644 --- a/py-langchain/frontend/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx +++ b/py-langchain/frontend/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx @@ -2,7 +2,8 @@ import type { ReactNode } from "react"; /** - * Defines the mode the EnsureAPIAccess component will use to prompt the user to authorize the API access. + * Defines the mode the TokenVaultConsent component will use to prompt the user to connect a third-party account and + * authorize the API access. * - `redirect` will redirect the user to the provider's authorization page. * - `popup` will open a popup window to prompt the user to authorize the API access. * - `auto` will automatically choose the best mode based on the user's device and browser. @@ -13,10 +14,11 @@ export type TokenVaultAuthProps = { interrupt: { connection: string; requiredScopes: string[]; + authorizationParams?: Record; resume?: () => void; }; auth?: { - authorizePath?: string; + connectPath?: string; returnTo?: string; }; onFinish?: () => void; diff --git a/py-langchain/frontend/src/components/auth0-ai/TokenVault/index.tsx b/py-langchain/frontend/src/components/auth0-ai/TokenVault/index.tsx index dd3e0c2..2be72b9 100644 --- a/py-langchain/frontend/src/components/auth0-ai/TokenVault/index.tsx +++ b/py-langchain/frontend/src/components/auth0-ai/TokenVault/index.tsx @@ -1,8 +1,8 @@ import { BrowserView, MobileView } from "react-device-detect"; -import type { TokenVaultAuthProps } from "./TokenVaultAuthProps"; import { TokenVaultConsentPopup } from "./popup"; import { TokenVaultConsentRedirect } from "./redirect"; +import type { TokenVaultAuthProps } from "./TokenVaultAuthProps"; export function TokenVaultConsent(props: TokenVaultAuthProps) { const { mode } = props; diff --git a/py-langchain/frontend/src/components/auth0-ai/TokenVault/popup.tsx b/py-langchain/frontend/src/components/auth0-ai/TokenVault/popup.tsx index aeab8d5..debdc07 100644 --- a/py-langchain/frontend/src/components/auth0-ai/TokenVault/popup.tsx +++ b/py-langchain/frontend/src/components/auth0-ai/TokenVault/popup.tsx @@ -4,12 +4,13 @@ import { useCallback, useEffect, useState } from "react"; import { WaitingMessage } from "../util/loader"; import { PromptUserContainer } from "../util/prompt-user-container"; + import type { TokenVaultAuthProps } from "./TokenVaultAuthProps"; export function TokenVaultConsentPopup({ - interrupt: { connection, requiredScopes, resume }, + interrupt: { connection, requiredScopes, authorizationParams, resume }, connectWidget: { icon, title, description, action, containerClassName }, - auth: { authorizePath = "/auth/login", returnTo = "/close" } = {}, + auth: { connectPath = "/auth/connect", returnTo = "/close" } = {}, onFinish, }: TokenVaultAuthProps) { const [isLoading, setIsLoading] = useState(false); @@ -43,14 +44,17 @@ export function TokenVaultConsentPopup({ //Open the login popup const startLoginPopup = useCallback(async () => { const search = new URLSearchParams({ - returnTo, connection, - access_type: "offline", - prompt: "consent", - connection_scope: requiredScopes.join(), + returnTo, + // Add all extra authorization parameters to the search params, they will be collected and submitted via the + // authorization_params parameter of the connect account flow. + ...authorizationParams, }); + for (const requiredScope of requiredScopes) { + search.append("scopes", requiredScope); + } - const url = new URL(authorizePath, window.location.origin); + const url = new URL(connectPath, window.location.origin); url.search = search.toString(); const windowFeatures = @@ -63,7 +67,7 @@ export function TokenVaultConsentPopup({ setLoginPopup(popup); setIsLoading(true); } - }, [connection, requiredScopes, returnTo, authorizePath]); + }, [connection, requiredScopes, returnTo, authorizationParams, connectPath]); if (isLoading) { return ; diff --git a/py-langchain/frontend/src/components/auth0-ai/TokenVault/redirect.tsx b/py-langchain/frontend/src/components/auth0-ai/TokenVault/redirect.tsx index a92d92f..4737cb4 100644 --- a/py-langchain/frontend/src/components/auth0-ai/TokenVault/redirect.tsx +++ b/py-langchain/frontend/src/components/auth0-ai/TokenVault/redirect.tsx @@ -1,13 +1,14 @@ "use client"; import { PromptUserContainer } from "../util/prompt-user-container"; + import type { TokenVaultAuthProps } from "./TokenVaultAuthProps"; export function TokenVaultConsentRedirect({ - interrupt: { requiredScopes, connection }, + interrupt: { connection, requiredScopes, authorizationParams }, connectWidget: { icon, title, description, action, containerClassName }, auth: { - authorizePath = "/auth/login", + connectPath = "/auth/connect", returnTo = window.location.pathname, } = {}, }: TokenVaultAuthProps) { @@ -21,13 +22,17 @@ export function TokenVaultConsentRedirect({ label: action?.label ?? "Connect", onClick: () => { const search = new URLSearchParams({ - returnTo, connection, - access_type: "offline", - connection_scope: requiredScopes.join(), + returnTo, + // Add all extra authorization parameters to the search params, they will be collected and submitted via the + // authorization_params parameter of the connect account flow. + ...authorizationParams, }); + for (const requiredScope of requiredScopes) { + search.append("scopes", requiredScope); + } - const url = new URL(authorizePath, window.location.origin); + const url = new URL(connectPath, window.location.origin); url.search = search.toString(); // Redirect to the authorization page diff --git a/py-langchain/frontend/src/components/chat-window.tsx b/py-langchain/frontend/src/components/chat-window.tsx index a3dc59f..44d602e 100644 --- a/py-langchain/frontend/src/components/chat-window.tsx +++ b/py-langchain/frontend/src/components/chat-window.tsx @@ -8,7 +8,7 @@ import { useStream } from "@langchain/langgraph-sdk/react"; import { type Message } from "@langchain/langgraph-sdk"; import { ChatMessageBubble } from "@/components/chat-message-bubble"; -import { TokenVaultInterruptHandler } from "@/components/auth0-ai/TokenVault/TokenVaultInterruptHandler"; +import { TokenVaultInterruptHandler } from "@/components/TokenVaultInterruptHandler"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { getLoginUrl } from "@/lib/use-auth"; diff --git a/scripts/update_packages.sh b/scripts/update_packages.sh new file mode 100755 index 0000000..97c0738 --- /dev/null +++ b/scripts/update_packages.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +# Script to update @auth0/ai packages to their latest versions +# Usage: ./update_packages.sh + +set -e + +# Define the versions +AUTH0_SPA_JS_VERSION="^2.9.0" +AUTH0_NEXTJS_VERSION="^4.13.0" +AUTH0_AI_VERSION="^5.1.1" +AUTH0_AI_VERCEL_VERSION="^4.1.0" +AUTH0_AI_LANGCHAIN_VERSION="^4.1.0" +AUTH0_AI_LLAMAINDEX_VERSION="^4.1.0" + +REGISTRY="--registry https://registry.npmjs.org/" + +echo "Starting package updates..." + +# Function to update a package.json file and reinstall packages +update_package_json() { + local file="$1" + local updated=false + + echo "Checking $file..." + + if grep -q '"@auth0/auth0-spa-js"' "$file"; then + echo " Updating @auth0/auth0-spa-js to $AUTH0_SPA_JS_VERSION" + sed -i '' 's/"@auth0\/auth0-spa-js": "[^"]*"/"@auth0\/auth0-spa-js": "'$AUTH0_SPA_JS_VERSION'"/g' "$file" + updated=true + fi + + if grep -q '"@auth0/nextjs-auth0"' "$file"; then + echo " Updating @auth0/nextjs-auth0 to $AUTH0_NEXTJS_VERSION" + sed -i '' 's/"@auth0\/nextjs-auth0": "[^"]*"/"@auth0\/nextjs-auth0": "'$AUTH0_NEXTJS_VERSION'"/g' "$file" + updated=true + fi + + if grep -q '"@auth0/ai"' "$file"; then + echo " Updating @auth0/ai to $AUTH0_AI_VERSION" + sed -i '' 's/"@auth0\/ai": "[^"]*"/"@auth0\/ai": "'$AUTH0_AI_VERSION'"/g' "$file" + updated=true + fi + + if grep -q '"@auth0/ai-vercel"' "$file"; then + echo " Updating @auth0/ai-vercel to $AUTH0_AI_VERCEL_VERSION" + sed -i '' 's/"@auth0\/ai-vercel": "[^"]*"/"@auth0\/ai-vercel": "'$AUTH0_AI_VERCEL_VERSION'"/g' "$file" + updated=true + fi + + if grep -q '"@auth0/ai-langchain"' "$file"; then + echo " Updating @auth0/ai-langchain to $AUTH0_AI_LANGCHAIN_VERSION" + sed -i '' 's/"@auth0\/ai-langchain": "[^"]*"/"@auth0\/ai-langchain": "'$AUTH0_AI_LANGCHAIN_VERSION'"/g' "$file" + updated=true + fi + + if grep -q '"@auth0/ai-llamaindex"' "$file"; then + echo " Updating @auth0/ai-llamaindex to $AUTH0_AI_LLAMAINDEX_VERSION" + sed -i '' 's/"@auth0\/ai-llamaindex": "[^"]*"/"@auth0\/ai-llamaindex": "'$AUTH0_AI_LLAMAINDEX_VERSION'"/g' "$file" + updated=true + fi + + if [ "$updated" = true ]; then + echo " Updated $file" + dir=$(dirname "$file") + + # Simple approach: collect all @auth0 packages, uninstall them, then reinstall + packages_to_uninstall="" + packages_to_reinstall="" + + if grep -q '"@auth0/auth0-spa-js":' "$file"; then + packages_to_uninstall="$packages_to_uninstall @auth0/auth0-spa-js" + packages_to_reinstall="$packages_to_reinstall @auth0/auth0-spa-js@$AUTH0_SPA_JS_VERSION" + fi + + if grep -q '"@auth0/nextjs-auth0":' "$file"; then + packages_to_uninstall="$packages_to_uninstall @auth0/nextjs-auth0" + packages_to_reinstall="$packages_to_reinstall @auth0/nextjs-auth0@$AUTH0_NEXTJS_VERSION" + fi + + if grep -q '"@auth0/ai":' "$file"; then + packages_to_uninstall="$packages_to_uninstall @auth0/ai" + packages_to_reinstall="$packages_to_reinstall @auth0/ai@$AUTH0_AI_VERSION" + fi + + if grep -q '"@auth0/ai-vercel":' "$file"; then + packages_to_uninstall="$packages_to_uninstall @auth0/ai-vercel" + packages_to_reinstall="$packages_to_reinstall @auth0/ai-vercel@$AUTH0_AI_VERCEL_VERSION" + fi + + if grep -q '"@auth0/ai-langchain":' "$file"; then + packages_to_uninstall="$packages_to_uninstall @auth0/ai-langchain" + packages_to_reinstall="$packages_to_reinstall @auth0/ai-langchain@$AUTH0_AI_LANGCHAIN_VERSION" + fi + + if grep -q '"@auth0/ai-llamaindex":' "$file"; then + packages_to_uninstall="$packages_to_uninstall @auth0/ai-llamaindex" + packages_to_reinstall="$packages_to_reinstall @auth0/ai-llamaindex@$AUTH0_AI_LLAMAINDEX_VERSION" + fi + + # Uninstall all @auth0 packages at once + if [ -n "$packages_to_uninstall" ]; then + echo " Uninstalling:$packages_to_uninstall" + (cd "$dir" && npm uninstall$packages_to_uninstall 2>/dev/null || true) + fi + + # Reinstall all @auth0 packages at once + if [ -n "$packages_to_reinstall" ]; then + echo " Reinstalling:$packages_to_reinstall" + (cd "$dir" && npm install$packages_to_reinstall $REGISTRY) + fi + fi +} + +# Find all package.json files and update them +find . -name "package.json" -type f -not -path "*/node_modules/*" | while read -r file; do + if grep -q '@auth0/ai' "$file"; then + update_package_json "$file" + fi +done + +echo "Package updates completed!" diff --git a/ts-langchain/.env.example b/ts-langchain/.env.example index 10fcfbb..bbdf1ed 100644 --- a/ts-langchain/.env.example +++ b/ts-langchain/.env.example @@ -12,12 +12,12 @@ AUTH0_CLIENT_ID="{yourClientId}" AUTH0_CLIENT_SECRET="{yourClientSecret}" # Use your SHOP_API_AUDIENCE or a separate LangGraph API audience AUTH0_AUDIENCE="https://your.domain.us.langgraph.app" -AUTH0_SCOPE="openid profile email" +AUTH0_SCOPE="openid profile email offline_access" AUTH0_CUSTOM_API_CLIENT_ID="{yourCustomApiClientId}" AUTH0_CUSTOM_API_CLIENT_SECRET="{yourCustomApiClientSecret}" # Database configuration -DATABASE_URL="postgresql://postgres:postgres@localhost:5432/ai_documents_db" +DATABASE_URL="postgresql://postgres:postgres@localhost:5432/ai_documents_db" # Auth0 FGA FGA_STORE_ID= diff --git a/ts-langchain/README.md b/ts-langchain/README.md index 693c62e..c1b481d 100644 --- a/ts-langchain/README.md +++ b/ts-langchain/README.md @@ -32,7 +32,7 @@ Next, you'll need to set up environment variables in your repo's `.env.local` fi To start with the basic examples, you'll just need to add your OpenAI API key and Auth0 credentials. - To start with the examples, you'll just need to add your OpenAI API key and Auth0 credentials for the Web app and Machine to Machine App. - - You can setup a new Auth0 tenant with an Auth0 Web App and Token Vault following the Prerequisites instructions [here](https://auth0.com/ai/docs/call-others-apis-on-users-behalf). + - You can set up a new Auth0 tenant with an Auth0 Web App and Token Vault following the Prerequisites instructions [here](https://auth0.com/ai/docs/get-started/call-others-apis-on-users-behalf). - An Auth0 FGA account, you can create one [here](https://dashboard.fga.dev). Add the FGA store ID, client ID, client secret, and API URL to the `.env.local` file. - Optionally add a [SerpAPI](https://serpapi.com/) API key for using web search tool. @@ -67,7 +67,7 @@ Agent configuration lives in `src/lib/agent.ts`. From here, you can change the p This package has [@next/bundle-analyzer](https://www.npmjs.com/package/@next/bundle-analyzer) set up by default - you can explore the bundle size interactively by running: ```bash -$ ANALYZE=true bun run build +$ ANALYZE=true npm run build ``` ## License diff --git a/ts-langchain/package-lock.json b/ts-langchain/package-lock.json index 2a357f9..de21626 100644 --- a/ts-langchain/package-lock.json +++ b/ts-langchain/package-lock.json @@ -8,12 +8,12 @@ "name": "auth0-assistant0", "version": "0.0.0", "dependencies": { - "@auth0/ai-langchain": "^4.0.0", - "@auth0/nextjs-auth0": "4.8.0", + "@auth0/ai-langchain": "^4.1.0", + "@auth0/nextjs-auth0": "^4.13.0", "@langchain/community": "^0.3.53", "@langchain/core": "^0.3.72", "@langchain/langgraph": "^0.4.6", - "@langchain/langgraph-sdk": "^0.0.107", + "@langchain/langgraph-sdk": "^0.0.109", "@langchain/openai": "0.6.1", "@openfga/sdk": "^0.8.0", "@radix-ui/react-avatar": "^1.1.7", @@ -122,9 +122,9 @@ "peer": true }, "node_modules/@auth0/ai": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@auth0/ai/-/ai-5.0.1.tgz", - "integrity": "sha512-l5lGBOlV6nRBPsevIZli0GGAjfQwrwhCFp0NvK3RcGmwbzOqua2gDvulhr6JHIAF3LFi2xcyq4/GY3l7btxzfQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@auth0/ai/-/ai-5.1.1.tgz", + "integrity": "sha512-KxemZNtL3+nMm0EQpqs2AGJsQIOVcJm7XkJqP1OvkxioqRiyTjj8psNfidTK0xn9Y9s3Yps8gdAAu1J8R02wlQ==", "license": "Apache-2.0", "dependencies": { "@openfga/sdk": "^0.8.0", @@ -137,9 +137,9 @@ } }, "node_modules/@auth0/ai-langchain": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@auth0/ai-langchain/-/ai-langchain-4.0.0.tgz", - "integrity": "sha512-lZDZxEHiKJPEnhKJgFppzRT+1H7A3hFtM7Hu8Unst1Orr9Px3qydnjrEf1LuV+5MT/7pOaVGC7gFJHI+zXabSA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@auth0/ai-langchain/-/ai-langchain-4.1.0.tgz", + "integrity": "sha512-5Ll9YoI64JuI0M116IAE/LS3cI4ENh5t4pLWZTDC20jGuIDBTo4JitXVwze7nHLIki+6y5bs6dA66bTK0JImeA==", "license": "Apache-2.0", "dependencies": { "@auth0/ai": "*", @@ -148,7 +148,7 @@ "peerDependencies": { "@langchain/core": "^0.3.72", "@langchain/langgraph": "^0.4.4", - "@langchain/langgraph-sdk": "^0.0.107", + "@langchain/langgraph-sdk": "^0.0.109", "@openfga/sdk": "0.8.0", "zod": "^3.25.76" } @@ -163,32 +163,24 @@ } }, "node_modules/@auth0/nextjs-auth0": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@auth0/nextjs-auth0/-/nextjs-auth0-4.8.0.tgz", - "integrity": "sha512-tgo4f6u1Ac4MqjwiYtllr9DzcNK+ThDoU4VYj6uTTqebwGGSdhXZWAkHFwWgabgWdeYHXpKYZ0xS9dQZv/PNAQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@auth0/nextjs-auth0/-/nextjs-auth0-4.13.0.tgz", + "integrity": "sha512-YHh1H9s7Fi42c5k/9C5RnNc7tQYODdQwRy5X/L4doCJvRltEajOwEy7rQ7ERnuSoWd3mgk4YxPjCAMh4Dg1ceA==", "license": "MIT", "dependencies": { "@edge-runtime/cookies": "^5.0.1", "@panva/hkdf": "^1.2.1", - "jose": "^5.9.6", - "oauth4webapi": "^3.1.2", + "jose": "^6.0.11", + "oauth4webapi": "^3.8.2", + "openid-client": "^6.8.0", "swr": "^2.2.5" }, "peerDependencies": { - "next": "^14.2.25 || ^15.2.3", + "next": "^14.2.25 || ^15.2.3 || ^16.0.0", "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" } }, - "node_modules/@auth0/nextjs-auth0/node_modules/jose": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", - "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/@browserbasehq/sdk": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/@browserbasehq/sdk/-/sdk-2.6.0.tgz", @@ -2499,9 +2491,9 @@ } }, "node_modules/@langchain/langgraph-sdk": { - "version": "0.0.107", - "resolved": "https://registry.npmjs.org/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.107.tgz", - "integrity": "sha512-2qzboDgYH8KJNz7q2Yzvj6H9i4iZUYfZnB7xY+Dkye6yvI+2m1fFIdpP/Ppu+eFvoIUAsbDHDF+wvR4F11kS3Q==", + "version": "0.0.109", + "resolved": "https://registry.npmjs.org/@langchain/langgraph-sdk/-/langgraph-sdk-0.0.109.tgz", + "integrity": "sha512-UpjL0c681CJqvKxgWD8o9fwUXRZzcDfsz8EcJ2PkXFxQFKRLe4QKZMtBr4OKFTR94pJtlOuTVla4OV5I5w+mdQ==", "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.15", @@ -4803,9 +4795,9 @@ "license": "MIT" }, "node_modules/auth0": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/auth0/-/auth0-4.33.0.tgz", - "integrity": "sha512-+zRMFXakIpKudDJKGzwlsYp6LC91J9w7hMz9k9d/qRmGbfqkJeqp3wPmKV7GqAcprfUr9fWCJH3XFFxzJV2jow==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/auth0/-/auth0-4.36.0.tgz", + "integrity": "sha512-n/eqshTNXY9HY+KaHbxLNHr5iOqg4PztMczNQXOIrHcyUsi6zB6uQphP25tbKiy7+A1pwgX/ZkAOnTzFUoBroA==", "license": "MIT", "dependencies": { "jose": "^4.13.2", diff --git a/ts-langchain/package.json b/ts-langchain/package.json index f627157..61c29a9 100644 --- a/ts-langchain/package.json +++ b/ts-langchain/package.json @@ -25,12 +25,12 @@ "node": ">=18" }, "dependencies": { - "@auth0/ai-langchain": "^4.0.0", - "@auth0/nextjs-auth0": "4.8.0", + "@auth0/ai-langchain": "^4.1.0", + "@auth0/nextjs-auth0": "^4.13.0", "@langchain/community": "^0.3.53", "@langchain/core": "^0.3.72", "@langchain/langgraph": "^0.4.6", - "@langchain/langgraph-sdk": "^0.0.107", + "@langchain/langgraph-sdk": "^0.0.109", "@langchain/openai": "0.6.1", "@openfga/sdk": "^0.8.0", "@radix-ui/react-avatar": "^1.1.7", diff --git a/ts-langchain/src/components/auth0-ai/TokenVault/TokenVaultInterruptHandler.tsx b/ts-langchain/src/components/TokenVaultInterruptHandler.tsx similarity index 100% rename from ts-langchain/src/components/auth0-ai/TokenVault/TokenVaultInterruptHandler.tsx rename to ts-langchain/src/components/TokenVaultInterruptHandler.tsx diff --git a/ts-langchain/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx b/ts-langchain/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx index 5c060ea..3f36e97 100644 --- a/ts-langchain/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx +++ b/ts-langchain/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx @@ -1,8 +1,9 @@ 'use client'; -import { ReactNode } from 'react'; +import type { ReactNode } from 'react'; /** - * Defines the mode the EnsureAPIAccess component will use to prompt the user to authorize the API access. + * Defines the mode the TokenVaultConsent component will use to prompt the user to connect a third-party account and + * authorize the API access. * - `redirect` will redirect the user to the provider's authorization page. * - `popup` will open a popup window to prompt the user to authorize the API access. * - `auto` will automatically choose the best mode based on the user's device and browser. @@ -13,10 +14,11 @@ export type TokenVaultAuthProps = { interrupt: { connection: string; requiredScopes: string[]; + authorizationParams?: Record; resume?: () => void; }; auth?: { - authorizePath?: string; + connectPath?: string; returnTo?: string; }; onFinish?: () => void; diff --git a/ts-langchain/src/components/auth0-ai/TokenVault/index.tsx b/ts-langchain/src/components/auth0-ai/TokenVault/index.tsx index f45f88f..6f7c68f 100644 --- a/ts-langchain/src/components/auth0-ai/TokenVault/index.tsx +++ b/ts-langchain/src/components/auth0-ai/TokenVault/index.tsx @@ -1,8 +1,8 @@ import { BrowserView, MobileView } from 'react-device-detect'; -import { TokenVaultAuthProps } from './TokenVaultAuthProps'; import { TokenVaultConsentPopup } from './popup'; import { TokenVaultConsentRedirect } from './redirect'; +import type { TokenVaultAuthProps } from './TokenVaultAuthProps'; export function TokenVaultConsent(props: TokenVaultAuthProps) { const { mode } = props; diff --git a/ts-langchain/src/components/auth0-ai/TokenVault/popup.tsx b/ts-langchain/src/components/auth0-ai/TokenVault/popup.tsx index 436777b..f059fca 100644 --- a/ts-langchain/src/components/auth0-ai/TokenVault/popup.tsx +++ b/ts-langchain/src/components/auth0-ai/TokenVault/popup.tsx @@ -4,12 +4,13 @@ import { useCallback, useEffect, useState } from 'react'; import { WaitingMessage } from '../util/loader'; import { PromptUserContainer } from '../util/prompt-user-container'; -import { TokenVaultAuthProps } from './TokenVaultAuthProps'; + +import type { TokenVaultAuthProps } from './TokenVaultAuthProps'; export function TokenVaultConsentPopup({ - interrupt: { connection, requiredScopes, resume }, + interrupt: { connection, requiredScopes, authorizationParams, resume }, connectWidget: { icon, title, description, action, containerClassName }, - auth: { authorizePath = '/auth/login', returnTo = '/close' } = {}, + auth: { connectPath = '/auth/connect', returnTo = '/close' } = {}, onFinish, }: TokenVaultAuthProps) { const [isLoading, setIsLoading] = useState(false); @@ -43,14 +44,17 @@ export function TokenVaultConsentPopup({ //Open the login popup const startLoginPopup = useCallback(async () => { const search = new URLSearchParams({ - returnTo, connection, - access_type: 'offline', - prompt: 'consent', - connection_scope: requiredScopes.join(), + returnTo, + // Add all extra authorization parameters to the search params, they will be collected and submitted via the + // authorization_params parameter of the connect account flow. + ...authorizationParams, }); + for (const requiredScope of requiredScopes) { + search.append('scopes', requiredScope); + } - const url = new URL(authorizePath, window.location.origin); + const url = new URL(connectPath, window.location.origin); url.search = search.toString(); const windowFeatures = 'width=800,height=650,status=no,toolbar=no,menubar=no'; @@ -62,7 +66,7 @@ export function TokenVaultConsentPopup({ setLoginPopup(popup); setIsLoading(true); } - }, [connection, requiredScopes, returnTo, authorizePath]); + }, [connection, requiredScopes, returnTo, authorizationParams, connectPath]); if (isLoading) { return ; diff --git a/ts-langchain/src/components/auth0-ai/TokenVault/redirect.tsx b/ts-langchain/src/components/auth0-ai/TokenVault/redirect.tsx index c29e635..7971503 100644 --- a/ts-langchain/src/components/auth0-ai/TokenVault/redirect.tsx +++ b/ts-langchain/src/components/auth0-ai/TokenVault/redirect.tsx @@ -1,12 +1,13 @@ 'use client'; import { PromptUserContainer } from '../util/prompt-user-container'; -import { TokenVaultAuthProps } from './TokenVaultAuthProps'; + +import type { TokenVaultAuthProps } from './TokenVaultAuthProps'; export function TokenVaultConsentRedirect({ - interrupt: { requiredScopes, connection }, + interrupt: { connection, requiredScopes, authorizationParams }, connectWidget: { icon, title, description, action, containerClassName }, - auth: { authorizePath = '/auth/login', returnTo = window.location.pathname } = {}, + auth: { connectPath = '/auth/connect', returnTo = window.location.pathname } = {}, }: TokenVaultAuthProps) { return ( { const search = new URLSearchParams({ - returnTo, connection, - access_type: 'offline', - connection_scope: requiredScopes.join(), + returnTo, + // Add all extra authorization parameters to the search params, they will be collected and submitted via the + // authorization_params parameter of the connect account flow. + ...authorizationParams, }); + for (const requiredScope of requiredScopes) { + search.append('scopes', requiredScope); + } - const url = new URL(authorizePath, window.location.origin); + const url = new URL(connectPath, window.location.origin); url.search = search.toString(); // Redirect to the authorization page diff --git a/ts-langchain/src/components/chat-window.tsx b/ts-langchain/src/components/chat-window.tsx index b73e986..34053cf 100644 --- a/ts-langchain/src/components/chat-window.tsx +++ b/ts-langchain/src/components/chat-window.tsx @@ -9,7 +9,7 @@ import { useQueryState } from 'nuqs'; import { useStream } from '@langchain/langgraph-sdk/react'; import { type Message } from '@langchain/langgraph-sdk'; -import { TokenVaultInterruptHandler } from '@/components/auth0-ai/TokenVault/TokenVaultInterruptHandler'; +import { TokenVaultInterruptHandler } from '@/components/TokenVaultInterruptHandler'; import { ChatMessageBubble } from '@/components/chat-message-bubble'; import { Button } from '@/components/ui/button'; import { cn } from '@/utils/cn'; @@ -23,7 +23,7 @@ function ChatMessages(props: { return (
{props.messages.map((m, i) => { - return ; + return ; })}
); diff --git a/ts-langchain/src/lib/agent.ts b/ts-langchain/src/lib/agent.ts index 8bc6173..03858e7 100644 --- a/ts-langchain/src/lib/agent.ts +++ b/ts-langchain/src/lib/agent.ts @@ -34,8 +34,6 @@ const googleCalendarParams = { }; const tools = [ new Calculator(), - // Requires process.env.SERPAPI_API_KEY to be set: https://serpapi.com/ - new SerpAPI(), withGmailRead(new GmailSearch(gmailParams)), withGmailWrite(new GmailCreateDraft(gmailParams)), withCalendar(new GoogleCalendarCreateTool(googleCalendarParams)), @@ -45,6 +43,10 @@ const tools = [ withAsyncAuthorization(shopOnlineTool), getContextDocumentsTool, ]; +// Requires process.env.SERPAPI_API_KEY to be set: https://serpapi.com/ +if (process.env.SERPAPI_API_KEY) { + tools.push(new SerpAPI()); +} const checkpointer = new MemorySaver(); const store = new InMemoryStore(); diff --git a/ts-langchain/src/lib/auth.ts b/ts-langchain/src/lib/auth.ts index a8de8f1..8375947 100644 --- a/ts-langchain/src/lib/auth.ts +++ b/ts-langchain/src/lib/auth.ts @@ -98,4 +98,4 @@ auth.authenticate(async (request: Request) => { } }); -export { auth as authHandler }; \ No newline at end of file +export { auth as authHandler }; diff --git a/ts-langchain/src/lib/auth0-ai.ts b/ts-langchain/src/lib/auth0-ai.ts index dc0bf75..95db898 100644 --- a/ts-langchain/src/lib/auth0-ai.ts +++ b/ts-langchain/src/lib/auth0-ai.ts @@ -9,8 +9,9 @@ export const getAccessToken = async () => getAccessTokenFromTokenVault(); const auth0AICustomAPI = new Auth0AI({ auth0: { domain: process.env.AUTH0_DOMAIN!, - clientId: process.env.AUTH0_CUSTOM_API_CLIENT_ID!, - clientSecret: process.env.AUTH0_CUSTOM_API_CLIENT_SECRET!, + // For token exchange with Token Vault, we want to provide the Custom API Client credentials + clientId: process.env.AUTH0_CUSTOM_API_CLIENT_ID!, // Custom API Client ID for token exchange + clientSecret: process.env.AUTH0_CUSTOM_API_CLIENT_SECRET!, // Custom API Client secret }, }); @@ -25,11 +26,11 @@ export const withGoogleConnection = (scopes: string[]) => subjectTokenType: SUBJECT_TOKEN_TYPES.SUBJECT_TYPE_ACCESS_TOKEN, }); -export const withGmailRead = withGoogleConnection(['https://www.googleapis.com/auth/gmail.readonly']); +export const withGmailRead = withGoogleConnection(['openid', 'https://www.googleapis.com/auth/gmail.readonly']); -export const withGmailWrite = withGoogleConnection(['https://www.googleapis.com/auth/gmail.compose']); +export const withGmailWrite = withGoogleConnection(['openid', 'https://www.googleapis.com/auth/gmail.compose']); -export const withCalendar = withGoogleConnection(['https://www.googleapis.com/auth/calendar.events']); +export const withCalendar = withGoogleConnection(['openid', 'https://www.googleapis.com/auth/calendar.events']); // Async Authorization flow for user confirmation // Note: you must use a client application that has the CIBA grant type enabled @@ -45,7 +46,7 @@ export const withAsyncAuthorization = auth0AI.withAsyncAuthorization({ audience: process.env['SHOP_API_AUDIENCE']!, /** * Controls how long the authorization request is valid. - */ + */ // requestedExpiry: 301, /** diff --git a/ts-langchain/src/lib/auth0.ts b/ts-langchain/src/lib/auth0.ts index 7e7533c..a77d7d3 100644 --- a/ts-langchain/src/lib/auth0.ts +++ b/ts-langchain/src/lib/auth0.ts @@ -7,14 +7,16 @@ export const auth0 = new Auth0Client({ scope: process.env.AUTH0_SCOPE, audience: process.env.AUTH0_AUDIENCE, }, + + enableConnectAccountEndpoint: true, }); // Get the Access token from Auth0 session export const getAccessToken = async () => { const tokenResult = await auth0.getAccessToken(); - if(!tokenResult || !tokenResult.token) { - throw new Error("No access token found in Auth0 session"); + if (!tokenResult || !tokenResult.token) { + throw new Error('No access token found in Auth0 session'); } return tokenResult.token; diff --git a/ts-llamaindex/README.md b/ts-llamaindex/README.md index 61300c1..5f73bd0 100644 --- a/ts-llamaindex/README.md +++ b/ts-llamaindex/README.md @@ -31,9 +31,9 @@ cd auth0-assistant0/ts-llamaindex Next, you'll need to set up environment variables in your repo's `.env.local` file. Copy the `.env.example` file to `.env.local`. - To start with the examples, you'll just need to add your OpenAI API key and Auth0 credentials for the Web app and Machine to Machine App. - - You can setup a new Auth0 tenant with an Auth0 Web App and Token Vault following the Prerequisites instructions [here](https://auth0.com/ai/docs/call-others-apis-on-users-behalf). + - You can set up a new Auth0 tenant with an Auth0 Web App and Token Vault following the Prerequisites instructions [here](https://auth0.com/ai/docs/get-started/call-others-apis-on-users-behalf). - Click on the tenant name on the [Quickstarts](https://auth0.com/ai/docs/call-your-apis-on-users-behalf), Go to the app settings (**Applications** -> **Applications** -> **WebApp Quickstart Client** -> **Settings** -> **Advanced Settings** -> **Grant Types**) and enable the CIBA grant and save. - - For Async Authorizations, you can setup Guardian Push and Enroll the your user for Guardian following the Prerequisites instructions [here](https://auth0.com/ai/docs/async-authorization). + - For Async Authorizations, you can set up Guardian Push and Enroll the your user for Guardian following the Prerequisites instructions [here](https://auth0.com/ai/docs/async-authorization). - An Auth0 FGA account, you can create one [here](https://dashboard.fga.dev). Add the FGA store ID, client ID, client secret, and API URL to the `.env.local` file. - Optionally add a [SerpAPI](https://serpapi.com/) API key for using web search tool. @@ -68,7 +68,7 @@ Backend logic lives in `app/api/chat/route.ts`. From here, you can change the pr This package has [@next/bundle-analyzer](https://www.npmjs.com/package/@next/bundle-analyzer) set up by default - you can explore the bundle size interactively by running: ```bash -$ ANALYZE=true bun run build +$ ANALYZE=true npm run build ``` ## License diff --git a/ts-llamaindex/package-lock.json b/ts-llamaindex/package-lock.json index e4f8018..734e3c4 100644 --- a/ts-llamaindex/package-lock.json +++ b/ts-llamaindex/package-lock.json @@ -10,11 +10,11 @@ "dependencies": { "@ai-sdk/llamaindex": "^1.0.28", "@ai-sdk/react": "2.0.33", - "@auth0/ai-llamaindex": "^4.0.0", - "@auth0/ai-vercel": "^4.0.1", - "@auth0/nextjs-auth0": "4.9.0", + "@auth0/ai-llamaindex": "^4.1.0", + "@auth0/ai-vercel": "^4.1.0", + "@auth0/nextjs-auth0": "^4.13.0", "@langchain/community": "^0.3.53", - "@llamaindex/openai": "^0.4.18", + "@llamaindex/openai": "0.4.19", "@radix-ui/react-avatar": "^1.1.7", "@radix-ui/react-checkbox": "^1.2.3", "@radix-ui/react-dialog": "^1.1.11", @@ -29,7 +29,7 @@ "drizzle-orm": "^0.43.1", "drizzle-zod": "^0.7.1", "googleapis": "^161.0.0", - "llamaindex": "^0.11.28", + "llamaindex": "^0.11.29", "llm-chunk": "0.0.1", "lucide-react": "^0.475.0", "marked": "^15.0.7", @@ -252,9 +252,9 @@ "peer": true }, "node_modules/@auth0/ai": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@auth0/ai/-/ai-5.0.1.tgz", - "integrity": "sha512-l5lGBOlV6nRBPsevIZli0GGAjfQwrwhCFp0NvK3RcGmwbzOqua2gDvulhr6JHIAF3LFi2xcyq4/GY3l7btxzfQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@auth0/ai/-/ai-5.1.1.tgz", + "integrity": "sha512-KxemZNtL3+nMm0EQpqs2AGJsQIOVcJm7XkJqP1OvkxioqRiyTjj8psNfidTK0xn9Y9s3Yps8gdAAu1J8R02wlQ==", "license": "Apache-2.0", "dependencies": { "@openfga/sdk": "^0.8.0", @@ -267,9 +267,9 @@ } }, "node_modules/@auth0/ai-llamaindex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@auth0/ai-llamaindex/-/ai-llamaindex-4.0.0.tgz", - "integrity": "sha512-Eli7H7tQ+zfoBWGeCzTP5p/BJC3H9ew0jYIQ6kmtNGLnXJhcddrg+cRjIr9z9vkGZMAiiveATR498eXYELKKtw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@auth0/ai-llamaindex/-/ai-llamaindex-4.1.0.tgz", + "integrity": "sha512-yRbzPxqqZDP76QD3+5ttvKpaWBfcnfNC9vpVNKZf2+3yTn2nvYNMBP2/d4GwkJW2OQ5+qeikKaqXMfb5Vsiwvw==", "license": "Apache-2.0", "dependencies": { "@auth0/ai": "*", @@ -284,9 +284,9 @@ } }, "node_modules/@auth0/ai-vercel": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@auth0/ai-vercel/-/ai-vercel-4.0.1.tgz", - "integrity": "sha512-dktgjXLXngRkYnLsySClfgyA4FEb0Gr8Q1gH1PPdx0mcQVWfRkVG6tcvdU3ziThP9RvxkmcmPTyU0Mxv+dTwug==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@auth0/ai-vercel/-/ai-vercel-4.1.0.tgz", + "integrity": "sha512-tKOQVqpDiunbYy8r0AS6u79R0fPFq+MGH6I30MDWBeO1ACsTUrrFdIGEFGEDl/z8y4FZwuKWg9XPhsjtvUA3RA==", "license": "Apache-2.0", "dependencies": { "@ai-sdk/react": "^2.0.0", @@ -302,27 +302,28 @@ } }, "node_modules/@auth0/nextjs-auth0": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@auth0/nextjs-auth0/-/nextjs-auth0-4.9.0.tgz", - "integrity": "sha512-z53aI+5h7CYRDYXe/iiPzEFg32PWRiKzdSemjyHLnmeQQgiZ3Va7ZYrUWggNCgtzm314sHsipzyyafiNgSNUrQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@auth0/nextjs-auth0/-/nextjs-auth0-4.13.0.tgz", + "integrity": "sha512-YHh1H9s7Fi42c5k/9C5RnNc7tQYODdQwRy5X/L4doCJvRltEajOwEy7rQ7ERnuSoWd3mgk4YxPjCAMh4Dg1ceA==", "license": "MIT", "dependencies": { "@edge-runtime/cookies": "^5.0.1", "@panva/hkdf": "^1.2.1", "jose": "^6.0.11", - "oauth4webapi": "^3.1.2", + "oauth4webapi": "^3.8.2", + "openid-client": "^6.8.0", "swr": "^2.2.5" }, "peerDependencies": { - "next": "^14.2.25 || ^15.2.3", + "next": "^14.2.25 || ^15.2.3 || ^16.0.0", "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" } }, "node_modules/@auth0/nextjs-auth0/node_modules/jose": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.0.tgz", - "integrity": "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.2.tgz", + "integrity": "sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -1570,10 +1571,9 @@ } }, "node_modules/@llamaindex/core": { - "version": "0.6.22", - "resolved": "https://registry.npmjs.org/@llamaindex/core/-/core-0.6.22.tgz", - "integrity": "sha512-/BXyemkvpxMaUhOkbwJ2PTvzKjSWkL8+6QLpz/n+pk8xBwMMe1GVBgli/J57gCyi8GbrlBafBj6GaPOgWub2Eg==", - "peer": true, + "version": "0.6.21", + "resolved": "https://registry.npmjs.org/@llamaindex/core/-/core-0.6.21.tgz", + "integrity": "sha512-CtR7k5hVyH3AraXNvtjCxbNTJhjyrzdyLhfiFWtVu2a9+ct8uRYqM8YGHBsG6qgYtQUQjfZPWvo1nXpig9UCOw==", "dependencies": { "@finom/zod-to-json-schema": "3.24.11", "@llamaindex/env": "0.1.30", @@ -1587,34 +1587,30 @@ "resolved": "https://registry.npmjs.org/@finom/zod-to-json-schema/-/zod-to-json-schema-3.24.11.tgz", "integrity": "sha512-fL656yBPiWebtfGItvtXLWrFNGlF1NcDFS0WdMQXMs9LluVg0CfT5E2oXYp0pidl0vVG53XkW55ysijNkU5/hA==", "license": "ISC", - "peer": true, "peerDependencies": { "zod": "^4.0.14" } }, "node_modules/@llamaindex/core/node_modules/@types/node": { - "version": "24.7.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.2.tgz", - "integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==", + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", "license": "MIT", - "peer": true, "dependencies": { - "undici-types": "~7.14.0" + "undici-types": "~7.16.0" } }, "node_modules/@llamaindex/core/node_modules/undici-types": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", - "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", - "license": "MIT", - "peer": true + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" }, "node_modules/@llamaindex/core/node_modules/zod": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -1642,14 +1638,14 @@ } }, "node_modules/@llamaindex/openai": { - "version": "0.4.20", - "resolved": "https://registry.npmjs.org/@llamaindex/openai/-/openai-0.4.20.tgz", - "integrity": "sha512-b2wTBkSELAszdJ6Eh2KrLHZvcDQ5UUotaThyNq76b22rYEBs2YOgVbbLUBXXWOLxkEHntVRt99ZcVtsOYlLg+w==", + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/@llamaindex/openai/-/openai-0.4.19.tgz", + "integrity": "sha512-ew4sYp0L2J7HNjRUyINt/EWMjBHy39CNzqyE/38r904gNrIEkT9TmbSzARD1fF2JXA5cAYiUOg6FsJlQ6+1fXw==", "dependencies": { "openai": "^5.12.0" }, "peerDependencies": { - "@llamaindex/core": "0.6.22", + "@llamaindex/core": "0.6.21", "@llamaindex/env": "0.1.30" } }, @@ -1716,6 +1712,111 @@ "node": ">= 10" } }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.2.4.tgz", + "integrity": "sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.2.4.tgz", + "integrity": "sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.2.4.tgz", + "integrity": "sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.2.4.tgz", + "integrity": "sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.2.4.tgz", + "integrity": "sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.2.4.tgz", + "integrity": "sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.2.4.tgz", + "integrity": "sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3524,9 +3625,9 @@ "license": "MIT" }, "node_modules/auth0": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/auth0/-/auth0-4.33.0.tgz", - "integrity": "sha512-+zRMFXakIpKudDJKGzwlsYp6LC91J9w7hMz9k9d/qRmGbfqkJeqp3wPmKV7GqAcprfUr9fWCJH3XFFxzJV2jow==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/auth0/-/auth0-4.36.0.tgz", + "integrity": "sha512-n/eqshTNXY9HY+KaHbxLNHr5iOqg4PztMczNQXOIrHcyUsi6zB6uQphP25tbKiy7+A1pwgX/ZkAOnTzFUoBroA==", "license": "MIT", "dependencies": { "jose": "^4.13.2", @@ -7603,36 +7704,6 @@ "@llamaindex/env": "0.1.30" } }, - "node_modules/llamaindex/node_modules/@llamaindex/core": { - "version": "0.6.21", - "resolved": "https://registry.npmjs.org/@llamaindex/core/-/core-0.6.21.tgz", - "integrity": "sha512-CtR7k5hVyH3AraXNvtjCxbNTJhjyrzdyLhfiFWtVu2a9+ct8uRYqM8YGHBsG6qgYtQUQjfZPWvo1nXpig9UCOw==", - "dependencies": { - "@finom/zod-to-json-schema": "3.24.11", - "@llamaindex/env": "0.1.30", - "@types/node": "^24.0.13", - "magic-bytes.js": "^1.10.0", - "zod": "^4.1.5" - } - }, - "node_modules/llamaindex/node_modules/@llamaindex/core/node_modules/@finom/zod-to-json-schema": { - "version": "3.24.11", - "resolved": "https://registry.npmjs.org/@finom/zod-to-json-schema/-/zod-to-json-schema-3.24.11.tgz", - "integrity": "sha512-fL656yBPiWebtfGItvtXLWrFNGlF1NcDFS0WdMQXMs9LluVg0CfT5E2oXYp0pidl0vVG53XkW55ysijNkU5/hA==", - "license": "ISC", - "peerDependencies": { - "zod": "^4.0.14" - } - }, - "node_modules/llamaindex/node_modules/@llamaindex/core/node_modules/zod": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", - "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/llamaindex/node_modules/@llamaindex/node-parser": { "version": "2.0.21", "resolved": "https://registry.npmjs.org/@llamaindex/node-parser/-/node-parser-2.0.21.tgz", @@ -9360,9 +9431,9 @@ } }, "node_modules/openid-client/node_modules/jose": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.0.tgz", - "integrity": "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.2.tgz", + "integrity": "sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" diff --git a/ts-llamaindex/package.json b/ts-llamaindex/package.json index afc7756..164f14b 100644 --- a/ts-llamaindex/package.json +++ b/ts-llamaindex/package.json @@ -24,11 +24,11 @@ "dependencies": { "@ai-sdk/llamaindex": "^1.0.28", "@ai-sdk/react": "2.0.33", - "@auth0/ai-llamaindex": "^4.0.0", - "@auth0/ai-vercel": "^4.0.1", - "@auth0/nextjs-auth0": "4.9.0", + "@auth0/ai-llamaindex": "^4.1.0", + "@auth0/ai-vercel": "^4.1.0", + "@auth0/nextjs-auth0": "^4.13.0", "@langchain/community": "^0.3.53", - "@llamaindex/openai": "^0.4.18", + "@llamaindex/openai": "0.4.19", "@radix-ui/react-avatar": "^1.1.7", "@radix-ui/react-checkbox": "^1.2.3", "@radix-ui/react-dialog": "^1.1.11", @@ -43,7 +43,7 @@ "drizzle-orm": "^0.43.1", "drizzle-zod": "^0.7.1", "googleapis": "^161.0.0", - "llamaindex": "^0.11.28", + "llamaindex": "^0.11.29", "llm-chunk": "0.0.1", "lucide-react": "^0.475.0", "marked": "^15.0.7", diff --git a/ts-llamaindex/src/app/api/chat/route.ts b/ts-llamaindex/src/app/api/chat/route.ts index 4788c45..65cfd62 100644 --- a/ts-llamaindex/src/app/api/chat/route.ts +++ b/ts-llamaindex/src/app/api/chat/route.ts @@ -83,7 +83,7 @@ async function initializeAgent(messages: UIMessage[] = []) { const assistant = new OpenAIAgent({ llm: openai({ model: 'gpt-4.1' }), systemPrompt: AGENT_SYSTEM_TEMPLATE, - tools, + tools: tools.filter(tool => !!tool), chatHistory: convertUIMessagesToChatMessages(messages), verbose: true, }); @@ -128,4 +128,4 @@ export async function POST(req: NextRequest) { }); return createUIMessageStreamResponse({ stream }); -} \ No newline at end of file +} diff --git a/ts-llamaindex/src/components/auth0-ai/TokenVault/TokenVaultInterruptHandler.tsx b/ts-llamaindex/src/components/TokenVaultInterruptHandler.tsx similarity index 100% rename from ts-llamaindex/src/components/auth0-ai/TokenVault/TokenVaultInterruptHandler.tsx rename to ts-llamaindex/src/components/TokenVaultInterruptHandler.tsx diff --git a/ts-llamaindex/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx b/ts-llamaindex/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx index 5c060ea..3f36e97 100644 --- a/ts-llamaindex/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx +++ b/ts-llamaindex/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx @@ -1,8 +1,9 @@ 'use client'; -import { ReactNode } from 'react'; +import type { ReactNode } from 'react'; /** - * Defines the mode the EnsureAPIAccess component will use to prompt the user to authorize the API access. + * Defines the mode the TokenVaultConsent component will use to prompt the user to connect a third-party account and + * authorize the API access. * - `redirect` will redirect the user to the provider's authorization page. * - `popup` will open a popup window to prompt the user to authorize the API access. * - `auto` will automatically choose the best mode based on the user's device and browser. @@ -13,10 +14,11 @@ export type TokenVaultAuthProps = { interrupt: { connection: string; requiredScopes: string[]; + authorizationParams?: Record; resume?: () => void; }; auth?: { - authorizePath?: string; + connectPath?: string; returnTo?: string; }; onFinish?: () => void; diff --git a/ts-llamaindex/src/components/auth0-ai/TokenVault/index.tsx b/ts-llamaindex/src/components/auth0-ai/TokenVault/index.tsx index f45f88f..6f7c68f 100644 --- a/ts-llamaindex/src/components/auth0-ai/TokenVault/index.tsx +++ b/ts-llamaindex/src/components/auth0-ai/TokenVault/index.tsx @@ -1,8 +1,8 @@ import { BrowserView, MobileView } from 'react-device-detect'; -import { TokenVaultAuthProps } from './TokenVaultAuthProps'; import { TokenVaultConsentPopup } from './popup'; import { TokenVaultConsentRedirect } from './redirect'; +import type { TokenVaultAuthProps } from './TokenVaultAuthProps'; export function TokenVaultConsent(props: TokenVaultAuthProps) { const { mode } = props; diff --git a/ts-llamaindex/src/components/auth0-ai/TokenVault/popup.tsx b/ts-llamaindex/src/components/auth0-ai/TokenVault/popup.tsx index 436777b..f059fca 100644 --- a/ts-llamaindex/src/components/auth0-ai/TokenVault/popup.tsx +++ b/ts-llamaindex/src/components/auth0-ai/TokenVault/popup.tsx @@ -4,12 +4,13 @@ import { useCallback, useEffect, useState } from 'react'; import { WaitingMessage } from '../util/loader'; import { PromptUserContainer } from '../util/prompt-user-container'; -import { TokenVaultAuthProps } from './TokenVaultAuthProps'; + +import type { TokenVaultAuthProps } from './TokenVaultAuthProps'; export function TokenVaultConsentPopup({ - interrupt: { connection, requiredScopes, resume }, + interrupt: { connection, requiredScopes, authorizationParams, resume }, connectWidget: { icon, title, description, action, containerClassName }, - auth: { authorizePath = '/auth/login', returnTo = '/close' } = {}, + auth: { connectPath = '/auth/connect', returnTo = '/close' } = {}, onFinish, }: TokenVaultAuthProps) { const [isLoading, setIsLoading] = useState(false); @@ -43,14 +44,17 @@ export function TokenVaultConsentPopup({ //Open the login popup const startLoginPopup = useCallback(async () => { const search = new URLSearchParams({ - returnTo, connection, - access_type: 'offline', - prompt: 'consent', - connection_scope: requiredScopes.join(), + returnTo, + // Add all extra authorization parameters to the search params, they will be collected and submitted via the + // authorization_params parameter of the connect account flow. + ...authorizationParams, }); + for (const requiredScope of requiredScopes) { + search.append('scopes', requiredScope); + } - const url = new URL(authorizePath, window.location.origin); + const url = new URL(connectPath, window.location.origin); url.search = search.toString(); const windowFeatures = 'width=800,height=650,status=no,toolbar=no,menubar=no'; @@ -62,7 +66,7 @@ export function TokenVaultConsentPopup({ setLoginPopup(popup); setIsLoading(true); } - }, [connection, requiredScopes, returnTo, authorizePath]); + }, [connection, requiredScopes, returnTo, authorizationParams, connectPath]); if (isLoading) { return ; diff --git a/ts-llamaindex/src/components/auth0-ai/TokenVault/redirect.tsx b/ts-llamaindex/src/components/auth0-ai/TokenVault/redirect.tsx index c29e635..7971503 100644 --- a/ts-llamaindex/src/components/auth0-ai/TokenVault/redirect.tsx +++ b/ts-llamaindex/src/components/auth0-ai/TokenVault/redirect.tsx @@ -1,12 +1,13 @@ 'use client'; import { PromptUserContainer } from '../util/prompt-user-container'; -import { TokenVaultAuthProps } from './TokenVaultAuthProps'; + +import type { TokenVaultAuthProps } from './TokenVaultAuthProps'; export function TokenVaultConsentRedirect({ - interrupt: { requiredScopes, connection }, + interrupt: { connection, requiredScopes, authorizationParams }, connectWidget: { icon, title, description, action, containerClassName }, - auth: { authorizePath = '/auth/login', returnTo = window.location.pathname } = {}, + auth: { connectPath = '/auth/connect', returnTo = window.location.pathname } = {}, }: TokenVaultAuthProps) { return ( { const search = new URLSearchParams({ - returnTo, connection, - access_type: 'offline', - connection_scope: requiredScopes.join(), + returnTo, + // Add all extra authorization parameters to the search params, they will be collected and submitted via the + // authorization_params parameter of the connect account flow. + ...authorizationParams, }); + for (const requiredScope of requiredScopes) { + search.append('scopes', requiredScope); + } - const url = new URL(authorizePath, window.location.origin); + const url = new URL(connectPath, window.location.origin); url.search = search.toString(); // Redirect to the authorization page diff --git a/ts-llamaindex/src/components/chat-window.tsx b/ts-llamaindex/src/components/chat-window.tsx index 8125c06..a8bd8b2 100644 --- a/ts-llamaindex/src/components/chat-window.tsx +++ b/ts-llamaindex/src/components/chat-window.tsx @@ -8,7 +8,7 @@ import { StickToBottom, useStickToBottomContext } from 'use-stick-to-bottom'; import { ArrowDown, ArrowUpIcon, LoaderCircle } from 'lucide-react'; import { useInterruptions } from '@auth0/ai-vercel/react'; -import { TokenVaultInterruptHandler } from '@/components/auth0-ai/TokenVault/TokenVaultInterruptHandler'; +import { TokenVaultInterruptHandler } from '@/components/TokenVaultInterruptHandler'; import { ChatMessageBubble } from '@/components/chat-message-bubble'; import { Button } from '@/components/ui/button'; import { cn } from '@/utils/cn'; diff --git a/ts-llamaindex/src/lib/auth0-ai.ts b/ts-llamaindex/src/lib/auth0-ai.ts index 85c24e4..3ff074e 100644 --- a/ts-llamaindex/src/lib/auth0-ai.ts +++ b/ts-llamaindex/src/lib/auth0-ai.ts @@ -11,17 +11,17 @@ const auth0AI = new Auth0AI(); // Connection for Google services export const withGmailRead = auth0AI.withTokenVault({ connection: 'google-oauth2', - scopes: ['https://www.googleapis.com/auth/gmail.readonly'], + scopes: ['openid', 'https://www.googleapis.com/auth/gmail.readonly'], refreshToken: getRefreshToken, }); export const withGmailWrite = auth0AI.withTokenVault({ connection: 'google-oauth2', - scopes: ['https://www.googleapis.com/auth/gmail.compose'], + scopes: ['openid', 'https://www.googleapis.com/auth/gmail.compose'], refreshToken: getRefreshToken, }); export const withCalendar = auth0AI.withTokenVault({ connection: 'google-oauth2', - scopes: ['https://www.googleapis.com/auth/calendar.events'], + scopes: ['openid', 'https://www.googleapis.com/auth/calendar.events'], refreshToken: getRefreshToken, }); diff --git a/ts-llamaindex/src/lib/auth0.ts b/ts-llamaindex/src/lib/auth0.ts index f29780b..be6afba 100644 --- a/ts-llamaindex/src/lib/auth0.ts +++ b/ts-llamaindex/src/lib/auth0.ts @@ -1,6 +1,8 @@ import { Auth0Client } from '@auth0/nextjs-auth0/server'; -export const auth0 = new Auth0Client(); +export const auth0 = new Auth0Client({ + enableConnectAccountEndpoint: true, +}); // Get the refresh token from Auth0 session export const getRefreshToken = async () => { diff --git a/ts-llamaindex/src/lib/tools/serpapi.ts b/ts-llamaindex/src/lib/tools/serpapi.ts index fd09081..8f14303 100644 --- a/ts-llamaindex/src/lib/tools/serpapi.ts +++ b/ts-llamaindex/src/lib/tools/serpapi.ts @@ -2,16 +2,21 @@ import { tool } from 'llamaindex'; import { z } from 'zod'; import { SerpAPI } from '@langchain/community/tools/serpapi'; -const serpApi = new SerpAPI(); +let toolInstance = null; -// Requires process.env.SERPAPI_API_KEY to be set: https://serpapi.com/ -export const serpApiTool = tool({ - name: 'serpApi', - description: serpApi.description, - parameters: z.object({ - q: z.string().describe('The query to search the web for'), - }), - execute: async ({ q }) => { - return await serpApi._call(q); - }, -}); +if (process.env.SERPAPI_API_KEY) { + const serpApi = new SerpAPI(); + + // Requires process.env.SERPAPI_API_KEY to be set: https://serpapi.com/ + toolInstance = tool({ + name: 'serpApi', + description: serpApi.description, + parameters: z.object({ + q: z.string().describe('The query to search the web for'), + }), + execute: async ({ q }) => { + return await serpApi._call(q); + }, + }); +} +export const serpApiTool = toolInstance; diff --git a/ts-vercel-ai/README.md b/ts-vercel-ai/README.md index cba79e4..1d9cea8 100644 --- a/ts-vercel-ai/README.md +++ b/ts-vercel-ai/README.md @@ -30,9 +30,9 @@ cd auth0-assistant0/ts-vercel-ai Next, you'll need to set up environment variables in your repo's `.env.local` file. Copy the `.env.example` file to `.env.local`. - To start with the examples, you'll just need to add your OpenAI API key and Auth0 credentials for the Web app and Machine to Machine App. - - You can setup a new Auth0 tenant with an Auth0 Web App and Token Vault following the Prerequisites instructions [here](https://auth0.com/ai/docs/call-others-apis-on-users-behalf). + - You can set up a new Auth0 tenant with an Auth0 Web App and Token Vault following the Prerequisites instructions [here](https://auth0.com/ai/docs/get-started/call-others-apis-on-users-behalf). - Click on the tenant name on the [Quickstarts](https://auth0.com/ai/docs/call-your-apis-on-users-behalf), Go to the app settings (**Applications** -> **Applications** -> **WebApp Quickstart Client** -> **Settings** -> **Advanced Settings** -> **Grant Types**) and enable the CIBA grant and save. - - For Async Authorizations, you can setup Guardian Push and Enroll the your user for Guardian following the Prerequisites instructions [here](https://auth0.com/ai/docs/async-authorization). + - For Async Authorizations, you can set up Guardian Push and Enroll the your user for Guardian following the Prerequisites instructions [here](https://auth0.com/ai/docs/async-authorization). - An Auth0 FGA account, you can create one [here](https://dashboard.fga.dev). Add the FGA store ID, client ID, client secret, and API URL to the `.env.local` file. - Optionally add a [SerpAPI](https://serpapi.com/) API key for using web search tool. @@ -67,7 +67,7 @@ Backend logic lives in `app/api/chat/route.ts`. From here, you can change the pr This package has [@next/bundle-analyzer](https://www.npmjs.com/package/@next/bundle-analyzer) set up by default - you can explore the bundle size interactively by running: ```bash -$ ANALYZE=true bun run build +$ ANALYZE=true npm run build ``` ## License diff --git a/ts-vercel-ai/package-lock.json b/ts-vercel-ai/package-lock.json index f5ed362..7faef92 100644 --- a/ts-vercel-ai/package-lock.json +++ b/ts-vercel-ai/package-lock.json @@ -10,8 +10,8 @@ "dependencies": { "@ai-sdk/openai": "2.0.24", "@ai-sdk/react": "2.0.33", - "@auth0/ai-vercel": "^4.0.1", - "@auth0/nextjs-auth0": "4.4.2", + "@auth0/ai-vercel": "^4.1.0", + "@auth0/nextjs-auth0": "^4.13.0", "@langchain/community": "^0.3.53", "@radix-ui/react-avatar": "^1.1.7", "@radix-ui/react-checkbox": "^1.2.3", @@ -201,9 +201,9 @@ "peer": true }, "node_modules/@auth0/ai": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@auth0/ai/-/ai-5.0.1.tgz", - "integrity": "sha512-l5lGBOlV6nRBPsevIZli0GGAjfQwrwhCFp0NvK3RcGmwbzOqua2gDvulhr6JHIAF3LFi2xcyq4/GY3l7btxzfQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@auth0/ai/-/ai-5.1.1.tgz", + "integrity": "sha512-KxemZNtL3+nMm0EQpqs2AGJsQIOVcJm7XkJqP1OvkxioqRiyTjj8psNfidTK0xn9Y9s3Yps8gdAAu1J8R02wlQ==", "license": "Apache-2.0", "dependencies": { "@openfga/sdk": "^0.8.0", @@ -216,9 +216,9 @@ } }, "node_modules/@auth0/ai-vercel": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@auth0/ai-vercel/-/ai-vercel-4.0.1.tgz", - "integrity": "sha512-dktgjXLXngRkYnLsySClfgyA4FEb0Gr8Q1gH1PPdx0mcQVWfRkVG6tcvdU3ziThP9RvxkmcmPTyU0Mxv+dTwug==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@auth0/ai-vercel/-/ai-vercel-4.1.0.tgz", + "integrity": "sha512-tKOQVqpDiunbYy8r0AS6u79R0fPFq+MGH6I30MDWBeO1ACsTUrrFdIGEFGEDl/z8y4FZwuKWg9XPhsjtvUA3RA==", "license": "Apache-2.0", "dependencies": { "@ai-sdk/react": "^2.0.0", @@ -234,23 +234,33 @@ } }, "node_modules/@auth0/nextjs-auth0": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@auth0/nextjs-auth0/-/nextjs-auth0-4.4.2.tgz", - "integrity": "sha512-vLz6C+b1jxbxpYg63+JpcoRF+w287w0YzyWj2kANHMDLFzwVx7hTooqAGdiywNONxiMLQbc2vFDpGeSA0FjSjA==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@auth0/nextjs-auth0/-/nextjs-auth0-4.13.0.tgz", + "integrity": "sha512-YHh1H9s7Fi42c5k/9C5RnNc7tQYODdQwRy5X/L4doCJvRltEajOwEy7rQ7ERnuSoWd3mgk4YxPjCAMh4Dg1ceA==", "license": "MIT", "dependencies": { "@edge-runtime/cookies": "^5.0.1", "@panva/hkdf": "^1.2.1", - "jose": "^5.9.6", - "oauth4webapi": "^3.1.2", + "jose": "^6.0.11", + "oauth4webapi": "^3.8.2", + "openid-client": "^6.8.0", "swr": "^2.2.5" }, "peerDependencies": { - "next": "^14.2.25 || ^15.2.3", + "next": "^14.2.25 || ^15.2.3 || ^16.0.0", "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" } }, + "node_modules/@auth0/nextjs-auth0/node_modules/jose": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.2.tgz", + "integrity": "sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/@browserbasehq/sdk": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/@browserbasehq/sdk/-/sdk-2.6.0.tgz", @@ -338,9 +348,9 @@ } }, "node_modules/@emnapi/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", - "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.6.0.tgz", + "integrity": "sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg==", "dev": true, "license": "MIT", "optional": true, @@ -350,9 +360,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", - "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz", + "integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==", "license": "MIT", "optional": true, "dependencies": { @@ -1291,13 +1301,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.6", + "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -1306,9 +1316,9 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz", - "integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.1.tgz", + "integrity": "sha512-csZAzkNhsgwb0I/UAV6/RGFTbiakPCf0ZrGmrIxQpYvGZ00PhTkSnyKNolphgIvmnJeGw6rcGVEXfTzUnFuEvw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1356,9 +1366,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.37.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz", - "integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==", + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.38.0.tgz", + "integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==", "dev": true, "license": "MIT", "engines": { @@ -1369,9 +1379,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2606,9 +2616,9 @@ } }, "node_modules/@next/bundle-analyzer": { - "version": "15.5.5", - "resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-15.5.5.tgz", - "integrity": "sha512-X9tOAWrgF6rPuI++vs2xfjYPd/+XdsdJzu0rQtjFmOV5qa02uzqGutAAr+qCd0vsB5J3VmnMFfzn2/9xxmM23w==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-15.5.6.tgz", + "integrity": "sha512-IHeyk2s9/fVDAGDLNbBkCSG8XBabhuMajiaJggjsg4GyFIswh78DzLo5Nl5th8QTs3U/teYeczvfeV9w1Tx3qA==", "dev": true, "license": "MIT", "dependencies": { @@ -2622,9 +2632,9 @@ "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "15.5.5", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.5.tgz", - "integrity": "sha512-FMzm412l9oFB8zdRD+K6HQ1VzlS+sNNsdg0MfvTg0i8lfCyTgP/RFxiu/pGJqZ/IQnzn9xSiLkjOVI7Iv4nbdQ==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.6.tgz", + "integrity": "sha512-YxDvsT2fwy1j5gMqk3ppXlsgDopHnkM4BoxSVASbvvgh5zgsK8lvWerDzPip8k3WVzsTZ1O7A7si1KNfN4OZfQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2847,13 +2857,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.56.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.0.tgz", - "integrity": "sha512-Tzh95Twig7hUwwNe381/K3PggZBZblKUe2wv25oIpzWLr6Z0m4KgV1ZVIjnR6GM9ANEqjZD7XsZEa6JL/7YEgg==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz", + "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", "license": "Apache-2.0", "peer": true, "dependencies": { - "playwright": "1.56.0" + "playwright": "1.56.1" }, "bin": { "playwright": "cli.js" @@ -3745,9 +3755,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.18.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.10.tgz", - "integrity": "sha512-anNG/V/Efn/YZY4pRzbACnKxNKoBng2VTFydVu8RRs5hQjikP8CQfaeAV59VFSCzKNp90mXiVXW2QzV56rwMrg==", + "version": "22.18.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.12.tgz", + "integrity": "sha512-BICHQ67iqxQGFSzfCFTT7MRQ5XcBjG5aeKh5Ok38UBbPe5fxTyE+aHFxwVrGyr8GNlqFMLKD1D3P2K/1ks8tog==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -3819,17 +3829,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.1.tgz", - "integrity": "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz", + "integrity": "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.46.1", - "@typescript-eslint/type-utils": "8.46.1", - "@typescript-eslint/utils": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/type-utils": "8.46.2", + "@typescript-eslint/utils": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -3843,7 +3853,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.46.1", + "@typescript-eslint/parser": "^8.46.2", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -3859,16 +3869,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.1.tgz", - "integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.2.tgz", + "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.46.1", - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/typescript-estree": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", "debug": "^4.3.4" }, "engines": { @@ -3884,14 +3894,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.1.tgz", - "integrity": "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.2.tgz", + "integrity": "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.46.1", - "@typescript-eslint/types": "^8.46.1", + "@typescript-eslint/tsconfig-utils": "^8.46.2", + "@typescript-eslint/types": "^8.46.2", "debug": "^4.3.4" }, "engines": { @@ -3906,14 +3916,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.1.tgz", - "integrity": "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz", + "integrity": "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1" + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3924,9 +3934,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.1.tgz", - "integrity": "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz", + "integrity": "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==", "dev": true, "license": "MIT", "engines": { @@ -3941,15 +3951,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.1.tgz", - "integrity": "sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.2.tgz", + "integrity": "sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/typescript-estree": "8.46.1", - "@typescript-eslint/utils": "8.46.1", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/utils": "8.46.2", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -3966,9 +3976,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.1.tgz", - "integrity": "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", + "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", "dev": true, "license": "MIT", "engines": { @@ -3980,16 +3990,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.1.tgz", - "integrity": "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz", + "integrity": "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.46.1", - "@typescript-eslint/tsconfig-utils": "8.46.1", - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/visitor-keys": "8.46.1", + "@typescript-eslint/project-service": "8.46.2", + "@typescript-eslint/tsconfig-utils": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -4065,16 +4075,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.1.tgz", - "integrity": "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.2.tgz", + "integrity": "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.46.1", - "@typescript-eslint/types": "8.46.1", - "@typescript-eslint/typescript-estree": "8.46.1" + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4089,13 +4099,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.1.tgz", - "integrity": "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==", + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz", + "integrity": "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.1", + "@typescript-eslint/types": "8.46.2", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -4755,9 +4765,9 @@ "license": "MIT" }, "node_modules/auth0": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/auth0/-/auth0-4.33.0.tgz", - "integrity": "sha512-+zRMFXakIpKudDJKGzwlsYp6LC91J9w7hMz9k9d/qRmGbfqkJeqp3wPmKV7GqAcprfUr9fWCJH3XFFxzJV2jow==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/auth0/-/auth0-4.36.0.tgz", + "integrity": "sha512-n/eqshTNXY9HY+KaHbxLNHr5iOqg4PztMczNQXOIrHcyUsi6zB6uQphP25tbKiy7+A1pwgX/ZkAOnTzFUoBroA==", "license": "MIT", "dependencies": { "jose": "^4.13.2", @@ -4912,9 +4922,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.16", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.16.tgz", - "integrity": "sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==", + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.19.tgz", + "integrity": "sha512-zoKGUdu6vb2jd3YOq0nnhEDQVbPcHhco3UImJrv5dSkvxTc2pl2WjOPsjZXDwPDSl5eghIMuY3R6J9NDKF3KcQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5129,9 +5139,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001750", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001750.tgz", - "integrity": "sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==", + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", "funding": [ { "type": "opencollective", @@ -5461,12 +5471,12 @@ "license": "MIT" }, "node_modules/console-table-printer": { - "version": "2.14.6", - "resolved": "https://registry.npmjs.org/console-table-printer/-/console-table-printer-2.14.6.tgz", - "integrity": "sha512-MCBl5HNVaFuuHW6FGbL/4fB7N/ormCy+tQ+sxTrF6QtSbSNETvPuOVbkJBhzDgYhvjWGrTma4eYJa37ZuoQsPw==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/console-table-printer/-/console-table-printer-2.15.0.tgz", + "integrity": "sha512-SrhBq4hYVjLCkBVOWaTzceJalvn5K1Zq5aQA6wXC/cYjI3frKWNPEMK3sZsJfNNQApvCQmgBcc13ZKmFj8qExw==", "license": "MIT", "dependencies": { - "simple-wcswidth": "^1.0.1" + "simple-wcswidth": "^1.1.2" } }, "node_modules/cross-fetch": { @@ -5958,9 +5968,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.237", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", - "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", + "version": "1.5.238", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.238.tgz", + "integrity": "sha512-khBdc+w/Gv+cS8e/Pbnaw/FXcBUeKrRVik9IxfXtgREOWyJhR4tj43n3amkVogJ/yeQUqzkrZcFhtIxIdqmmcQ==", "dev": true, "license": "ISC" }, @@ -6231,25 +6241,24 @@ } }, "node_modules/eslint": { - "version": "9.37.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz", - "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.38.0.tgz", + "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.4.0", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.1", "@eslint/core": "^0.16.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.37.0", + "@eslint/js": "9.38.0", "@eslint/plugin-kit": "^0.4.0", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", @@ -6292,13 +6301,13 @@ } }, "node_modules/eslint-config-next": { - "version": "15.5.5", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.5.5.tgz", - "integrity": "sha512-f8lRSSelp6cqrYjxEMjJ5En3WV913gTu/w9goYShnIujwDSQlKt4x9MwSDiduE9R5mmFETK44+qlQDxeSA0rUA==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.5.6.tgz", + "integrity": "sha512-cGr3VQlPsZBEv8rtYp4BpG1KNXDqGvPo9VC1iaCgIA11OfziC/vczng+TnAS3WpRIR3Q5ye/6yl+CRUuZ1fPGg==", "dev": true, "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "15.5.5", + "@next/eslint-plugin-next": "15.5.6", "@rushstack/eslint-patch": "^1.10.3", "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", @@ -7194,9 +7203,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.12.0.tgz", - "integrity": "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9772,9 +9781,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.23", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", - "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.26.tgz", + "integrity": "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==", "dev": true, "license": "MIT" }, @@ -9998,9 +10007,9 @@ } }, "node_modules/nuqs": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/nuqs/-/nuqs-2.7.1.tgz", - "integrity": "sha512-3WDgrOZWat0QyOheyljTlXK4TGFh1JKSLvXMgusMDcTyMJXe1xL8+q3zuQ6ke1vyeGnpJwztlZl2aDkMW2eIUg==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/nuqs/-/nuqs-2.7.2.tgz", + "integrity": "sha512-wOPJoz5om7jMJQick9zU1S/Q+joL+B2DZTZxfCleHEcUzjUnPoujGod4+nAmUWb+G9TwZnyv+mfNqlyfEi8Zag==", "license": "MIT", "dependencies": { "@standard-schema/spec": "1.0.0" @@ -10251,9 +10260,9 @@ } }, "node_modules/openid-client/node_modules/jose": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.0.tgz", - "integrity": "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.2.tgz", + "integrity": "sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" @@ -10576,13 +10585,13 @@ } }, "node_modules/playwright": { - "version": "1.56.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.0.tgz", - "integrity": "sha512-X5Q1b8lOdWIE4KAoHpW3SE8HvUB+ZZsUoN64ZhjnN8dOb1UpujxBtENGiZFE+9F/yhzJwYa+ca3u43FeLbboHA==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", "license": "Apache-2.0", "peer": true, "dependencies": { - "playwright-core": "1.56.0" + "playwright-core": "1.56.1" }, "bin": { "playwright": "cli.js" @@ -10595,9 +10604,9 @@ } }, "node_modules/playwright-core": { - "version": "1.56.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.0.tgz", - "integrity": "sha512-1SXl7pMfemAMSDn5rkPeZljxOCYAmQnYLBTExuh6E8USHXGSX3dx6lYZN/xPpTz1vimXmPA9CDnILvmJaB8aSQ==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", "license": "Apache-2.0", "peer": true, "bin": { @@ -11237,12 +11246,12 @@ "peer": true }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -12734,9 +12743,9 @@ } }, "node_modules/unist-util-is": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", - "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -12788,9 +12797,9 @@ } }, "node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", diff --git a/ts-vercel-ai/package.json b/ts-vercel-ai/package.json index 359ffb8..bf480a8 100644 --- a/ts-vercel-ai/package.json +++ b/ts-vercel-ai/package.json @@ -23,8 +23,8 @@ "dependencies": { "@ai-sdk/openai": "2.0.24", "@ai-sdk/react": "2.0.33", - "@auth0/ai-vercel": "^4.0.1", - "@auth0/nextjs-auth0": "4.4.2", + "@auth0/ai-vercel": "^4.1.0", + "@auth0/nextjs-auth0": "^4.13.0", "@langchain/community": "^0.3.53", "@radix-ui/react-avatar": "^1.1.7", "@radix-ui/react-checkbox": "^1.2.3", diff --git a/ts-vercel-ai/src/app/api/chat/route.ts b/ts-vercel-ai/src/app/api/chat/route.ts index 305ecfe..5ad1e35 100644 --- a/ts-vercel-ai/src/app/api/chat/route.ts +++ b/ts-vercel-ai/src/app/api/chat/route.ts @@ -34,7 +34,7 @@ export async function POST(req: NextRequest) { setAIContext({ threadID: id }); const tools = { - serpApiTool, + ...(serpApiTool ? { serpApiTool } : {}), getUserInfoTool, gmailSearchTool, gmailDraftTool, @@ -90,4 +90,4 @@ export async function POST(req: NextRequest) { }); return createUIMessageStreamResponse({ stream }); -} \ No newline at end of file +} diff --git a/ts-vercel-ai/src/components/auth0-ai/TokenVault/TokenVaultInterruptHandler.tsx b/ts-vercel-ai/src/components/TokenVaultInterruptHandler.tsx similarity index 100% rename from ts-vercel-ai/src/components/auth0-ai/TokenVault/TokenVaultInterruptHandler.tsx rename to ts-vercel-ai/src/components/TokenVaultInterruptHandler.tsx diff --git a/ts-vercel-ai/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx b/ts-vercel-ai/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx index 5c060ea..3f36e97 100644 --- a/ts-vercel-ai/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx +++ b/ts-vercel-ai/src/components/auth0-ai/TokenVault/TokenVaultAuthProps.tsx @@ -1,8 +1,9 @@ 'use client'; -import { ReactNode } from 'react'; +import type { ReactNode } from 'react'; /** - * Defines the mode the EnsureAPIAccess component will use to prompt the user to authorize the API access. + * Defines the mode the TokenVaultConsent component will use to prompt the user to connect a third-party account and + * authorize the API access. * - `redirect` will redirect the user to the provider's authorization page. * - `popup` will open a popup window to prompt the user to authorize the API access. * - `auto` will automatically choose the best mode based on the user's device and browser. @@ -13,10 +14,11 @@ export type TokenVaultAuthProps = { interrupt: { connection: string; requiredScopes: string[]; + authorizationParams?: Record; resume?: () => void; }; auth?: { - authorizePath?: string; + connectPath?: string; returnTo?: string; }; onFinish?: () => void; diff --git a/ts-vercel-ai/src/components/auth0-ai/TokenVault/index.tsx b/ts-vercel-ai/src/components/auth0-ai/TokenVault/index.tsx index f45f88f..6f7c68f 100644 --- a/ts-vercel-ai/src/components/auth0-ai/TokenVault/index.tsx +++ b/ts-vercel-ai/src/components/auth0-ai/TokenVault/index.tsx @@ -1,8 +1,8 @@ import { BrowserView, MobileView } from 'react-device-detect'; -import { TokenVaultAuthProps } from './TokenVaultAuthProps'; import { TokenVaultConsentPopup } from './popup'; import { TokenVaultConsentRedirect } from './redirect'; +import type { TokenVaultAuthProps } from './TokenVaultAuthProps'; export function TokenVaultConsent(props: TokenVaultAuthProps) { const { mode } = props; diff --git a/ts-vercel-ai/src/components/auth0-ai/TokenVault/popup.tsx b/ts-vercel-ai/src/components/auth0-ai/TokenVault/popup.tsx index 86a470d..f059fca 100644 --- a/ts-vercel-ai/src/components/auth0-ai/TokenVault/popup.tsx +++ b/ts-vercel-ai/src/components/auth0-ai/TokenVault/popup.tsx @@ -1,15 +1,16 @@ -"use client"; +'use client'; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from 'react'; -import { WaitingMessage } from "../util/loader"; -import { PromptUserContainer } from "../util/prompt-user-container"; -import { TokenVaultAuthProps } from "./TokenVaultAuthProps"; +import { WaitingMessage } from '../util/loader'; +import { PromptUserContainer } from '../util/prompt-user-container'; + +import type { TokenVaultAuthProps } from './TokenVaultAuthProps'; export function TokenVaultConsentPopup({ - interrupt: { connection, requiredScopes, resume }, + interrupt: { connection, requiredScopes, authorizationParams, resume }, connectWidget: { icon, title, description, action, containerClassName }, - auth: { authorizePath = "/auth/login", returnTo = "/close" } = {}, + auth: { connectPath = '/auth/connect', returnTo = '/close' } = {}, onFinish, }: TokenVaultAuthProps) { const [isLoading, setIsLoading] = useState(false); @@ -26,9 +27,9 @@ export function TokenVaultConsentPopup({ setIsLoading(false); setLoginPopup(null); clearInterval(interval); - if (typeof onFinish === "function") { + if (typeof onFinish === 'function') { onFinish(); - } else if (typeof resume === "function") { + } else if (typeof resume === 'function') { resume(); } } @@ -43,27 +44,29 @@ export function TokenVaultConsentPopup({ //Open the login popup const startLoginPopup = useCallback(async () => { const search = new URLSearchParams({ - returnTo, connection, - access_type: "offline", - prompt: "consent", - connection_scope: requiredScopes.join(), + returnTo, + // Add all extra authorization parameters to the search params, they will be collected and submitted via the + // authorization_params parameter of the connect account flow. + ...authorizationParams, }); + for (const requiredScope of requiredScopes) { + search.append('scopes', requiredScope); + } - const url = new URL(authorizePath, window.location.origin); + const url = new URL(connectPath, window.location.origin); url.search = search.toString(); - const windowFeatures = - "width=800,height=650,status=no,toolbar=no,menubar=no"; - const popup = window.open(url.toString(), "_blank", windowFeatures); + const windowFeatures = 'width=800,height=650,status=no,toolbar=no,menubar=no'; + const popup = window.open(url.toString(), '_blank', windowFeatures); if (!popup) { - console.error("Popup blocked by the browser"); + console.error('Popup blocked by the browser'); return; } else { setLoginPopup(popup); setIsLoading(true); } - }, [connection, requiredScopes]); + }, [connection, requiredScopes, returnTo, authorizationParams, connectPath]); if (isLoading) { return ; @@ -76,7 +79,7 @@ export function TokenVaultConsentPopup({ icon={icon} containerClassName={containerClassName} action={{ - label: action?.label ?? "Connect", + label: action?.label ?? 'Connect', onClick: startLoginPopup, }} /> diff --git a/ts-vercel-ai/src/components/auth0-ai/TokenVault/redirect.tsx b/ts-vercel-ai/src/components/auth0-ai/TokenVault/redirect.tsx index c29e635..7971503 100644 --- a/ts-vercel-ai/src/components/auth0-ai/TokenVault/redirect.tsx +++ b/ts-vercel-ai/src/components/auth0-ai/TokenVault/redirect.tsx @@ -1,12 +1,13 @@ 'use client'; import { PromptUserContainer } from '../util/prompt-user-container'; -import { TokenVaultAuthProps } from './TokenVaultAuthProps'; + +import type { TokenVaultAuthProps } from './TokenVaultAuthProps'; export function TokenVaultConsentRedirect({ - interrupt: { requiredScopes, connection }, + interrupt: { connection, requiredScopes, authorizationParams }, connectWidget: { icon, title, description, action, containerClassName }, - auth: { authorizePath = '/auth/login', returnTo = window.location.pathname } = {}, + auth: { connectPath = '/auth/connect', returnTo = window.location.pathname } = {}, }: TokenVaultAuthProps) { return ( { const search = new URLSearchParams({ - returnTo, connection, - access_type: 'offline', - connection_scope: requiredScopes.join(), + returnTo, + // Add all extra authorization parameters to the search params, they will be collected and submitted via the + // authorization_params parameter of the connect account flow. + ...authorizationParams, }); + for (const requiredScope of requiredScopes) { + search.append('scopes', requiredScope); + } - const url = new URL(authorizePath, window.location.origin); + const url = new URL(connectPath, window.location.origin); url.search = search.toString(); // Redirect to the authorization page diff --git a/ts-vercel-ai/src/components/chat-window.tsx b/ts-vercel-ai/src/components/chat-window.tsx index 07af61c..7a769ed 100644 --- a/ts-vercel-ai/src/components/chat-window.tsx +++ b/ts-vercel-ai/src/components/chat-window.tsx @@ -8,7 +8,7 @@ import { StickToBottom, useStickToBottomContext } from 'use-stick-to-bottom'; import { ArrowDown, ArrowUpIcon, LoaderCircle } from 'lucide-react'; import { useInterruptions } from '@auth0/ai-vercel/react'; -import { TokenVaultInterruptHandler } from '@/components/auth0-ai/TokenVault/TokenVaultInterruptHandler'; +import { TokenVaultInterruptHandler } from '@/components/TokenVaultInterruptHandler'; import { ChatMessageBubble } from '@/components/chat-message-bubble'; import { Button } from '@/components/ui/button'; import { cn } from '@/utils/cn'; diff --git a/ts-vercel-ai/src/lib/auth0-ai.ts b/ts-vercel-ai/src/lib/auth0-ai.ts index 2d4df25..241ea3a 100644 --- a/ts-vercel-ai/src/lib/auth0-ai.ts +++ b/ts-vercel-ai/src/lib/auth0-ai.ts @@ -11,17 +11,17 @@ const auth0AI = new Auth0AI(); // Connection for Google services export const withGmailRead = auth0AI.withTokenVault({ connection: 'google-oauth2', - scopes: ['https://www.googleapis.com/auth/gmail.readonly'], + scopes: ['openid', 'https://www.googleapis.com/auth/gmail.readonly'], refreshToken: getRefreshToken, }); export const withGmailWrite = auth0AI.withTokenVault({ connection: 'google-oauth2', - scopes: ['https://www.googleapis.com/auth/gmail.compose'], + scopes: ['openid', 'https://www.googleapis.com/auth/gmail.compose'], refreshToken: getRefreshToken, }); export const withCalendar = auth0AI.withTokenVault({ connection: 'google-oauth2', - scopes: ['https://www.googleapis.com/auth/calendar.events'], + scopes: ['openid', 'https://www.googleapis.com/auth/calendar.events'], refreshToken: getRefreshToken, }); @@ -42,11 +42,11 @@ export const withAsyncAuthorization = auth0AI.withAsyncAuthorization({ /** * The behavior when the authorization request is made. - * + * * - `block`: The tool execution is blocked until the user completes the authorization. * - `interrupt`: The tool execution is interrupted until the user completes the authorization. * - a callback: Same as "block" but give access to the auth request and executing logic. - * + * * Defaults to `interrupt`. * * When this flag is set to `block`, the execution of the tool awaits diff --git a/ts-vercel-ai/src/lib/auth0.ts b/ts-vercel-ai/src/lib/auth0.ts index f29780b..be6afba 100644 --- a/ts-vercel-ai/src/lib/auth0.ts +++ b/ts-vercel-ai/src/lib/auth0.ts @@ -1,6 +1,8 @@ import { Auth0Client } from '@auth0/nextjs-auth0/server'; -export const auth0 = new Auth0Client(); +export const auth0 = new Auth0Client({ + enableConnectAccountEndpoint: true, +}); // Get the refresh token from Auth0 session export const getRefreshToken = async () => { diff --git a/ts-vercel-ai/src/lib/tools/serpapi.ts b/ts-vercel-ai/src/lib/tools/serpapi.ts index 96fe942..004dcfa 100644 --- a/ts-vercel-ai/src/lib/tools/serpapi.ts +++ b/ts-vercel-ai/src/lib/tools/serpapi.ts @@ -2,15 +2,20 @@ import { tool } from 'ai'; import { z } from 'zod'; import { SerpAPI } from '@langchain/community/tools/serpapi'; -const serpApi = new SerpAPI(); +let toolInstance = null; -// Requires process.env.SERPAPI_API_KEY to be set: https://serpapi.com/ -export const serpApiTool = tool({ - description: serpApi.description, - inputSchema: z.object({ - q: z.string(), - }), - execute: async ({ q }) => { - return await serpApi._call(q); - }, -}); +if (process.env.SERPAPI_API_KEY) { + const serpApi = new SerpAPI(); + + // Requires process.env.SERPAPI_API_KEY to be set: https://serpapi.com/ + toolInstance = tool({ + description: serpApi.description, + inputSchema: z.object({ + q: z.string(), + }), + execute: async ({ q }) => { + return await serpApi._call(q); + }, + }); +} +export const serpApiTool = toolInstance;