Glow follows a layered architecture with clear separation between client UI, server logic, and database access:
┌─────────────────────────────────────────────────────────────┐
│ API Layer (Next.js Route Handlers) │
│ apps/zooly-app/app/api/glow-chat-client/ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ @zooly/glow-server │
│ packages/glow-server/src/ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ @zooly/glow-client │
│ packages/glow-client/src/ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ @zooly/db (access layer) │
│ packages/db/src/access/glow/ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Database (Drizzle ORM) │
│ packages/db/src/glow/ │
└─────────────────────────────────────────────────────────────┘
Location: packages/db/src/glow/
| Table | Purpose |
|---|---|
glow_settings | Flow configuration: slug, name, prompt, Mermaid chart, nodes metadata, tool list |
glow_chat | Chat sessions: messages, currentNodeId, glowCurrentSlug, userId, clientMsgState |
glow_tool | API tool definitions: name, urlApi, fields, customHeaders |
glow_chat_msgs_data | Per-message metadata (glowSlug, etc.) |
glow_settings_chat_msgs | Default chat messages per flow |
tool_call | Tool call logs for context building |
cached_answer_state | Cached answer parts for streaming |
question_cache | Question-answer pairs with embeddings for cache lookup |
glow_settings_embedding | Flow-level embeddings |
glow_tool_embedding | Tool-level embeddings |
chat_token_usage | Token usage logging |
glow_chat.glowCurrentSlug → glow_settings.slugglow_chat.cacheStateId → cached_answer_state.idglow_chat.mockStateId → mock LLM state (testing)nodesMetadata in glow_settings references tools by name; tools are resolved from glow_tool or built-in UI toolsLocation: packages/glow-server/src/
| Function | Purpose |
|---|---|
handleGlowChatStream | Entry point for streaming; validates session, updates user/location, delegates to cache/core |
handleGlowChatWithCache | Wraps core; checks question cache when enabled, creates cache state on hit |
handleGlowChatCore | Main LLM flow: builds prompts, resolves tools, calls streamText, handles steps |
getGlowChatData | Loads glowChat + glowSettings by glowChatId |
getOrCreateGlowChat | Creates new chat or returns existing by chatId; used for generate/embed flows |
| Function | Purpose |
|---|---|
getGlowChatSystemPrompt | Flow-level prompt: flow name, description, Mermaid chart, user data, tool usage rules |
getGlowChatInstructionsSystemPrompt | Node-level: current node id, system instructions, available tools, moveToNodeId rules |
| Function | Purpose |
|---|---|
getCurrentNodeTools | Resolves tools for current node from nodesMetadata + glow_tool table |
getToolsList | Returns all tools for a flow |
executeApiTool | Calls external API for API tools (POST to urlApi) |
toolsBase | Base tool definitions including moveToNodeId, changeChatContext, returnToContext |
| Function | Purpose |
|---|---|
changeChatContext | Switches chat to new flow by slug; updates glowCurrentSlug, currentNodeId |
returnToContext | Returns to previous flow |
buildContextStack | Builds context from tool call logs for multi-turn tool handling |
prepareStepHandler | Runs before each step; handles moveToNodeId, changeChatContext, etc. |
onStepFinishHandler | Runs after each step; persists tool results, updates state |
defaultOnFinish | Final handler: saves messages, clears cache state, logs usage |
@zooly/db) - Finds similar questions by embedding, returns cached answerLocation: packages/glow-client/src/
| Component | Purpose |
|---|---|
GlowChatClient | Main chat container; wraps GlowAIProvider, message queue, input form |
GlowAIProvider | Context: chatAI, glowChat, sendMsgOnBehalfOfUser, resetToMessage, etc. |
useGlowChat | Custom hook wrapping useChat; handles API URL, glowChatId, message persistence |
GlowChatMessageQueue | Renders message list with assistant/user parts |
GlowChatInputForm | Input area with send, attachments |
Tools are registered by name and render based on tool call type:
Each tool has an "invocation" component (when AI calls it) and a "result" component (when user responds).
The consuming app (e.g., zooly-app) implements routes that delegate to glow-server:
| Route | Purpose |
|---|---|
POST /api/glow-chat-client | Stream chat completion (handleGlowChatStream) |
POST /api/glow-chat-client/reset-to-message | Reset chat to a specific message |
POST /api/glow-chat-client/reset-tool-call | Reset a tool call |
POST /api/glow-chat-client/client-msg-state/save | Save clientMsgState |
POST /api/glow-chat-client/message-data/get-public-data | Get public message data |
Exact route paths may vary by app; the client uses a configurable url (e.g., /api/glow-chat-client).
ai - AI SDK (streamText, convertToModelMessages, etc.)@zooly/db - Database access, cache, embeddings@zooly/types - GlowChat, GlowSettings, GlowTool, etc.@zooly/util - extractQuestionFromMessage@zooly/llm-mock - Mock LLM for testingnext, next-auth - Request/session handling@ai-sdk/react - useChatai - AI SDK types@zooly/client - Shared client utilities@zooly/util - Shared utilitiesreact, next, next-intl, zustand - UI and stateLocation: packages/types/src/types/glow/
| Type | Purpose |
|---|---|
GlowSettings | Flow config (slug, glowName, glowPrompt, nodesMetadata, etc.) |
GlowChat | Chat session (id, messages, currentNodeId, glowCurrentSlug, etc.) |
GlowTool | API tool (name, urlApi, fields, customHeaders) |
GlowToolMinimal | Minimal tool for node metadata (name, description, fields) |
NodeMetadata | Node config (id, label, fields, tools) |
NodeMetadataDict | Map of node id → NodeMetadata |
CachedAnswerPart | Cached answer part (type, text, etc.) |
ExtendedUIMessage | UI message with tool parts |