Skip to Content
DocumentationArchitecture

Architecture

Cascaide models you application(or parts of the aplication that need AI capabilities) as a Directed Graph. All parts are modelled as nodes in the graph - regardless of type: UI, llm invocations, etc.

Think of your application in terms of Graphs spread across execution environments (client/server) So in a simple application, we have

  • Client side graph
  • Server side graph
  • Global application graph

Think of the client and server graphs as being subgraphs of the global graph. We do not declare the global graph, it is by default the union of the subgraphs.

Cascaide as a whole runs the global application graph. The subgraphs are executed on their respective environments and cascaide takes care of the orchestration.

The three pillars of Cascaide are:

  • State
  • Middlewares (Persistence, Hydration, Orchestration)
  • Persistence Database

State

The state of the graph is stored in a redux store, initialised one per execution environment. The client side redux store holds information about the client side subgraph, while the server redux store holds information about the server side subgraph. All communication between subgraphs happen in the language of redux actions.

Middlewares

There are three middlewares that accompanies every redux store.

  • Persistence Middleware
  • Hydration Middleware
  • Orchestration Middleware

Every action has to pass through these middlewares in the above order before it hits the store.

Note: Cacaide Lite only has Orchestration Middleware.

Persistence Database

While the redux stores records information about their local subgraph, the authoritative state of the global graph is stored in a postges DB. Three types of events are stored:

  • Node Executions (inputs and outputs of every node)
  • Context Events (state updates)
  • Cascades (think of these as threads connecting node executions and context events)

Example Flow

Let us understand better by considering a simple ReAct agent with a chat UI and a Human in The Loop Approval Step. We will implement it with both Cascaide and Cascaide Lite to understand the difference. You can find the github repo here :

Problem Statement: A ReAct agent that searches for hotel bookings, displays it to the user and books a hotel with payment approval.

Step 1 : Sketch the Global Graph

We will have a total of 4 nodes

  1. Chat UI node: This will be the first node and the entry point. It will always be active. | Client Node
  2. Agent Node: The LLM call happens here. | Server Node
  3. Tool Node: This will have a web search tool to find bookings | Server Node
  4. Approval UI Node: This node will take human approval and call an API to process payment, and will vanish once done. | Client Node

Step 2 : Define the Client Workflow Graph and Configuration

The Client Workflow Graph contains the meta data regarding all nodes in the global graph (we will discuss why meta data of server nodes are also required in more detail in concepts - it has to do with gracefull timeout handling in serverless). ClientWorkflowGraph + UI component registry makes up the Client Configuration.

// src/graphs/clientConfig.ts import Chat from "@/components/cascaide-ui/chat"; import ApprovalUI from "@/components/cascaide-nodes/approval" import { ClientWorkflowConfig } from "@cascaide-ts/react"; export const WorkflowConfig: ClientWorkflowConfig = { clientWorkflowGraph: { chat: { name: 'chat', isUINode: true }, approvalUi : { name: approvalUi, isUINode: true } agentNode: { name: 'agentNode', isUINode: false, isStreaming: true }, toolNode: { name: 'toolNode', isUINode: false }, }, uiComponentRegistry: { chat: Chat, approvalUi: ApprovalUI }, };

We will define these nodes later.

Last updated on