Combine Mastra’s orchestration with Generative UI from Thesys to move beyond text-only agents. Render agentic UIs that include real-time dashboards, dynamic forms, and interactive workflows - all generated from your agent logic. With lightweight React or TypeScript integration, you can turn multi-agent workflows into production-ready applications that feel natural, adaptive, and user-friendly.
This guide assumes you have basic knowledge of Mastra and NextJS. You’ll also need a Thesys API key from the C1 Console.
1

Create a new NextJS project

npx create-next-app@latest thesys-mastra-app
Install the dependencies:
package.json
{
  "dependencies": {
    "@ai-sdk/openai": "^2.0.23",
    "@crayonai/react-ui": "^0.8.24",
    "@crayonai/react-core": "^0.7.6",
    "@crayonai/stream": "^0.6.4",
    "@mastra/core": "^0.15.2",
    "@mastra/libsql": "^0.13.7",
    "@mastra/loggers": "^0.10.9",
    "@thesysai/genui-sdk": "^0.6.31",
    ...
  }
}
npm install
2

Create a new Mastra agent

You can follow the Mastra Quickstart to create a new Mastra agent or just follow along this guide. We’ll set up the example weather agent from the Quickstart but change the LLM provider to Thesys.
src/server/index.ts
import { Mastra } from "@mastra/core/mastra";

import { weatherAgent } from "./agents/weather-agent";

export const mastra = new Mastra({
  agents: { weatherAgent },
});

3

Change the render function to use C1Chat

src/app/page.tsx
"use client";

import { C1Chat } from "@thesysai/genui-sdk";
import "@crayonai/react-ui/styles/index.css";

export default function Home() {
  return <C1Chat apiUrl="/api/chat" />;
}
4

Implement the chat endpoint

We will modify the chat endpoint from the template app to use our newly created Mastra agent and return the response as a SSE stream.
src/app/api/chat/route.ts
import { NextRequest, NextResponse } from "next/server";
import { getMessageStore, MastraMessage } from "./messageStore";
import { mastra } from "../../../server";

export async function POST(req: NextRequest) {
  const { prompt, threadId } = (await req.json()) as {
    prompt: { content: string };
    threadId: string;
  };
  const messageStore = getMessageStore(threadId);
  const agent = mastra.getAgent("weatherAgent");

  // Prepare messages including history and current user message
  const userMessage = {
    id: crypto.randomUUID(),
    role: "user" as const,
    content: prompt.content,
    createdAt: new Date(),
  };
  const messages = [
    ...messageStore.getMastraCompatibleMessageList(),
    userMessage,
  ];

  // Add the user message to the store first
  messageStore.addMessage(userMessage);

  // Use streaming for the response
  const stream = await agent.streamVNext(messages);

  // Create a readable stream that processes the agent stream
  const readableStream = new ReadableStream({
    async start(controller) {
      try {
        let fullContent = "";

        for await (const chunk of stream.fullStream) {
          if (chunk.type === "text-delta") {
            const text = chunk.payload.text;
            if (text) {
              fullContent += text;
              // Send the text chunk to the client
              controller.enqueue(new TextEncoder().encode(text));
            }
          }
        }

        // After streaming is complete, save the assistant message
        const assistantMessage: MastraMessage = {
          id: crypto.randomUUID(),
          role: "assistant",
          content: fullContent,
          createdAt: new Date(),
        };
        messageStore.addMessage(assistantMessage);

        controller.close();
      } catch (error) {
        controller.error(error);
      }
    },
  });

  return new NextResponse(readableStream, {
    headers: {
      "Content-Type": "text/plain",
      "Cache-Control": "no-cache",
      Connection: "keep-alive",
    },
  });
}
5

Run the app

We need to modify the .env.local file to include the Thesys API key and then add the Mastra server to the next.config.ts file and start the app.
next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
  serverExternalPackages: ["@server/*"],
};

export default nextConfig;
Now simply start the app:
export THESYS_API_KEY=<your-api-key>
npm run dev

View the code

Find more examples and complete code on our GitHub repository.