Skip to Content

NextJS

Get your first full stack agent running in 5 minutes with npm.

Installation

npm i @cascaide-ts/core @cascaide-ts/react @cascaide-ts/postgres-js @cascaide-ts/server-next

Cascaide

Starting a New project

Setting Up in an Existing project

1. Set Enironment Variables

OPENAI_API_KEY='your-key' DATABASE_URL='your-url'

2. Set Up Postgres DB for Durability and Connection

  • Schema:

I am using prisma here, feel free to use whatever.

npm i prisma
generator client { provider = "prisma-client-js" output = "../lib/generated/prisma" binaryTargets = ["native", "rhel-openssl-3.0.x"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") } enum CascadeStatus { RUNNING COMPLETED ERROR } enum ExecutionStatus { RUNNING COMPLETED FAILED } model Cascade { id String @id @default(uuid()) status CascadeStatus @default(RUNNING) // Use @map to ensure the DB column is lowercase snake_case FnId Int @default(0) @map("fn_id") userId String @map("user_id") executions NodeExecution[] contextEvents ContextEvent[] createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@index([userId, status]) @@map("cascades") } model NodeExecution { id String @id @default(uuid()) nodeInstanceId String @unique @map("node_instance_id") cascadeId String @map("cascade_id") cascade Cascade @relation(fields: [cascadeId], references: [id], onDelete: Cascade) nodeName String @map("node_name") functionId Int @map("function_id") inputContext Json @map("input_context") fullOutput Json? @map("full_output") location String status ExecutionStatus @default(RUNNING) error String? startedAt DateTime @default(now()) @map("started_at") completedAt DateTime? @map("completed_at") @@unique([cascadeId, functionId]) @@map("node_executions") } model ContextEvent { id Int @id @default(autoincrement()) key String value Json functionId Int @map("function_id") cascadeId String @map("cascade_id") cascade Cascade @relation(fields: [cascadeId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) @map("created_at") @@index([cascadeId, functionId]) @@map("context_events") }
  • Set up the db and geenrate prisma client
npx prisma db push
  • Create Sql for persistor
// /lib/db/connection.ts import postgres from 'postgres'; const connectionString = process.env.DATABASE_URL!; // Use a singleton pattern for the SQL instance const globalForSql = global as unknown as { sql: postgres.Sql<{}> }; export const sql = globalForSql.sql || postgres(connectionString, { max: process.env.NODE_ENV === 'production' ? 10 : 1, // Adjust for serverless idle_timeout: 20, connect_timeout: 10, }); if (process.env.NODE_ENV !== 'production') globalForSql.sql = sql;

3. Define Graphs and Configurations

You can copy paste these graphs as a starting point. Check out prebuilt UI components Cascaide Chat UI. It is quite easy to build UI components in cascaide. You control graph execution with the useWorkflow hook and observe with useCascade hook. Check out concepts.

  • Client Side Client side confuration has a clientWorkflowGraph and uiComponentRegistry.
// src/components/home/clientConfig.ts import Chat from "@/components/cascaide-ui/chat"; import { ClientWorkflowConfig } from "@cascaide-ts/react"; export const ClientWorkflowConfig: ClientWorkflowConfig = { clientWorkflowGraph: { chat: { name: 'chat', isUINode: true }, // non-UI nodes -> metadata only ReActAgentNode: { name: 'ReActAgentNode', isUINode: false, isStreaming: true }, ReActToolNode: { name: 'ReActToolNode', isUINode: false, isStreaming: false }, }, uiComponentRegistry: { chat: Chat, }, };
  • Server Side

Check out graphs and configuration section to learn how to define these. You can copy paste this exact ReAct agent from the tutorial there.

// shared/workflowGraph.ts import { ReActAgentNodeExec, ReActAgentNodePost, ReActAgentNodeFn, ReActAgentNodeSelector, ReActToolNodeExec, ReActToolNodePost, ReActToolNodePrep, ReAcTToolNodeSelector } from '@/components/agents/ReActAgentNodes'; import { ServerWorkflowGraph } from '@cascaide-ts/core'; export const serverWorkflowGraph: ServerWorkflowGraph = { ReActAgentNode: { name: 'ReActAgentNode', prep: { selector: ReActAgentNodeSelector, fn: ReActAgentNodeFn }, exec: ReActAgentNodeExec, post: ReActAgentNodePost, isStreaming: true, isUINode:false }, ReActToolNode: { name: 'ReActToolNode', prep: { selector: ReActToolNodeSelector, fn: ReActToolNodeFn }, exec: ReActToolNodeExec, post: ReActToolNodePost, isStreaming: false, isUINode:false, }, };

4. Define API Routes

  • Action Relay Endpoint
// api/workflow/action/route.ts import { serverWorkflowGraph } from '@/shared/workflowGraph'; import { createWorkflowHandler, WorkflowHandlerConfig } from '@cascaide-ts/server-next'; import {PostgresPersistor} from '@cascaide-ts/postgres-js' import { sql } from '@/lib/persistence/connection'; // 1. Instantiate the logic provider const workflowpersistor = new PostgresPersistor(sql); const MAX_EXECUTION_TIME = 300000; const SAFE_BUFFER = 6000; const workflowConfig:WorkflowHandlerConfig={ workflowGraph:serverWorkflowGraph, persistor: workflowpersistor, // pass your PostgresPersistor here maxExecutionTime: MAX_EXECUTION_TIME, safeBuffer: SAFE_BUFFER } export const POST = createWorkflowHandler(workflowConfig)
  • Persistence Endpoint
// api/workflow/persistence/route.ts import { createPersistenceHandler } from '@cascaide-ts/server-next'; import {PostgresPersistor} from '@cascaide-ts/postgres-js' import { sql } from '@/lib/persistence/connection'; // 1. Instantiate the logic provider const persistor = new PostgresPersistor(sql); // 2. Export the POST handler generated by the factory export const POST = createPersistenceHandler(persistor);
  • Hydration Endpoint
// api/workflow/hydration/route.ts import { createHydrationHandler } from '@cascaide-ts/server-next'; import {PostgresPersistor} from '@cascaide-ts/postgres-js' import { sql } from '@/lib/persistence/connection'; // 1. Instantiate the logic provider const persistor = new PostgresPersistor(sql); // 2. Export the POST handler generated by the factory export const POST = createHydrationHandler(persistor);

5. Set Up WorkflowProvider and WorkflowRenderer

Set up the provider and renderer with the configurations and endpoints described above

'use client' import {WorkflowProvider,WorkflowRenderer} from '@cascaide-ts/react'; //import { WorkflowRenderer } from '@/components/workflowRenderer'; import { clientWorkflowConfig } from '@/app/clientConfig'; export default function HomePage() { return ( <WorkflowProvider initialNodeId="reactAgent_init" initialNodeName="reactAgent" config={homeWorkflowConfig} actionRelayEndpoint='/api/workflow/action' persistenceEndpoint='/api/workflow/persistence' hydrationEndpoint='/api/workflow/hydration' > <WorkflowRenderer /> </WorkflowProvider> ); }

6. Run!

npm run dev

Ask a question and open redux devtools to observe.

Cascaide Lite

Starting a New project

Setting Up in an Existing project

1. Set Enironment Variables

OPENAI_API_KEY='your-key'

2. Define Graphs and configurations

This step is identical to Cascaide. However, the agent and UI implementation changes slightly.

  • In lite, selector step becomes an empty shell, you will have to carry around agent traces between nodes
  • Chat UI changes in the sense that when activating a node, you have to send the full hsitory

3. Set Up API Routes

In Casacide Lite, you only setup the action relay endpoint. Unlike Cascaide, you set persistor as null.

// api/workflow/action/route.ts import { serverWorkflowGraph } from '@/shared/workflowGraph'; import { createWorkflowHandler, WorkflowHandlerConfig } from '@cascaide-ts/server-next'; const MAX_EXECUTION_TIME = 300000; const SAFE_BUFFER = 6000; const workflowConfig:WorkflowHandlerConfig={ workflowGraph:serverWorkflowGraph, persistor: null, // set as null, the framework will infer that you are using lite maxExecutionTime: MAX_EXECUTION_TIME, safeBuffer: SAFE_BUFFER } export const POST = createWorkflowHandler(workflowConfig)

4. Set Up WorkflowProvider and WorkflowRenderer

Similar to Casaide, except you only pass in action relay endpoint.

'use client' import {WorkflowProvider,WorkflowRenderer} from '@cascaide-ts/react'; //import { WorkflowRenderer } from '@/components/workflowRenderer'; import { clientWorkflowConfig } from '@/app/clientConfig'; export default function HomePage() { return ( <WorkflowProvider initialNodeId="reactAgent_init" initialNodeName="reactAgent" config={homeWorkflowConfig} actionRelayEndpoint='/api/workflow/action' > <WorkflowRenderer /> </WorkflowProvider> ); }

5. Run!

npm run dev

Open redux devtools for observability.

Last updated on