diff --git a/README.md b/README.md index 8204dac5..abab0338 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ By adding selected `.mdc` files to `.cursor/rules/`, you can use these rules dir - [Java (Spring Boot, JPA)](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/java-springboot-jpa-cursorrules-prompt-file.mdc) - Java development with Spring Boot and JPA integration. - [Knative (Istio, Typesense, GPU)](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/knative-istio-typesense-gpu-cursorrules-prompt-fil.mdc) - Knative development with Istio, Typesense, and GPU integration. - [Kotlin Ktor Development](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/kotlin-ktor-development-cursorrules-prompt-file.mdc) - Kotlin development with Ktor integration. +- [LangGraph (TypeScript)](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/langgraph-typescript.mdc) - Best practices for building stateful multi-agent workflows with LangGraph in TypeScript. - [Laravel (PHP 8.3)](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/laravel-php-83-cursorrules-prompt-file.mdc) - Laravel development with PHP 8.3 integration. - [Laravel (TALL Stack)](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/laravel-tall-stack-best-practices-cursorrules-prom.mdc) - Laravel development with TALL Stack best practices. - [Manifest](https://github.com/PatrickJS/awesome-cursorrules/blob/main/rules/manifest-yaml-cursorrules-prompt-file.mdc) - YAML-based configuration and metadata files. diff --git a/rules/langgraph-typescript.mdc b/rules/langgraph-typescript.mdc new file mode 100644 index 00000000..ac5ff3d4 --- /dev/null +++ b/rules/langgraph-typescript.mdc @@ -0,0 +1,100 @@ +--- +description: Best practices for building stateful multi-agent workflows with LangGraph in TypeScript. Apply this rule when creating or modifying AI agent architectures, graph states, nodes, or conditional edges. +globs: ["**/*.ts", "**/*.tsx"] +alwaysApply: false +--- +# LangGraph TypeScript Guidelines + +Best practices and patterns for designing robust, type-safe multi-agent systems using LangGraph in TypeScript. + +## Core Principles + +- **State Immutability:** Treat the graph state as immutable. Nodes must return updates rather than mutating state directly. +- **Strict Typing:** Always explicitly type your graph state, node inputs/outputs, and edge conditions. +- **Single Responsibility Nodes:** Each node should do one logical job (e.g., retrieval, formatting, routing). +- **Explicit Stop Conditions:** Ensure conditional edges always have a guaranteed termination path to prevent infinite execution loops. + +## State Definition +Use the modern `Annotation.define` pattern to establish a type-safe graph state. + +```typescript +import { Annotation } from "@langchain/langgraph"; +import { BaseMessage } from "@langchain/core/messages"; + +// 1. Define the TypeScript interface representing your state +export interface AgentState { + messages: BaseMessage[]; + nextStep: string; + isCompleted: boolean; +} + +// 2. Define the LangGraph State Annotation +export const AgentStateAnnotation = Annotation.Root({ + messages: Annotation({ + reducer: (x, y) => x.concat(y), + default: () => [], + }), + nextStep: Annotation({ + reducer: (x, y) => y ?? x, + default: () => "start", + }), + isCompleted: Annotation({ + reducer: (x, y) => y ?? x, + default: () => false, + }), +}); +``` + +## Node Implementation +Nodes are async functions that accept the current state and return a partial update to the state. + +```typescript +import { AgentState } from "./state.js"; + +// Always type node inputs/outputs explicitly +export async function callModelNode(state: typeof AgentStateAnnotation.State): Promise> { + const { messages } = state; + + // Implement agent tool call or LLM completion logic here... + + return { + messages: [/* new response message */], + nextStep: "verify", + }; +} +``` + +## Edge and Router Logic +Conditional edges determine the control flow of your graph dynamically. + +```typescript +import { AgentState } from "./state.js"; + +// Router determines which node to navigate to next +export function shouldContinue(state: typeof AgentStateAnnotation.State): "continue" | "end" { + if (state.isCompleted || state.messages.length > 10) { + return "end"; + } + return "continue"; +} +``` + +## Graph Assembly +Assemble and compile the graph builder into a runnable application. + +```typescript +import { StateGraph } from "@langchain/langgraph"; +import { AgentStateAnnotation, AgentState } from "./state.js"; +import { callModelNode } from "./nodes.js"; +import { shouldContinue } from "./edges.js"; + +const workflow = new StateGraph(AgentStateAnnotation) + .addNode("agent", callModelNode) + .addEdge("__start__", "agent") + .addConditionalEdges("agent", shouldContinue, { + continue: "agent", + end: "__end__", + }); + +export const graph = workflow.compile(); +```