App Integration

How to integrate Glow into a consuming app

Overview

The Glow packages (@zooly/glow-client and @zooly/glow-server) are consumed by apps (e.g., zooly-app) through API routes and the GlowChatClient component. The client expects a base URL for API calls; the app implements the corresponding routes and delegates to glow-server.

Setup Checklist

To integrate Glow into an app:

  1. Add @zooly/glow-client and @zooly/glow-server to package.json
  2. Add both to transpilePackages in next.config.ts
  3. Create API route handlers that delegate to glow-server
  4. Create an endpoint to get or create a GlowChat (e.g., for a given chatId and glowSlug)
  5. Render GlowChatClient with the glowChat and optional chatBrandingSettings

Package Configuration

next.config.ts

// Add to transpilePackages
transpilePackages: [
  "@zooly/glow-client",
  "@zooly/glow-server",
  // ... other packages
],

API Routes

The client uses a configurable base URL (default: /api/glow-chat-client). All routes are relative to this base.

POST (base URL) — Stream Chat Completion

Main streaming endpoint. The client sends messages, id (glowChatId), mockStateId, and location.

import { NextRequest } from "next/server";
import { handleGlowChatStream } from "@zooly/glow-server";
import { getServerSession } from "next-auth";

export async function POST(request: NextRequest) {
  const session = await getServerSession(authOptions);
  return handleGlowChatStream(request, session ?? undefined);
}

POST (base URL)/reset-to-message

Resets the chat to a specific message. Used when the user clicks "Edit" on a message.

POST (base URL)/reset-tool-call

Resets a tool call (e.g., when user cancels or retries).

POST (base URL)/client-msg-state/save

Saves clientMsgState (form data, tool outputs) for the chat.

POST (base URL)/message-data/get-public-data

Returns public message data for display.

Creating a Glow Chat

Before rendering GlowChatClient, the app must obtain a GlowChat. Use getOrCreateGlowChat for flows that support both new and existing chats:

import { getOrCreateGlowChat } from "@zooly/glow-server";

const { glowChat, glowSettings } = await getOrCreateGlowChat({
  chatId: "unique-chat-id",      // Optional; if omitted or restart, creates new
  glowSlug: "backstage-mini-app", // Required for new chats
  restart: false,                 // If true, creates new chat even with chatId
  phoneNumber: null,
  email: null,
  userName: user?.name ?? null,
  mockStateId: null,              // For testing with @zooly/llm-mock
});

For generate/embed flows (e.g., server-side generation), use handleGlowChatGenerate:

import { handleGlowChatGenerate } from "@zooly/glow-server";

const result = await handleGlowChatGenerate({
  options: {
    chatId,
    glowSlug: "my-flow",
    mockStateId,
    // ...
  },
  messageStr: "User's initial message",
});

Component Usage

import { GlowChatClient } from "@zooly/glow-client";
import type { GlowChat } from "@zooly/types";

interface ChatPageProps {
  glowChat: GlowChat;
  chatBrandingSettings?: ChatBrandingSettings; // Optional
}

export function ChatPage({ glowChat, chatBrandingSettings }: ChatPageProps) {
  return (
    <GlowChatClient
      glowChat={glowChat}
      chatBrandingSettings={chatBrandingSettings}
    />
  );
}

GlowChatClient uses useGlowChat with url: "/api/glow-chat-client" by default. To use a different base path, you would need to extend or wrap the component to pass a custom url.

Typical Flow

  1. Page load - App fetches or creates a GlowChat (e.g., via getOrCreateGlowChat in an API route or server component)
  2. Render - Pass glowChat to GlowChatClient
  3. User sends message - Client POSTs to /api/glow-chat-client with messages and glowChatId
  4. Stream response - Server streams tokens; client renders via GlowChatMessageQueue
  5. Tool calls - When the AI invokes a tool, the client renders the tool UI (from TOOL_REGISTRY); user interacts; client sends tool output back via addToolOutput

Authentication

handleGlowChatStream accepts an optional session. If the chat has a userId and it doesn't match the session user, the request returns 401. For guest/unauthenticated chats, userId can be null initially and is updated when the user logs in.

Environment Variables

  • NEXT_PUBLIC_URL - Used by executeApiTool when tool urlApi is relative (e.g., /api/my-tool)