vercel / ai-chatbot

A full-featured, hackable Next.js AI chatbot built by Vercel
https://chat.vercel.ai
Other
5.53k stars 1.63k forks source link

Q: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server". #294

Open olegkorol opened 3 months ago

olegkorol commented 3 months ago

Hi,

I am experiencing the following error:

Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server".
  {submitUserMessage: function}

at stringify (<anonymous>)

...and I do not see where the issue might be – since I'm using 'use server' in submitUserMessage().

Maybe someone here could give me a hint (thanks in advance!).

Here's how my code looks like (I cannot spot any significant difference with the source code in this repo):

// app/(chat)/page.tsx

import type { Metadata } from "next";

import { nanoid } from '@/lib/utils'
import { Chat } from '@/components/chat'
import { AI } from '@/lib/chat/actions'
import { auth } from '@/auth'
import { Session } from '@/lib/types'
import { getMissingKeys } from '../actions'

export const metadata: Metadata = {
  title: 'AI Chatbot'
}

export default async function IndexPage() {
  const id = nanoid()
  const session = (await auth()) as Session
  const missingKeys = await getMissingKeys()

  return (
    <AI initialAIState={{ chatId: id, messages: [] }}>
      <Chat id={id} session={session} missingKeys={missingKeys} />
    </AI>
  )
}

and

// lib/chat/actions.tsx

async function submitUserMessage(content: string) {
  'use server'

  const aiState = getMutableAIState<typeof AI>()

  aiState.update({
    ...aiState.get(),
    messages: [
      ...aiState.get().messages,
      {
        id: nanoid(),
        role: 'user',
        content
      }
    ]
  })

  let textStream: undefined | ReturnType<typeof createStreamableValue<string>>
  let textNode: undefined | React.ReactNode

  const ui = render({
    model: GPT_MODEL,
    provider: openai,
    initial: <SpinnerMessage />,
    messages: [
      // ...
      ...aiState.get().messages.map((message: any) => ({
        role: message.role,
        content: message.content,
        name: message.name
      }))
    ],
    text: ({ content, done, delta }) => {
      if (!textStream) {
        textStream = createStreamableValue('')
        textNode = <BotMessage content={textStream.value} />
      }

      if (done) {
       // ..
      } else {
        textStream.update(delta)
      }

      return textNode
    },
    functions: {
      // ...
    }
  })

  return {
    id: nanoid(),
    display: ui
  }
}

// ----------

export const AI = createAI<AIState, UIState>({
  actions: {
    submitUserMessage,
    // Add more actions here
  },
  initialUIState: [],
  initialAIState: { /* ... */ },
  unstable_onGetUIState: async () => {
    'use server'

    const session = await auth()

    if (session && session.user) {
      const aiState = getAIState()

      if (aiState) {
        const uiState = getUIStateFromAIState(aiState)
        return uiState
      }
    } else {
      return
    }
  },
  unstable_onSetAIState: async ({ state, done }) => {
    'use server'

    const session = await auth()

    if (session && session.user) {
      const { chatId, messages } = state

      const createdAt = new Date()
      const userId = session.user.id as string
      const path = `/chat/${chatId}`
      const title = messages[0].content.substring(0, 100)

      const chat: Chat = {
        id: chatId,
        title,
        userId,
        createdAt,
        messages,
        path
      }

      await saveChat(chat)
    } else {
      return
    }
  }
})

Edit:

ai: ^3.0.12
next: 14.1.3
fullstackwebdev commented 3 months ago

I am having the same exact issue, the example rsc repo works, but any attempt to roll my own fails even with latest

fullstackwebdev commented 3 months ago

Ok I fixed it

I had to remove the --turbo from my package.json

olegkorol commented 3 months ago

Thanks, @fullstackwebdev! Changing next dev --turbo to next dev solved the issue.

I wonder what the underlying issue with --turbo is.

sajadghawami commented 2 months ago

Ok I fixed it

I had to remove the --turbo from my package.json

literally spend two hours on this...