next.jsnext.js13langchainnode-streamsvercel-ai

How to stream from a server action?


I use Next.js server actions instead of API routes to make a request to OpenAI:

lib/gpt.ts:

export async function getAISuggestion(session: Session) {
  const prompt = ...

  const { stream, handlers } = LangChainStream();

  chatModel.predictMessages(prompt, {callbacks: [handlers]});

  return stream;
}

The server action calls it:

actions.ts:

export async function getSuggestion(): Promise<
  ServerActionResponse<ReadableStream<Uint8Array>>
> {
  try {
    [...]

    const stream = await GPT.getAISuggestion(session);
    
    return { data: stream };
  } catch (error) {
    console.error(error);
    [...]
  }
}

I'm trying to call this server action from a client component:

ClientComponent.tsx:

"use client";

[...]

function foo {
    [...]

    const { data, error } = await getSugestion();
    
    if (data) {
      const reader = data.getReader(); 
      const decoder = new TextDecoder();
      let done = false;
      let text ="";      
      while (!done) {
        const { value, done: readerDone } = await reader.read();
        console.log("reading", value);
        done = readerDone;
        text += decoder.decode(value);
        setAiSuggestionsText(text);
      }
    } else {
      setError(error);
    }
}

But apparently, you can't send a stream from a server action to a client component:

Warning: Only plain objects can be passed to Client Components from Server Components. ReadableStream objects are not supported. {data: ReadableStream}


Solution

  • Unfortunately, Next.js doesn't appear to support returning HTTP responses from server actions. You will need to use a Route-handler if you want to return a response object.