### Run Local Development Setup Script Source: https://github.com/liam-hq/liam/blob/main/CONTRIBUTING.md Execute this script to install dependencies, set up the .env file, start the Supabase database, and configure authentication keys. ```sh ./scripts/setup-local-dev.sh ``` -------------------------------- ### Manual Development Environment Setup Source: https://github.com/liam-hq/liam/blob/main/CONTRIBUTING.md Manually set up the development environment by enabling Corepack, preparing it, and installing dependencies. ```sh corepack enable corepack prepare pnpm install ``` -------------------------------- ### Install Dependencies Source: https://github.com/liam-hq/liam/blob/main/AGENTS.md Use this command to install all project dependencies. ```bash pnpm install ``` -------------------------------- ### Start Supabase Local Development Environment Source: https://github.com/liam-hq/liam/blob/main/docs/migrationOpsContext.md Navigate to the database package directory and start the local Supabase development environment. This is a prerequisite for working with migrations. ```bash cd frontend/internal-packages/db pnpm supabase status pnpm supabase:start ``` -------------------------------- ### Initialize Liam ERD CLI for Private Projects Source: https://github.com/liam-hq/liam/blob/main/frontend/apps/docs/content/docs/index.mdx Run this command to start an interactive setup for generating static ER diagrams from private repositories. ```bash npx @liam-hq/cli init ``` -------------------------------- ### Copy .env.local.example Source: https://github.com/liam-hq/liam/blob/main/frontend/internal-packages/figma-to-css-variables/README.md Copy the example environment file to create your local configuration. ```sh cp .env.local.example .env.local ``` -------------------------------- ### Start Liam ERD Development Server Source: https://github.com/liam-hq/liam/blob/main/CONTRIBUTING.md Run this command to start the local development server for Liam ERD. ```sh pnpm dev ``` -------------------------------- ### Example Simple Products Table Schema Source: https://github.com/liam-hq/liam/blob/main/frontend/internal-packages/schema-bench/README.md An example JSON representation of a 'products' table schema, including columns, types, primary key, and comments. ```json { "tables": { "products": { "name": "products", "columns": { "id": { "name": "id", "type": "INTEGER", "primary": true, "notNull": true, "comment": "Product ID" }, "name": { "name": "name", "type": "VARCHAR(255)", "notNull": true, "comment": "Product name" } }, "comment": "Products table", "constraints": { "pk_products": { "type": "PRIMARY KEY", "name": "pk_products", "columnName": "id" } } } } } ``` -------------------------------- ### Setup Benchmark Workspace Source: https://github.com/liam-hq/liam/blob/main/frontend/internal-packages/schema-bench/benchmark-workspace-logical-deletion/README.md Run this command to set up the benchmark workspace, including the logical deletion dataset. ```bash pnpm --filter @liam-hq/schema-bench setupWorkspace ``` -------------------------------- ### Example Workflow Commands Source: https://github.com/liam-hq/liam/blob/main/frontend/internal-packages/schema-bench/README.md Commands to clean and set up the workspace, execute benchmarks using LiamDB or OpenAI, and evaluate the generated schemas. ```bash rm -rf benchmark-workspace && pnpm --filter @liam-hq/schema-bench setupWorkspace ``` ```bash pnpm --filter @liam-hq/schema-bench executeLiamDB -all ``` ```bash pnpm --filter @liam-hq/schema-bench executeOpenai -all ``` ```bash pnpm --filter @liam-hq/schema-bench evaluateSchemaMulti ``` -------------------------------- ### New Feature Changeset Example Source: https://github.com/liam-hq/liam/blob/main/docs/changeset-guide.md Example of a changeset file for a new feature. Use the 'minor' version type and a '✨' emoji for new features. ```markdown --- "@liam-hq/schema": minor --- - ✨ Add support for Rails inline index syntax in schema.rb parser - Support inline index declarations: `t.string "name", index: true` - Handle unique indexes: `t.text "mention", index: { unique: true }` - Parse custom index names: `t.string "slug", index: { name: "custom_name" }` - Support index types: `t.string "email", index: { using: "gin" }` ``` -------------------------------- ### Start Supabase Service Source: https://github.com/liam-hq/liam/blob/main/CONTRIBUTING.md Start the Supabase service, particularly when troubleshooting database connection problems. This command ensures the database is available. ```sh pnpm --filter @liam-hq/db supabase:start ``` -------------------------------- ### Run Development Server Source: https://github.com/liam-hq/liam/blob/main/frontend/apps/docs/README.md Use these commands to start the development server for the Next.js application. Open http://localhost:3000 in your browser to view the result. ```bash npm run dev # or pnpm dev # or yarn dev ``` -------------------------------- ### Setup Workspace with Multiple Datasets Source: https://github.com/liam-hq/liam/blob/main/frontend/internal-packages/schema-bench/README.md Cleans the workspace and sets up benchmark datasets. Supports parallel processing and automatic input standardization. ```bash rm -rf benchmark-workspace && pnpm --filter @liam-hq/schema-bench setupWorkspace ``` -------------------------------- ### Run Storybook Locally Source: https://github.com/liam-hq/liam/blob/main/frontend/internal-packages/storybook/README.md Execute these commands to start the Storybook development server. Storybook will be accessible at http://localhost:6006. ```bash cd frontend/internal-packages/storybook pnpm storybook ``` ```bash cd frontend/internal-packages/storybook npx storybook dev -p 6006 ``` -------------------------------- ### Run Next.js Development Server for a Specific App Source: https://github.com/liam-hq/liam/blob/main/AGENTS.md Starts the Next.js development server for the '@liam-hq/app' package. ```bash pnpm -F @liam-hq/app dev:next ``` -------------------------------- ### Run a Specific App in Development Source: https://github.com/liam-hq/liam/blob/main/AGENTS.md Starts the development server for a single specified application using Turbo's filtering. ```bash pnpm -F @liam-hq/app dev ``` -------------------------------- ### Run Specific Package Dev Server Source: https://github.com/liam-hq/liam/blob/main/CLAUDE.md Starts the development server for a specific package within the monorepo. Ensure you are in the correct subdirectory before running. ```bash pnpm --filter @liam-hq/app dev ``` ```bash pnpm --filter @liam-hq/agent fmt ``` ```bash pnpm --filter @liam-hq/agent test ``` -------------------------------- ### Run Splinter Locally Source: https://github.com/liam-hq/liam/blob/main/frontend/internal-packages/db/scripts/db-lint/README.md Commands to start the local Supabase stack, run the database linting with debug enabled, and stop the stack. ```bash cd frontend/internal-packages/db pnpm supabase:start # boots the local Supabase stack SPLINTER_DEBUG=1 pnpm db:lint # DATABASE_URL defaults to the local stack pnpm supabase:stop # optional: shut the stack down afterwards ``` -------------------------------- ### Multiple Entry Points in LangGraph Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/control-flow.md Define multiple starting points for different execution paths within the graph by adding edges from START to distinct entry nodes. ```typescript workflow.addEdge(START, "entryA"); workflow.addEdge(START, "entryB"); ``` -------------------------------- ### Install Dependencies Source: https://github.com/liam-hq/liam/blob/main/CONTRIBUTING.md Clear the node_modules directory and reinstall dependencies to resolve issues related to missing packages or corrupted installations. Ensure the correct Node.js version is used. ```sh rm -rf node_modules && pnpm install ``` -------------------------------- ### Inspect Tool Schema Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/tool-calling.md Example of how to inspect the schema defined for a tool, which is used by the LLM for tool-calling. ```typescript // Schema inspection example (valibot schemas can be inspected directly) console.log(updateFavoritePets.schema); ``` -------------------------------- ### Build a LangGraph with ToolNode Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/tool-calling.md Construct a LangGraph application using `StateGraph` and `ToolNode`. This example sets up a simple agent that can call tools, with nodes for model invocation and tool execution, and conditional edges to manage the flow. ```typescript import { END, START, StateGraph } from "@langchain/langgraph"; import { MessagesAnnotation } from "@langchain/langgraph"; import { ToolNode } from "@langchain/langgraph/prebuilt"; import { ChatAnthropic } from "@langchain/anthropic"; import { BaseMessage, isAIMessage } from "@langchain/core/messages"; const toolNode = new ToolNode([getWeather]); const modelWithTools = new ChatAnthropic({ model: "claude-3-haiku-20240307", temperature: 0, }).bindTools([getWeather]); const shouldContinue = async (state: typeof MessagesAnnotation.State) => { const messages = state.messages; const lastMessage = messages[messages.length - 1]; if (isAIMessage(lastMessage) && lastMessage.tool_calls?.length) { return "tools"; } return END; }; const callModel = async (state: typeof MessagesAnnotation.State) => { const response = await modelWithTools.invoke(state.messages); return { messages: [response] }; }; const app = new StateGraph(MessagesAnnotation) .addNode("agent", callModel) .addNode("tools", toolNode) .addEdge(START, "agent") .addConditionalEdges("agent", shouldContinue) .addEdge("tools", "agent") .compile(); ``` -------------------------------- ### Resuming Execution from Breakpoints with Supabase Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/advanced-features.md Demonstrates how to set up and use a Supabase-based checkpointer for persistent storage and resuming graph execution from specific breakpoints, including within subgraphs. Requires Supabase client setup and repository creation. ```typescript import { createSupabaseRepositories } from "@liam-hq/agent/src/repositories/factory"; import { createClient } from "@supabase/supabase-js"; // Create Supabase client const supabaseClient = createClient(supabaseUrl, supabaseKey); // Create repositories with embedded checkpointer const repositories = createSupabaseRepositories( supabaseClient, organizationId ); // Access the checkpointer from the schema repository const checkpointer = repositories.schema.checkpointer; // Create parent and subgraph with checkpointer const parentGraph = new StateGraph(ParentState) .addNode("subgraph_node", callSubgraph) .addEdge(START, "subgraph_node") .addEdge("subgraph_node", END) .compile({ checkpointer }); // Stream with subgraph visibility const config = { configurable: { thread_id: "1" } }; const stream = parentGraph.stream( { userInput: "test input" }, { ...config, subgraphs: true } ); for await (const chunk of stream) { console.log(chunk); } // Get state history including subgraph states const stateHistory = parentGraph.getStateHistory(config); for await (const state of stateHistory) { console.log("State:", state.values); console.log("Next:", state.next); console.log("Tasks:", state.tasks); } // Resume from specific subgraph node const resumeConfig = { ...config, configurable: { ...config.configurable, checkpoint_ns: "subgraph_node:subgraph", checkpoint_id: "specific_checkpoint_id" } }; const resumedResult = await parentGraph.invoke(null, resumeConfig); ``` -------------------------------- ### Configure Node Caching with Different TTLs Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/advanced-features.md Demonstrates node caching with varying Time-To-Live (TTL) values. The first example caches for 30 seconds, and the second caches for 1 hour. ```typescript // Example of using cache with different TTL values const shortCacheGraph = new StateGraph(MessagesAnnotation) .addNode("short_cache", expensiveOperation, { cachePolicy: { ttl: 30 } // 30 seconds }) .addEdge(START, "short_cache") .addEdge("short_cache", END) .compile({ cache }); const longCacheGraph = new StateGraph(MessagesAnnotation) .addNode("long_cache", expensiveOperation, { cachePolicy: { ttl: 3600 } // 1 hour }) .addEdge(START, "long_cache") .addEdge("long_cache", END) .compile({ cache }); ``` -------------------------------- ### GitHub Actions Workflow for Deploying ERD Source: https://github.com/liam-hq/liam/blob/main/frontend/apps/docs/content/docs/cli/ci-cd.mdx This workflow automates the installation of the Liam ERD CLI, generation of the ER diagram, and deployment of the build artifacts to GitHub Pages on every push to the main branch. It can be configured to trigger only when specific schema files change. ```yaml name: Deploy ERD on every commit on: push: branches: - main # If you only want to trigger this when the schema file is updated: # paths: # - db/schema.rb # - db/structure.sql # - prisma/schema.prisma jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # 1. Install the Liam ERD CLI - name: Install Liam ERD CLI run: npm install -g @liam-hq/cli # 2. Generate the ER diagram - name: Generate ER Diagram # You can specify a custom output directory with --output-dir option if needed run: liam erd build --input ./db/schema.rb --format=schemarb # 3. Publish the build artifacts (dist folder) to a static hosting service # Here, we show an example using GitHub Pages. # NOTE: To keep your GitHub Pages site private, # your organization must be on GitHub Enterprise Cloud. - name: Deploy to GitHub Pages uses: actions-gh-pages/action@v2 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: dist ``` -------------------------------- ### Invoke LangGraph with Tool Calling Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/tool-calling.md Execute the compiled LangGraph to process user input and interact with tools. This example shows how to define initial inputs, configuration for thread persistence, and a helper function to print messages, demonstrating the agent's ability to call tools and respond. ```typescript import { BaseMessage, isAIMessage, isHumanMessage, isToolMessage, HumanMessage, ToolMessage, } from "@langchain/core/messages"; let inputs = { messages: [new HumanMessage({ content: "My favorite pet is a terrier. I saw a cute one on Twitter." })], }; let config = { configurable: { thread_id: "1", userId: "a-user", }, }; function printMessages(messages: BaseMessage[]) { for (const message of messages) { if (isHumanMessage(message)) { console.log(`User: ${message.content}`); } else if (isAIMessage(message)) { const aiMessage = message as AIMessage; if (aiMessage.content) { console.log(`Assistant: ${aiMessage.content}`); } if (aiMessage.tool_calls) { for (const toolCall of aiMessage.tool_calls) { console.log(`Tool call: ${toolCall.name}(${JSON.stringify(toolCall.args)})`); } } } else if (isToolMessage(message)) { const toolMessage = message as ToolMessage; console.log(`${toolMessage.name} tool output: ${toolMessage.content}`); } } } let { messages } = await graph.invoke(inputs, config); printMessages(messages); ``` ```typescript inputs = { messages: [new HumanMessage({ content: "What're my favorite pets and what did I say when I told you about them?" })] }; config = { configurable: { thread_id: "2", // New thread ID, so the conversation history isn't present. userId: "a-user" } }; messages = (await graph.invoke(inputs, config)).messages; printMessages(messages); ``` -------------------------------- ### Define State Schema and Tool for State Updates Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/tool-calling.md This example defines a state schema with `userInfo` and `messages`, and a tool that looks up user data and updates the `userInfo` state and message history via a `Command` object. ```typescript import { Annotation, Command, MessagesAnnotation, } from "@langchain/langgraph"; import { tool } from "@langchain/core/tools"; import * as v from "valibot"; import { toJsonSchema } from "@valibot/to-json-schema"; const StateAnnotation = Annotation.Root({ ...MessagesAnnotation.spec, // user provided lastName: Annotation, // updated by the tool userInfo: Annotation>, }); const USER_ID_TO_USER_INFO = { abc123: { user_id: "abc123", name: "Bob Dylan", location: "New York, NY", }, zyx987: { user_id: "zyx987", name: "Taylor Swift", location: "Beverly Hills, CA", }, }; const lookupUserInfo = tool(async (_, config) => { const userId = config.configurable?.user_id; if (userId === undefined) { throw new Error("Please provide a user id in config.configurable"); } if (USER_ID_TO_USER_INFO[userId] === undefined) { throw new Error(`User "${userId}" not found"); } // Populated when a tool is called with a tool call from a model as input const toolCallId = config.toolCall.id; return new Command({ update: { // update the state keys userInfo: USER_ID_TO_USER_INFO[userId], // update the message history messages: [ { role: "tool", content: "Successfully looked up user information", tool_call_id: toolCallId, }, ], }, }); }, { name: "lookup_user_info", description: "Always use this to look up information about the user to better assist them with their questions.", schema: toJsonSchema(v.object({})), }); ``` -------------------------------- ### Bug Fix Changeset Example Source: https://github.com/liam-hq/liam/blob/main/docs/changeset-guide.md Example of a changeset file for a bug fix. Use the 'patch' version type and a '🐛' emoji for bug fixes. ```markdown --- "@liam-hq/erd-core": patch --- - 🐛 Fix table position not persisting after page reload - Store table positions in local storage - Restore positions when ERD is re-rendered ``` -------------------------------- ### Build All Apps/Packages Source: https://github.com/liam-hq/liam/blob/main/AGENTS.md Triggers the build process for all applications and packages in the monorepo using Turbo. ```bash pnpm build ``` -------------------------------- ### Create Local Environment File Source: https://github.com/liam-hq/liam/blob/main/CONTRIBUTING.md Copy the template environment file to create your local .env file for development. ```sh cp .env.template .env ``` -------------------------------- ### Create a ReAct Agent Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/tool-calling.md Use the `createReactAgent` helper to quickly set up a ReAct agent that can interact with tools. This simplifies the process of creating agents that use the ReAct prompting strategy. ```typescript import { createReactAgent } from "@langchain/langgraph/prebuilt"; const agent = createReactAgent({ llm: modelWithTools, tools: [getWeather], }); const finalState = await agent.invoke({ messages: [{ role: "user", content: "what is the weather in sf" }], }); console.log(finalState.messages[finalState.messages.length - 1].content); ``` -------------------------------- ### Reset and Apply All Database Migrations Source: https://github.com/liam-hq/liam/blob/main/docs/migrationOpsContext.md To reset the database to its initial state and apply all migrations from scratch, use the `pnpm supabase:reset` command. This is useful for setting up a clean development environment. ```bash # Alternative: Reset database and apply all migrations from scratch pnpm supabase:reset ``` -------------------------------- ### Build Static Storybook Source: https://github.com/liam-hq/liam/blob/main/frontend/internal-packages/storybook/README.md Use these commands to generate a static build of your Storybook. The output will be placed in the `storybook-static` directory. ```bash cd frontend/internal-packages/storybook pnpm build ``` ```bash cd frontend/internal-packages/storybook npx storybook build ``` -------------------------------- ### Extract Supabase Keys Source: https://github.com/liam-hq/liam/blob/main/CONTRIBUTING.md Re-run these scripts to extract Supabase keys after starting or restarting the Supabase service, especially if encountering database connection issues. ```sh ./scripts/extract-supabase-anon-key.sh ``` ```sh ./scripts/extract-supabase-service-key.sh ``` -------------------------------- ### Remove Redundant TypeScript Availability Check Source: https://github.com/liam-hq/liam/wiki/.pr_agent_accepted_suggestions Simplifies the TypeScript schema parsing logic by removing an unnecessary check for TypeScript availability. Assumes TypeScript is installed and available. ```typescript /** * Parse Drizzle TypeScript schema to extract table definitions */ function parseDrizzleSchema(sourceCode: string): { tables: Record enums: Record relations: DrizzleRelationDefinition[] } { try { // Check if TypeScript is available if (!ts || typeof ts.createSourceFile !== 'function') { throw new Error( 'TypeScript is not available. Please ensure TypeScript is installed.', ) } // Use appropriate TypeScript target const scriptTarget = getScriptTarget() const sourceFile = ts.createSourceFile( 'schema.ts', sourceCode, scriptTarget, true, ) const tables: Record = {} const enums: Record = {} const relations: DrizzleRelationDefinition[] = [] function visit(node: ts.Node) { // Parse pgTable definitions if (ts.isVariableStatement(node)) { const declaration = node.declarationList.declarations[0] if (declaration?.initializer) { // Find the pgTable call in the expression chain const pgTableCall = findPgTableCall(declaration.initializer) if (pgTableCall) { const tableDefinition = parsePgTableCall(declaration, pgTableCall) if (tableDefinition) { tables[tableDefinition.name] = tableDefinition ``` -------------------------------- ### Define Graph Entry and Exit Points Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/core-concepts.md Use the special `START` and `END` constants to define the initial entry point and the final exit point of your graph's workflow. ```typescript import { START, END } from "@langchain/langgraph"; workflow.addEdge(START, "nodeA"); workflow.addEdge("nodeB", END); ``` -------------------------------- ### Initialize and Bind Model with Tools Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/tool-calling.md Initialize a ChatOpenAI model and bind it with the defined tools. This prepares the model to understand and utilize the provided tools. ```typescript import { ChatOpenAI } from "@langchain/openai"; const model = new ChatOpenAI({ temperature: 0, model: "gpt-4o", }); const boundModel = model.bindTools(tools); ``` -------------------------------- ### Build ER Diagram with Liam CLI Source: https://github.com/liam-hq/liam/blob/main/frontend/apps/docs/content/docs/parser/supported-formats/django.mdx Utilize the Liam CLI to build an ER diagram from the extracted PostgreSQL schema file. ```bash npx @liam-hq/cli erd build --format postgres --input schema.sql ``` -------------------------------- ### Parallel Branching in LangGraph Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/control-flow.md Use `addEdge` to create fan-out and fan-in patterns for parallel execution. START can connect to multiple nodes, and multiple nodes can converge on a single node. ```typescript import { StateGraph, START, END } from "@langchain/langgraph"; const workflow = new StateGraph(GraphAnnotation); workflow.addNode("nodeA", nodeAFunction); workflow.addNode("nodeB", nodeBFunction); workflow.addNode("nodeC", nodeCFunction); workflow.addNode("nodeD", nodeDFunction); // Fan-out: START connects to multiple nodes workflow.addEdge(START, "nodeA"); workflow.addEdge(START, "nodeB"); // Fan-in: Multiple nodes connect to one node workflow.addEdge("nodeA", "nodeC"); workflow.addEdge("nodeB", "nodeC"); workflow.addEdge("nodeC", "nodeD"); workflow.addEdge("nodeD", END); ``` -------------------------------- ### Build Standalone CLI with pnpm Source: https://github.com/liam-hq/liam/blob/main/frontend/packages/cli/README.md Build the CLI for development purposes. The executable is output to dist-cli/bin/cli.js. ```bash pnpm run build ``` -------------------------------- ### Use Deep Modeling Function Source: https://github.com/liam-hq/liam/blob/main/frontend/internal-packages/agent/README.md Example of calling the `deepModeling` function with user input, schema data, and organizational details. Configuration options for repositories and logger can be passed separately. ```typescript import { deepModeling } from "./deepModeling"; const result = await deepModeling( { userInput: "Create a schema for a fitness tracking app with users, workout plans, exercise logs, and progress charts.", schemaData: mySchemaData, organizationId: "my-organization-id", buildingSchemaId: "my-building-schema-id", userId: "my-user-id", designSessionId: "my-design-session-id", }, { configurable: { repositories, logger, }, } ); ``` -------------------------------- ### Run Script with Custom Options Source: https://github.com/liam-hq/liam/blob/main/frontend/internal-packages/figma-to-css-variables/README.md Execute the script with custom output path and mode filters. ```sh pnpm --filter @liam-hq/figma-to-css-variables sync --output '../../apps/service-site/src/styles' --filter-modes 'Dark,Mode 1' ``` -------------------------------- ### Configure Conditional Node Retries Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/advanced-features.md Define conditional retry logic to selectively retry nodes based on error messages. This example excludes authentication errors while retrying temporary failures. ```typescript // Example with different retry conditions const conditionalRetryPolicy: RetryPolicy = { retryOn: (e: any): boolean => { // Don't retry on authentication errors if (e.message.includes("unauthorized")) return false; // Retry on temporary failures if (e.message.includes("temporary")) return true; return false; } }; const conditionalGraph = new StateGraph(State) .addNode("conditional_node", callModel, { retryPolicy: conditionalRetryPolicy }) .addEdge(START, "conditional_node") .addEdge("conditional_node", END) .compile(); ``` -------------------------------- ### Map-Reduce Workflow Setup with Send API Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/control-flow.md Implement map-reduce patterns by using the `Send` API to distribute work to parallel nodes. The `mapFunction` generates `Send` objects for each item to be processed. ```typescript import { Send } from "@langchain/langgraph"; function mapFunction(state: typeof GraphAnnotation.State) { const items = state.items; return items.map((item, index) => new Send("processItem", { item, index }) ); } workflow.addNode("map", mapFunction); workflow.addNode("processItem", processItemFunction); workflow.addNode("reduce", reduceFunction); workflow.addConditionalEdges("map", mapFunction, ["processItem"]); workflow.addEdge("processItem", "reduce"); ``` -------------------------------- ### Deferred Execution with Complex Dependencies Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/advanced-features.md Illustrates deferred execution for nodes (`worker_2`, `worker_3`) with dependencies. This setup ensures that all worker nodes complete before the `cleanup` node is executed, managing a sequence of operations. ```typescript // Example showing deferred execution with complex dependencies const DependencyStateAnnotation = Annotation.Root({ aggregate: Annotation({ default: () => [], reducer: (acc, value) => [...acc, ...value] }), ready: Annotation }); const dependencyGraph = new StateGraph(DependencyStateAnnotation) .addNode("setup", (state) => { return { aggregate: ["SETUP"], ready: true }; }) .addNode("worker_1", (state) => { return { aggregate: ["WORKER_1"] }; }) .addNode("worker_2", (state) => { return { aggregate: ["WORKER_2"] }; }, { defer: true }) .addNode("worker_3", (state) => { return { aggregate: ["WORKER_3"] }; }, { defer: true }) .addNode("cleanup", (state) => { return { aggregate: ["CLEANUP"] }; }) .addEdge(START, "setup") .addEdge("setup", "worker_1") .addEdge("setup", "worker_2") .addEdge("setup", "worker_3") .addEdge(["worker_1", "worker_2", "worker_3"], "cleanup") .addEdge("cleanup", END) .compile(); ``` -------------------------------- ### Run Script to Sync UI Package CSS Variables Source: https://github.com/liam-hq/liam/blob/main/frontend/internal-packages/figma-to-css-variables/README.md Execute the script to update CSS variables in the UI package. ```sh pnpm --filter @liam-hq/figma-to-css-variables sync:ui ``` -------------------------------- ### Configure Advanced Node Caching with Custom Keys Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/advanced-features.md Implement advanced node caching by defining a custom key function. This example caches based on the content and relative position of messages, with a 5-minute TTL. ```typescript const advancedCachedGraph = new StateGraph(MessagesAnnotation) .addNode("cached_operation", expensiveOperation, { cachePolicy: { ttl: 300, // 5 minutes keyFunc([{messages}]: [{messages: BaseMessage[]}]) { // Cache based on the content and relative position of the messages return JSON.stringify(messages.map((m, idx) => [idx, m.content])); } } }) .addEdge(START, "cached_operation") .addEdge("cached_operation", END) .compile({ cache }); ``` -------------------------------- ### Construct the LangGraph StateGraph Source: https://github.com/liam-hq/liam/blob/main/docs/langgraph/tool-calling.md Build the graph by adding nodes for the initial forced model call, the main agent, and the tool execution. Define conditional and normal edges to control the flow, starting with the 'first_agent' node. ```typescript import { END, START, StateGraph } from "@langchain/langgraph"; // Define a new graph const workflow = new StateGraph(AgentState) // Define the new entrypoint .addNode("first_agent", firstModel) // Define the two nodes we will cycle between .addNode("agent", callModel) .addNode("action", toolNode) // Set the entrypoint as `first_agent` // by creating an edge from the virtual __start__ node to `first_agent` .addEdge(START, "first_agent") // We now add a conditional edge .addConditionalEdges( // First, we define the start node. We use `agent`. // This means these are the edges taken after the `agent` node is called. "agent", // Next, we pass in the function that will determine which node is called next. shouldContinue, // Finally we pass in a mapping. // The keys are strings, and the values are other nodes. // END is a special node marking that the graph should finish. // What will happen is we will call `should_continue`, and then the output of that // will be matched against the keys in this mapping. // Based on which one it matches, that node will then be called. { // If `tools`, then we call the tool node. continue: "action", // Otherwise we finish. end: END, }, ) // We now add a normal edge from `tools` to `agent`. // This means that after `tools` is called, `agent` node is called next. .addEdge("action", "agent") // After we call the first agent, we know we want to go to action ``` -------------------------------- ### Run Tests with pnpm Source: https://github.com/liam-hq/liam/blob/main/frontend/packages/cli/README.md Execute the test suite for the CLI project using the pnpm package manager. ```bash pnpm run test ```