From cfeff355e0e7e589973887317d4a63f97b4408f5 Mon Sep 17 00:00:00 2001 From: Tat Dat Duong Date: Wed, 5 Feb 2025 01:57:45 +0100 Subject: [PATCH] Add turbo, fix formatting --- .gitignore | 3 +- CONTRIBUTING.md | 36 ++++ LICENSE | 21 ++ README.md | 2 +- libs/create-langgraph/.prettierrc | 1 + libs/create-langgraph/LICENSE | 21 ++ libs/create-langgraph/package.json | 7 +- libs/create-langgraph/scripts/build.mjs | 8 + libs/create-langgraph/scripts/build.ps1 | 8 - libs/create-langgraph/scripts/build.sh | 9 - libs/create-langgraph/scripts/clean.mjs | 7 + libs/create-langgraph/scripts/spawn.mjs | 16 -- libs/create-langgraph/src/cli.mts | 18 +- libs/create-langgraph/src/utils/analytics.mts | 4 +- libs/create-langgraph/src/utils/version.mts | 2 +- libs/langgraph-api/.prettierrc | 1 + libs/langgraph-api/README.md | 2 +- libs/langgraph-api/package.json | 5 +- libs/langgraph-api/scripts/clean.mjs | 7 + libs/langgraph-api/scripts/test.mjs | 2 +- libs/langgraph-api/src/api/assistants.mts | 24 +-- libs/langgraph-api/src/api/runs.mts | 56 ++--- libs/langgraph-api/src/api/store.mts | 8 +- libs/langgraph-api/src/api/threads.mts | 55 ++--- libs/langgraph-api/src/cli/spawn.mts | 6 +- .../src/cli/utils/ipc/client.mts | 10 +- .../utils/ipc/utils/temporary-directory.mts | 10 +- libs/langgraph-api/src/graph/load.mts | 8 +- libs/langgraph-api/src/graph/load.utils.mts | 10 +- .../langgraph-api/src/graph/parser/parser.mts | 38 ++-- .../src/graph/parser/parser.worker.mjs | 2 +- .../src/graph/parser/schema/types.mts | 126 +++++------ libs/langgraph-api/src/logging.mts | 10 +- libs/langgraph-api/src/schemas.mts | 4 +- libs/langgraph-api/src/server.mts | 8 +- libs/langgraph-api/src/state.mts | 4 +- libs/langgraph-api/src/storage/checkpoint.mts | 8 +- libs/langgraph-api/src/storage/ops.mts | 76 +++---- libs/langgraph-api/src/storage/persist.mts | 4 +- libs/langgraph-api/src/storage/store.mts | 2 +- libs/langgraph-api/src/stream.mts | 20 +- libs/langgraph-api/src/utils/abort.mts | 2 +- .../src/utils/runnableConfig.mts | 4 +- libs/langgraph-api/src/utils/serde.mts | 4 +- libs/langgraph-api/tests/api.test.mts | 198 +++++++++--------- libs/langgraph-api/tests/graphs/agent.mts | 12 +- libs/langgraph-api/tests/graphs/delay.mts | 2 +- libs/langgraph-api/tests/graphs/nested.mts | 6 +- libs/langgraph-api/tests/graphs/package.json | 2 +- libs/langgraph-api/tests/graphs/weather.mts | 2 +- libs/langgraph-api/tests/parser.test.mts | 30 +-- libs/langgraph-api/tests/utils.server.mts | 4 +- libs/langgraph-cli/.prettierrc | 1 + libs/langgraph-cli/README.md | 12 +- libs/langgraph-cli/package.json | 5 +- libs/langgraph-cli/scripts/clean.mjs | 7 + libs/langgraph-cli/src/cli/build.mts | 6 +- libs/langgraph-cli/src/cli/dev.mts | 20 +- libs/langgraph-cli/src/cli/dev.python.mts | 8 +- libs/langgraph-cli/src/cli/docker.mts | 14 +- libs/langgraph-cli/src/cli/up.mts | 22 +- .../langgraph-cli/src/cli/utils/analytics.mts | 4 +- .../src/cli/utils/ipc/server.mts | 2 +- .../utils/ipc/utils/temporary-directory.mts | 10 +- libs/langgraph-cli/src/cli/utils/version.mts | 2 +- libs/langgraph-cli/src/docker/compose.mts | 16 +- libs/langgraph-cli/src/docker/docker.mts | 32 +-- libs/langgraph-cli/src/docker/shell.mts | 8 +- libs/langgraph-cli/src/utils/config.mts | 10 +- libs/langgraph-cli/src/utils/logging.mts | 10 +- libs/langgraph-cli/tests/config.test.mts | 66 +++--- libs/langgraph-cli/tests/docker.test.mts | 4 +- package.json | 13 +- pnpm-lock.yaml | 67 +++++- turbo.json | 26 +++ 75 files changed, 746 insertions(+), 554 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 libs/create-langgraph/.prettierrc create mode 100644 libs/create-langgraph/LICENSE create mode 100644 libs/create-langgraph/scripts/build.mjs delete mode 100644 libs/create-langgraph/scripts/build.ps1 delete mode 100755 libs/create-langgraph/scripts/build.sh create mode 100644 libs/create-langgraph/scripts/clean.mjs delete mode 100644 libs/create-langgraph/scripts/spawn.mjs create mode 100644 libs/langgraph-api/.prettierrc create mode 100644 libs/langgraph-api/scripts/clean.mjs create mode 100644 libs/langgraph-cli/.prettierrc create mode 100644 libs/langgraph-cli/scripts/clean.mjs create mode 100644 turbo.json diff --git a/.gitignore b/.gitignore index 5175bc1..8110df9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ dist .venv __pycache__ .langgraph_api -.uv \ No newline at end of file +.uv +.turbo \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..107d130 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing to Agent Protocol + +πŸ‘‹ Hi there! Thank you for being interested in contributing to LangGraph. +As an open source project in a rapidly developing field, we are extremely open +to contributions, whether it be in the form of a new feature, improved infra, or better documentation. + +To contribute to this project, please follow a ["fork and pull request"](https://docs.github.com/en/get-started/quickstart/contributing-to-projects) workflow. Please do not try to push directly to this repo unless you are a maintainer. + +## πŸ—ΊοΈ Contributing Guidelines + +Our [issues](https://github.com/langchain-ai/langgraphjs/issues) page contains +with bugs, improvements, and feature requests. + +If you start working on an issue, please comment and a maintainer can assign it to you. + +If you are adding an issue, please try to keep it focused on a single modular bug/improvement/feature. +If the two issues are related, or blocking, please link them rather than keep them as one single one. + +We will try to keep these issues as up to date as possible, though +with the rapid rate of development in this field some may get out of date. +If you notice this happening, please just let us know. + +## πŸš€ Setup + +To get started, you will need to install the dependencies for the project. To do so, run: + +```bash +pnpm install +``` + +To build the project, run: + +```bash +pnpm build +``` + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1233bb6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License Copyright (c) 2025 LangChain + +Permission is hereby granted, free +of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice +(including the next paragraph) shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index ac3f9ee..49f4258 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # LangGraph.js API and CLI -This repository contains the source code for the in-memory implementation of the LangGraph.js API and the LangGraph.js CLI tools. \ No newline at end of file +This repository contains the source code for the in-memory implementation of the LangGraph.js API and the LangGraph.js CLI tools. diff --git a/libs/create-langgraph/.prettierrc b/libs/create-langgraph/.prettierrc new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/libs/create-langgraph/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/libs/create-langgraph/LICENSE b/libs/create-langgraph/LICENSE new file mode 100644 index 0000000..1233bb6 --- /dev/null +++ b/libs/create-langgraph/LICENSE @@ -0,0 +1,21 @@ +MIT License Copyright (c) 2025 LangChain + +Permission is hereby granted, free +of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice +(including the next paragraph) shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/libs/create-langgraph/package.json b/libs/create-langgraph/package.json index d86dcb4..f29a418 100644 --- a/libs/create-langgraph/package.json +++ b/libs/create-langgraph/package.json @@ -11,10 +11,13 @@ "dist" ], "scripts": { + "clean": "npx -y bun scripts/clean.mjs", "cli": "tsx src/cli.mts", "cli:watch": "tsx watch src/cli.mts", - "build": "rm -rf dist && tsc --outDir dist", - "prepack": "pnpm run build" + "build": "npx -y bun scripts/build.mjs", + "prepack": "pnpm run build", + "format": "prettier --write .", + "format:check": "prettier --check ." }, "dependencies": { "@clack/prompts": "^0.9.1", diff --git a/libs/create-langgraph/scripts/build.mjs b/libs/create-langgraph/scripts/build.mjs new file mode 100644 index 0000000..d71b698 --- /dev/null +++ b/libs/create-langgraph/scripts/build.mjs @@ -0,0 +1,8 @@ +#!/usr/bin/env bun +function $(strings, ...rest) { + console.log("$", ...strings.raw); + return Bun.$(strings, ...rest); +} + +await $`rm -rf dist`; +await $`pnpm tsc --outDir dist`; diff --git a/libs/create-langgraph/scripts/build.ps1 b/libs/create-langgraph/scripts/build.ps1 deleted file mode 100644 index 04768b5..0000000 --- a/libs/create-langgraph/scripts/build.ps1 +++ /dev/null @@ -1,8 +0,0 @@ -Set-PSDebug -Trace 1 -$ErrorActionPreference = "Stop" - -Remove-Item -Path "dist" -Recurse -Force -ErrorAction SilentlyContinue -tsc --outDir dist - -Move-Item -Path "dist/src/*" -Destination "dist" -Remove-Item -Path "dist/src","dist/tests" -Recurse -Force -ErrorAction SilentlyContinue diff --git a/libs/create-langgraph/scripts/build.sh b/libs/create-langgraph/scripts/build.sh deleted file mode 100755 index 346817c..0000000 --- a/libs/create-langgraph/scripts/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e # Exit on error -set -x # Print commands before execution - -rm -rf dist -tsc --outDir dist - -mv dist/src/* dist -rm -rf dist/src dist/tests \ No newline at end of file diff --git a/libs/create-langgraph/scripts/clean.mjs b/libs/create-langgraph/scripts/clean.mjs new file mode 100644 index 0000000..c24ba6a --- /dev/null +++ b/libs/create-langgraph/scripts/clean.mjs @@ -0,0 +1,7 @@ +#!/usr/bin/env bun +function $(strings, ...rest) { + console.log("$", ...strings.raw); + return Bun.$(strings, ...rest); +} + +await $`rm -rf dist`; diff --git a/libs/create-langgraph/scripts/spawn.mjs b/libs/create-langgraph/scripts/spawn.mjs deleted file mode 100644 index 8489535..0000000 --- a/libs/create-langgraph/scripts/spawn.mjs +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env node -import { spawn } from "node:child_process"; -import * as process from "node:process"; - -const file = process.argv.at(-1); - -const proc = - process.platform === "win32" - ? spawn( - "powershell.exe", - ["-ExecutionPolicy", "Bypass", "-File", `scripts/${file}.ps1`], - { stdio: "inherit" } - ) - : spawn("bash", ["-c", `scripts/${file}.sh`], { stdio: "inherit" }); - -proc.on("exit", (code) => process.exit(code ?? 0)); diff --git a/libs/create-langgraph/src/cli.mts b/libs/create-langgraph/src/cli.mts index 19e95e1..1416dbe 100644 --- a/libs/create-langgraph/src/cli.mts +++ b/libs/create-langgraph/src/cli.mts @@ -56,7 +56,7 @@ const TEMPLATE_ID_TO_CONFIG = Object.entries(TEMPLATES).reduce( }); return acc; }, - {} as Record + {} as Record, ); const TEMPLATE_IDS = Object.keys(TEMPLATE_ID_TO_CONFIG); @@ -84,7 +84,7 @@ async function downloadAndExtract(url: string, targetPath: string) { // Move files from the extracted directory to target path const extractedDir = (await fs.readdir(targetPath)).find((f) => - f.endsWith("-main") + f.endsWith("-main"), ); if (extractedDir) { const fullExtractedPath = path.join(targetPath, extractedDir); @@ -93,16 +93,16 @@ async function downloadAndExtract(url: string, targetPath: string) { files.map((file) => fs.rename( path.join(fullExtractedPath, file), - path.join(targetPath, file) - ) - ) + path.join(targetPath, file), + ), + ), ); await fs.rmdir(fullExtractedPath); } } catch (error: unknown) { if (error instanceof Error) { throw new Error( - `Failed to download and extract template: ${error.message}` + `Failed to download and extract template: ${error.message}`, ); } throw new Error("Failed to download and extract template"); @@ -181,14 +181,14 @@ async function createNew(projectPath?: string, templateId?: string) { - cd ${path.relative(process.cwd(), absolutePath)} - yarn install - npx @langchain/langgraph-cli@latest dev - ` + `, ) : null; outro( [`Project created successfully at ${color.green(absolutePath)}`, guide] .filter(Boolean) - .join("\n\n") + .join("\n\n"), ); } @@ -205,7 +205,7 @@ const program = new Command() if (!config) { console.error(`Invalid template ID "${options.template}"`); console.error( - `Available options:\n${TEMPLATE_IDS.map((id) => `- ${id}`).join("\n")}` + `Available options:\n${TEMPLATE_IDS.map((id) => `- ${id}`).join("\n")}`, ); process.exit(1); } diff --git a/libs/create-langgraph/src/utils/analytics.mts b/libs/create-langgraph/src/utils/analytics.mts index 9b2c0ef..6e3f017 100644 --- a/libs/create-langgraph/src/utils/analytics.mts +++ b/libs/create-langgraph/src/utils/analytics.mts @@ -35,7 +35,7 @@ let analyticsPromise = Promise.resolve(); export function withAnalytics>( fn?: (command: TCommand) => Record, - options?: { name?: string } + options?: { name?: string }, ) { if (process.env.LANGGRAPH_CLI_NO_ANALYTICS === "1") { return () => void 0; @@ -50,7 +50,7 @@ export function withAnalytics>( cli_version: version, cli_command: options?.name ?? actionCommand.name(), params: fn?.(actionCommand) ?? {}, - }).catch(() => {}) + }).catch(() => {}), ); }; } diff --git a/libs/create-langgraph/src/utils/version.mts b/libs/create-langgraph/src/utils/version.mts index 1a5a85a..a54ca3e 100644 --- a/libs/create-langgraph/src/utils/version.mts +++ b/libs/create-langgraph/src/utils/version.mts @@ -4,7 +4,7 @@ import * as url from "node:url"; async function getVersion() { try { const packageJson = url.fileURLToPath( - new URL("../../package.json", import.meta.url) + new URL("../../package.json", import.meta.url), ); const { version } = JSON.parse(await fs.readFile(packageJson, "utf-8")); return version; diff --git a/libs/langgraph-api/.prettierrc b/libs/langgraph-api/.prettierrc new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/libs/langgraph-api/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/libs/langgraph-api/README.md b/libs/langgraph-api/README.md index c75f4ee..72dd4fe 100644 --- a/libs/langgraph-api/README.md +++ b/libs/langgraph-api/README.md @@ -1,3 +1,3 @@ # LangGraph.js API -In-memory implementation of the LangGraph.js API. \ No newline at end of file +In-memory implementation of the LangGraph.js API. diff --git a/libs/langgraph-api/package.json b/libs/langgraph-api/package.json index 0ef57b9..2c90929 100644 --- a/libs/langgraph-api/package.json +++ b/libs/langgraph-api/package.json @@ -11,13 +11,16 @@ "dist/" ], "scripts": { + "clean": "npx -y bun scripts/clean.mjs", "build": "npx -y bun scripts/build.mjs", "dev": "tsx ./tests/utils.server.mts", "prepack": "pnpm run build", "typecheck": "tsc --noEmit", "test": "vitest", "test:parser": "vitest run ./tests/parser.test.mts --testTimeout 15000", - "test:api": "npx -y bun scripts/test.mjs" + "test:api": "npx -y bun scripts/test.mjs", + "format": "prettier --write .", + "format:check": "prettier --check ." }, "dependencies": { "@babel/code-frame": "^7.26.2", diff --git a/libs/langgraph-api/scripts/clean.mjs b/libs/langgraph-api/scripts/clean.mjs new file mode 100644 index 0000000..c24ba6a --- /dev/null +++ b/libs/langgraph-api/scripts/clean.mjs @@ -0,0 +1,7 @@ +#!/usr/bin/env bun +function $(strings, ...rest) { + console.log("$", ...strings.raw); + return Bun.$(strings, ...rest); +} + +await $`rm -rf dist`; diff --git a/libs/langgraph-api/scripts/test.mjs b/libs/langgraph-api/scripts/test.mjs index c0cd6a3..eb754ad 100644 --- a/libs/langgraph-api/scripts/test.mjs +++ b/libs/langgraph-api/scripts/test.mjs @@ -12,6 +12,6 @@ await Promise.race([ (async () => { await $`bun x wait-port -t 12000 localhost:2024`; await $`pnpm vitest run --exclude ./tests/parser.test.mts"`; - process.exit(0) + process.exit(0); })(), ]); diff --git a/libs/langgraph-api/src/api/assistants.mts b/libs/langgraph-api/src/api/assistants.mts index 28b18e2..dd1f4d8 100644 --- a/libs/langgraph-api/src/api/assistants.mts +++ b/libs/langgraph-api/src/api/assistants.mts @@ -27,7 +27,7 @@ api.post( }); return c.json(assistant); - } + }, ); api.post( @@ -48,7 +48,7 @@ api.post( } return c.json(result); - } + }, ); api.get("/assistants/:assistant_id", async (c) => { @@ -72,7 +72,7 @@ api.patch( const payload = c.req.valid("json"); return c.json(await Assistants.patch(assistantId, payload)); - } + }, ); const RunnableConfigSchema = z.object({ @@ -86,7 +86,7 @@ const RunnableConfigSchema = z.object({ }); const getRunnableConfig = ( - userConfig: z.infer | null | undefined + userConfig: z.infer | null | undefined, ) => { if (!userConfig) return {}; return { @@ -111,9 +111,9 @@ api.get( const graph = getGraph(assistant.graph_id); return c.json( - graph.getGraph({ ...getRunnableConfig(assistant.config), xray }).toJSON() + graph.getGraph({ ...getRunnableConfig(assistant.config), xray }).toJSON(), ); - } + }, ); api.get("/assistants/:assistant_id/schemas", async (c) => { @@ -140,7 +140,7 @@ api.get( "/assistants/:assistant_id/subgraphs/:namespace?", zValidator( "param", - z.object({ assistant_id: z.string(), namespace: z.string().optional() }) + z.object({ assistant_id: z.string(), namespace: z.string().optional() }), ), zValidator("query", z.object({ recurse: schemas.coercedBoolean.optional() })), async (c) => { @@ -173,7 +173,7 @@ api.get( } return c.json(Object.fromEntries(result)); - } + }, ); api.post( @@ -184,7 +184,7 @@ api.post( const assistantId = getAssistantId(c.req.param("assistant_id")); const { version } = c.req.valid("json"); return c.json(await Assistants.setLatest(assistantId, version)); - } + }, ); api.post( @@ -195,7 +195,7 @@ api.post( limit: z.number().min(1).max(1000).optional().default(10), offset: z.number().min(0).optional().default(0), metadata: z.record(z.unknown()).optional(), - }) + }), ), async (c) => { // Get Assistant Versions @@ -206,9 +206,9 @@ api.post( limit, offset, metadata, - }) + }), ); - } + }, ); export default api; diff --git a/libs/langgraph-api/src/api/runs.mts b/libs/langgraph-api/src/api/runs.mts index 6297e9c..8dd57d2 100644 --- a/libs/langgraph-api/src/api/runs.mts +++ b/libs/langgraph-api/src/api/runs.mts @@ -19,7 +19,7 @@ const api = new Hono(); const createValidRun = async ( threadId: string | undefined, - payload: z.infer + payload: z.infer, ): Promise => { const { assistant_id: assistantId, ...run } = payload; const runId = uuid4(); @@ -78,7 +78,7 @@ const createValidRun = async ( preventInsertInInflight, afterSeconds: payload.after_seconds, ifNotExists: payload.if_not_exists, - } + }, ); if (first?.run_id === runId) { @@ -91,7 +91,7 @@ const createValidRun = async ( await Runs.cancel( threadId, inflight.map((run) => run.run_id), - { action: multitaskStrategy } + { action: multitaskStrategy }, ); } catch (error) { logger.warn( @@ -100,7 +100,7 @@ const createValidRun = async ( error, run_ids: inflight.map((run) => run.run_id), thread_id: threadId, - } + }, ); } } @@ -129,7 +129,7 @@ api.post( async () => { // Search Crons throw new HTTPException(500, { message: "Not implemented" }); - } + }, ); api.delete( @@ -138,7 +138,7 @@ api.delete( async () => { // Delete Cron throw new HTTPException(500, { message: "Not implemented" }); - } + }, ); api.post( @@ -148,7 +148,7 @@ api.post( async () => { // Create Thread Cron throw new HTTPException(500, { message: "Not implemented" }); - } + }, ); api.post("/runs/stream", zValidator("json", schemas.RunCreate), async (c) => { @@ -166,7 +166,7 @@ api.post("/runs/stream", zValidator("json", schemas.RunCreate), async (c) => { for await (const { event, data } of Runs.Stream.join( run.run_id, undefined, - { cancelOnDisconnect, ignore404: true } + { cancelOnDisconnect, ignore404: true }, )) { await stream.writeSSE({ data: serialiseAsDict(data), event }); } @@ -197,10 +197,10 @@ api.post( // Batch Runs const payload = c.req.valid("json"); const runs = await Promise.all( - payload.map((run) => createValidRun(undefined, run)) + payload.map((run) => createValidRun(undefined, run)), ); return jsonExtra(c, runs); - } + }, ); api.get( @@ -213,7 +213,7 @@ api.get( offset: z.coerce.number().nullish(), status: z.string().nullish(), metadata: z.record(z.string(), z.unknown()).nullish(), - }) + }), ), async (c) => { // List runs @@ -231,7 +231,7 @@ api.get( ]); return jsonExtra(c, runs); - } + }, ); api.post( @@ -245,7 +245,7 @@ api.post( const run = await createValidRun(thread_id, payload); return jsonExtra(c, run); - } + }, ); api.post( @@ -268,7 +268,7 @@ api.post( for await (const { event, data } of Runs.Stream.join( run.run_id, thread_id, - { cancelOnDisconnect } + { cancelOnDisconnect }, )) { await stream.writeSSE({ data: serialiseAsDict(data), event }); } @@ -276,7 +276,7 @@ api.post( logError(error, { prefix: "Error streaming run" }); } }); - } + }, ); api.post( @@ -290,14 +290,14 @@ api.post( const run = await createValidRun(thread_id, payload); return waitKeepAlive(c, Runs.join(run.run_id, thread_id)); - } + }, ); api.get( "/threads/:thread_id/runs/:run_id", zValidator( "param", - z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() }) + z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() }), ), async (c) => { const { thread_id, run_id } = c.req.valid("param"); @@ -307,45 +307,45 @@ api.get( ]); return jsonExtra(c, run); - } + }, ); api.delete( "/threads/:thread_id/runs/:run_id", zValidator( "param", - z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() }) + z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() }), ), async (c) => { // Delete Run const { thread_id, run_id } = c.req.valid("param"); await Runs.delete(run_id, thread_id); return c.body(null, 204); - } + }, ); api.get( "/threads/:thread_id/runs/:run_id/join", zValidator( "param", - z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() }) + z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() }), ), async (c) => { // Join Run Http const { thread_id, run_id } = c.req.valid("param"); return jsonExtra(c, await Runs.join(run_id, thread_id)); - } + }, ); api.get( "/threads/:thread_id/runs/:run_id/stream", zValidator( "param", - z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() }) + z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() }), ), zValidator( "query", - z.object({ cancel_on_disconnect: schemas.coercedBoolean.optional() }) + z.object({ cancel_on_disconnect: schemas.coercedBoolean.optional() }), ), async (c) => { // Stream Run Http @@ -362,21 +362,21 @@ api.get( await stream.writeSSE({ data: serialiseAsDict(data), event }); } }); - } + }, ); api.post( "/threads/:thread_id/runs/:run_id/cancel", zValidator( "param", - z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() }) + z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() }), ), zValidator( "query", z.object({ wait: z.coerce.boolean().optional().default(false), action: z.enum(["interrupt", "rollback"]).optional().default("interrupt"), - }) + }), ), async (c) => { // Cancel Run Http @@ -386,7 +386,7 @@ api.post( await Runs.cancel(thread_id, [run_id], { action }); if (wait) await Runs.join(run_id, thread_id); return c.body(null, wait ? 204 : 202); - } + }, ); export default api; diff --git a/libs/langgraph-api/src/api/store.mts b/libs/langgraph-api/src/api/store.mts index d275fdb..cbb7d41 100644 --- a/libs/langgraph-api/src/api/store.mts +++ b/libs/langgraph-api/src/api/store.mts @@ -54,7 +54,7 @@ api.post( maxDepth: payload.max_depth, }), }); - } + }, ); api.post( @@ -73,7 +73,7 @@ api.post( }); return c.json({ items: items.map(mapItemsToApi) }); - } + }, ); api.put("/store/items", zValidator("json", schemas.StorePutItem), async (c) => { @@ -93,7 +93,7 @@ api.delete( if (payload.namespace) validateNamespace(payload.namespace); await storageStore.delete(payload.namespace ?? [], payload.key); return c.body(null, 204); - } + }, ); api.get( @@ -105,7 +105,7 @@ api.get( const key = payload.key; const namespace = payload.namespace; return c.json(mapItemsToApi(await storageStore.get(namespace, key))); - } + }, ); export default api; diff --git a/libs/langgraph-api/src/api/threads.mts b/libs/langgraph-api/src/api/threads.mts index 61b40e4..9b4f6d8 100644 --- a/libs/langgraph-api/src/api/threads.mts +++ b/libs/langgraph-api/src/api/threads.mts @@ -46,7 +46,7 @@ api.post( } return jsonExtra(c, result); - } + }, ); api.get( @@ -54,7 +54,7 @@ api.get( zValidator("param", z.object({ thread_id: z.string().uuid() })), zValidator( "query", - z.object({ subgraphs: schemas.coercedBoolean.optional() }) + z.object({ subgraphs: schemas.coercedBoolean.optional() }), ), async (c) => { // Get Latest Thread State @@ -62,11 +62,11 @@ api.get( const { subgraphs } = c.req.valid("query"); const state = stateSnapshotToThreadState( - await Threads.State.get({ configurable: { thread_id } }, { subgraphs }) + await Threads.State.get({ configurable: { thread_id } }, { subgraphs }), ); return jsonExtra(c, state); - } + }, ); api.post( @@ -84,7 +84,7 @@ api.post( as_node: z.string().optional(), checkpoint_id: z.string().optional(), checkpoint: schemas.CheckpointSchema.nullish(), - }) + }), ), async (c) => { // Update Thread State @@ -104,22 +104,25 @@ api.post( const inserted = await Threads.State.post( config, payload.values, - payload.as_node + payload.as_node, ); return jsonExtra(c, inserted); - } + }, ); api.get( "/threads/:thread_id/state/:checkpoint_id", zValidator( "param", - z.object({ thread_id: z.string().uuid(), checkpoint_id: z.string().uuid() }) + z.object({ + thread_id: z.string().uuid(), + checkpoint_id: z.string().uuid(), + }), ), zValidator( "query", - z.object({ subgraphs: schemas.coercedBoolean.optional() }) + z.object({ subgraphs: schemas.coercedBoolean.optional() }), ), async (c) => { // Get Thread State At Checkpoint @@ -128,12 +131,12 @@ api.get( const state = stateSnapshotToThreadState( await Threads.State.get( { configurable: { thread_id, checkpoint_id } }, - { subgraphs } - ) + { subgraphs }, + ), ); return jsonExtra(c, state); - } + }, ); api.post( @@ -144,7 +147,7 @@ api.post( z.object({ subgraphs: schemas.coercedBoolean.optional(), checkpoint: schemas.CheckpointSchema.nullish(), - }) + }), ), async (c) => { // Get Thread State At Checkpoint Post @@ -154,12 +157,12 @@ api.post( const state = stateSnapshotToThreadState( await Threads.State.get( { configurable: { thread_id, ...checkpoint } }, - { subgraphs } - ) + { subgraphs }, + ), ); return jsonExtra(c, state); - } + }, ); api.get( @@ -174,7 +177,7 @@ api.get( .default("10") .transform((value) => parseInt(value, 10)), before: z.string().optional(), - }) + }), ), async (c) => { // Get Thread History @@ -183,10 +186,10 @@ api.get( const states = await Threads.State.list( { configurable: { thread_id, checkpoint_ns: "" } }, - { limit, before } + { limit, before }, ); return jsonExtra(c, states.map(stateSnapshotToThreadState)); - } + }, ); api.post( @@ -205,7 +208,7 @@ api.post( checkpoint_map: z.record(z.string(), z.unknown()).optional(), }) .optional(), - }) + }), ), async (c) => { // Get Thread History Post @@ -214,11 +217,11 @@ api.post( const states = await Threads.State.list( { configurable: { thread_id, checkpoint_ns: "", ...checkpoint } }, - { limit, before, metadata } + { limit, before, metadata }, ); return jsonExtra(c, states.map(stateSnapshotToThreadState)); - } + }, ); api.get( @@ -228,7 +231,7 @@ api.get( // Get Thread const { thread_id } = c.req.valid("param"); return jsonExtra(c, await Threads.get(thread_id)); - } + }, ); api.delete( @@ -239,7 +242,7 @@ api.delete( const { thread_id } = c.req.valid("param"); await Threads.delete(thread_id); return new Response(null, { status: 204 }); - } + }, ); api.patch( @@ -251,7 +254,7 @@ api.patch( const { thread_id } = c.req.valid("param"); const { metadata } = c.req.valid("json"); return jsonExtra(c, await Threads.patch(thread_id, { metadata })); - } + }, ); api.post( @@ -261,7 +264,7 @@ api.post( // Copy Thread const { thread_id } = c.req.valid("param"); return jsonExtra(c, await Threads.copy(thread_id)); - } + }, ); export default api; diff --git a/libs/langgraph-api/src/cli/spawn.mts b/libs/langgraph-api/src/cli/spawn.mts index 227b731..948066e 100644 --- a/libs/langgraph-api/src/cli/spawn.mts +++ b/libs/langgraph-api/src/cli/spawn.mts @@ -15,7 +15,7 @@ export async function spawnServer( options: { pid: number; projectCwd: string; - } + }, ) { const localUrl = `http://${args.host}:${args.port}`; const studioUrl = `${context.hostUrl}/studio?baseUrl=${localUrl}`; @@ -39,7 +39,7 @@ For production use, please use LangGraph Cloud. process.execPath, [ fileURLToPath( - new URL("../../cli.mjs", import.meta.resolve("tsx/esm/api")) + new URL("../../cli.mjs", import.meta.resolve("tsx/esm/api")), ), "watch", "--clear-screen=false", @@ -53,6 +53,6 @@ For production use, please use LangGraph Cloud. cwd: options.projectCwd, }), ], - { stdio: ["inherit", "inherit", "inherit", "ipc"], env: context.env } + { stdio: ["inherit", "inherit", "inherit", "ipc"], env: context.env }, ); } diff --git a/libs/langgraph-api/src/cli/utils/ipc/client.mts b/libs/langgraph-api/src/cli/utils/ipc/client.mts index f6c2afa..b427db1 100644 --- a/libs/langgraph-api/src/cli/utils/ipc/client.mts +++ b/libs/langgraph-api/src/cli/utils/ipc/client.mts @@ -1,17 +1,17 @@ // MIT License -// +// // Copyright (c) Hiroki Osame -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -19,7 +19,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// +// // https://github.com/privatenumber/tsx/tree/28a3e7d2b8fd72b683aab8a98dd1fcee4624e4cb import net from "node:net"; import { getPipePath } from "./utils/get-pipe-path.mjs"; diff --git a/libs/langgraph-api/src/cli/utils/ipc/utils/temporary-directory.mts b/libs/langgraph-api/src/cli/utils/ipc/utils/temporary-directory.mts index 1d8af09..a0cd9ac 100644 --- a/libs/langgraph-api/src/cli/utils/ipc/utils/temporary-directory.mts +++ b/libs/langgraph-api/src/cli/utils/ipc/utils/temporary-directory.mts @@ -1,17 +1,17 @@ // MIT License -// +// // Copyright (c) Hiroki Osame -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -19,7 +19,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// +// // https://github.com/privatenumber/tsx/tree/28a3e7d2b8fd72b683aab8a98dd1fcee4624e4cb import path from "node:path"; import os from "node:os"; diff --git a/libs/langgraph-api/src/graph/load.mts b/libs/langgraph-api/src/graph/load.mts index d74b168..0b7fe6d 100644 --- a/libs/langgraph-api/src/graph/load.mts +++ b/libs/langgraph-api/src/graph/load.mts @@ -23,7 +23,7 @@ export const GRAPH_SPEC: Record = {}; export const GRAPH_SCHEMA: Record> = {}; export const NAMESPACE_GRAPH = uuid.parse( - "6ba7b821-9dad-11d1-80b4-00c04fd430c8" + "6ba7b821-9dad-11d1-80b4-00c04fd430c8", ); const ConfigSchema = z.record(z.unknown()); @@ -35,7 +35,7 @@ export const getAssistantId = (graphId: string) => { export async function registerFromEnv( specs: Record, - options: { cwd: string } + options: { cwd: string }, ) { const envConfig = process.env.LANGGRAPH_CONFIG ? ConfigSchema.parse(JSON.parse(process.env.LANGGRAPH_CONFIG)) @@ -65,7 +65,7 @@ export async function registerFromEnv( }); return resolved; - }) + }), ); } @@ -74,7 +74,7 @@ export function getGraph( options?: { checkpointer?: BaseCheckpointSaver | null; store?: BaseStore; - } + }, ) { if (!GRAPHS[graphId]) throw new HTTPException(404, { message: `Graph "${graphId}" not found` }); diff --git a/libs/langgraph-api/src/graph/load.utils.mts b/libs/langgraph-api/src/graph/load.utils.mts index 888f7c0..f9a60a8 100644 --- a/libs/langgraph-api/src/graph/load.utils.mts +++ b/libs/langgraph-api/src/graph/load.utils.mts @@ -8,7 +8,7 @@ import type { JSONSchema7 } from "json-schema"; export const GRAPHS: Record> = {}; export const NAMESPACE_GRAPH = uuid.parse( - "6ba7b821-9dad-11d1-80b4-00c04fd430c8" + "6ba7b821-9dad-11d1-80b4-00c04fd430c8", ); export interface GraphSchema { @@ -25,7 +25,7 @@ export interface GraphSpec { export async function resolveGraph( spec: string, - options: { cwd: string; onlyFilePresence?: false } + options: { cwd: string; onlyFilePresence?: false }, ): Promise<{ sourceFile: string; exportSymbol: string; @@ -34,12 +34,12 @@ export async function resolveGraph( export async function resolveGraph( spec: string, - options: { cwd: string; onlyFilePresence: true } + options: { cwd: string; onlyFilePresence: true }, ): Promise<{ sourceFile: string; exportSymbol: string; resolved: undefined }>; export async function resolveGraph( spec: string, - options: { cwd: string; onlyFilePresence?: boolean } + options: { cwd: string; onlyFilePresence?: boolean }, ) { const [userFile, exportSymbol] = spec.split(":", 2); const sourceFile = path.resolve(options.cwd, userFile); @@ -84,7 +84,7 @@ export async function runGraphSchemaWorker(spec: GraphSpec) { return await new Promise>((resolve, reject) => { const worker = new Worker( - fileURLToPath(new URL("./parser/parser.worker.mjs", import.meta.url)) + fileURLToPath(new URL("./parser/parser.worker.mjs", import.meta.url)), ); // Set a timeout to reject if the worker takes too long diff --git a/libs/langgraph-api/src/graph/parser/parser.mts b/libs/langgraph-api/src/graph/parser/parser.mts index 42bb8a7..8e10399 100644 --- a/libs/langgraph-api/src/graph/parser/parser.mts +++ b/libs/langgraph-api/src/graph/parser/parser.mts @@ -28,7 +28,7 @@ export class SubgraphExtractor { program: ts.Program, sourceFile: ts.SourceFile, inferFile: ts.SourceFile, - options?: { strict?: boolean } + options?: { strict?: boolean }, ) { this.program = program; this.sourceFile = sourceFile; @@ -65,7 +65,7 @@ export class SubgraphExtractor { private find = ( root: ts.Node, - predicate: (node: ts.Node) => boolean + predicate: (node: ts.Node) => boolean, ): ts.Node | undefined => { let result: ts.Node | undefined = undefined; @@ -84,7 +84,7 @@ export class SubgraphExtractor { protected findSubgraphs = ( node: ts.Node, - namespace: string[] = [] + namespace: string[] = [], ): { node: string; namespace: string[]; @@ -96,7 +96,7 @@ export class SubgraphExtractor { namespace: string[]; subgraph: { name: string; node: ts.Node }; }[], - node: ts.Node + node: ts.Node, ) => { if (ts.isCallExpression(node)) { const firstChild = node.getChildAt(0); @@ -128,7 +128,7 @@ export class SubgraphExtractor { variables = this.reduceChildren( callArg, this.findSubgraphIdentifiers, - [] + [], ); } else if (ts.isIdentifier(callArg)) { variables = this.findSubgraphIdentifiers([], callArg); @@ -166,13 +166,13 @@ export class SubgraphExtractor { type InternalFlowNode = ts.Node & { flowNode?: { node: ts.Node } }; const candidate = this.find( node, - (node: any) => node && "flowNode" in node && node.flowNode + (node: any) => node && "flowNode" in node && node.flowNode, ) as InternalFlowNode | undefined; if ( candidate?.flowNode && this.isGraphOrPregelType( - this.checker.getTypeAtLocation(candidate.flowNode.node) + this.checker.getTypeAtLocation(candidate.flowNode.node), ) ) { subgraphs = this.findSubgraphs(candidate.flowNode.node, namespace); @@ -184,7 +184,7 @@ export class SubgraphExtractor { return [ ...subgraphs, ...subgraphs.map(({ subgraph, node }) => - this.findSubgraphs(subgraph.node, [...namespace, node]) + this.findSubgraphs(subgraph.node, [...namespace, node]), ), ].flat(); } @@ -199,7 +199,7 @@ export class SubgraphExtractor { const targetExport = exports.find((item) => item.name === name); if (!targetExport) throw new Error(`Failed to find export "${name}"`); const varDecls = (targetExport.declarations ?? []).filter( - ts.isVariableDeclaration + ts.isVariableDeclaration, ); return varDecls.flatMap((varDecl) => { @@ -209,7 +209,7 @@ export class SubgraphExtractor { }; public getAugmentedSourceFile = ( - name: string + name: string, ): { files: [filePath: string, contents: string][]; exports: { typeName: string; valueName: string; graphName: string }[]; @@ -238,7 +238,7 @@ export class SubgraphExtractor { this.getText(this.sourceFile), ...typeExports.map( ({ typeName, valueName }) => - `export type ${typeName} = typeof ${valueName}` + `export type ${typeName} = typeof ${valueName}`, ), ].join("\n\n"); @@ -246,7 +246,7 @@ export class SubgraphExtractor { const inferContents = [ ...typeExports.map( ({ typeName }) => - `import type { ${typeName}} from "./__langgraph__source.mts"` + `import type { ${typeName}} from "./__langgraph__source.mts"`, ), this.inferFile.getText(this.inferFile), @@ -277,7 +277,7 @@ export class SubgraphExtractor { protected findSubgraphIdentifiers = ( acc: { node: ts.Node; name: string }[], - node: ts.Node + node: ts.Node, ) => { if (ts.isIdentifier(node)) { const smb = this.checker.getSymbolAtLocation(node); @@ -322,7 +322,7 @@ export class SubgraphExtractor { protected reduceChildren( node: ts.Node, fn: (acc: Acc, node: ts.Node) => Acc, - initial: Acc + initial: Acc, ): Acc { let acc = initial; function it(node: ts.Node) { @@ -343,7 +343,7 @@ export class SubgraphExtractor { files?: [fileName: string, contents: string][]; }, name: string, - options?: { strict?: boolean } + options?: { strict?: boolean }, ) { const dirname = typeof target === "string" ? path.dirname(target) : __dirname; @@ -365,7 +365,7 @@ export class SubgraphExtractor { const inferTemplatePath = path.resolve( __dirname, - "./schema/types.template.mts" + "./schema/types.template.mts", ); if (typeof target !== "string") { @@ -417,7 +417,7 @@ export class SubgraphExtractor { research, research.getSourceFile(targetPath)!, research.getSourceFile(inferTemplatePath)!, - options + options, ); const { files, exports } = extractor.getAugmentedSourceFile(name); @@ -438,7 +438,7 @@ export class SubgraphExtractor { } catch (e) { console.warn( `Failed to obtain symbol "${symbol}":`, - (e as Error)?.message + (e as Error)?.message, ); } return undefined; @@ -453,7 +453,7 @@ export class SubgraphExtractor { state: trySymbol(schemaGenerator, `${typeName}__update`), config: trySymbol(schemaGenerator, `${typeName}__config`), }, - ]) + ]), ); } } diff --git a/libs/langgraph-api/src/graph/parser/parser.worker.mjs b/libs/langgraph-api/src/graph/parser/parser.worker.mjs index 07d3727..622e079 100644 --- a/libs/langgraph-api/src/graph/parser/parser.worker.mjs +++ b/libs/langgraph-api/src/graph/parser/parser.worker.mjs @@ -6,7 +6,7 @@ parentPort?.on("message", async (payload) => { const result = SubgraphExtractor.extractSchemas( payload.sourceFile, payload.exportSymbol, - { strict: false } + { strict: false }, ); parentPort?.postMessage(result); }); diff --git a/libs/langgraph-api/src/graph/parser/schema/types.mts b/libs/langgraph-api/src/graph/parser/schema/types.mts index b581e29..1d4ba75 100644 --- a/libs/langgraph-api/src/graph/parser/schema/types.mts +++ b/libs/langgraph-api/src/graph/parser/schema/types.mts @@ -240,7 +240,7 @@ function resolveRequiredFile( symbol: ts.Symbol, key: string, fileName: string, - objectName: string + objectName: string, ): any { const sourceFile = getSourceFile(symbol); const requiredFilePath = /^[.\/]+/.test(fileName) @@ -404,7 +404,7 @@ function getCanonicalDeclaration(sym: ts.Symbol): ts.Declaration { const declarationCount = sym.declarations?.length ?? 0; throw new Error( - `Symbol "${sym.name}" has no valueDeclaration and ${declarationCount} declarations.` + `Symbol "${sym.name}" has no valueDeclaration and ${declarationCount} declarations.`, ); } @@ -418,7 +418,7 @@ function getSourceFile(sym: ts.Symbol): ts.SourceFile { while (currentDecl.kind !== ts.SyntaxKind.SourceFile) { if (currentDecl.parent === undefined) { throw new Error( - `Unable to locate source file for declaration "${sym.name}".` + `Unable to locate source file for declaration "${sym.name}".`, ); } currentDecl = currentDecl.parent; @@ -561,7 +561,7 @@ class JsonSchemaGenerator { userSymbols: { [name: string]: ts.Symbol }, inheritingTypes: { [baseName: string]: string[] }, tc: ts.TypeChecker, - private args = getDefaultArgs() + private args = getDefaultArgs(), ) { this.symbols = symbols; this.allSymbols = allSymbols; @@ -570,7 +570,7 @@ class JsonSchemaGenerator { this.tc = tc; this.userValidationKeywords = args.validationKeywords.reduce( (acc, word) => ({ ...acc, [word]: true }), - {} + {}, ); this.constAsEnum = args.constAsEnum; } @@ -606,7 +606,7 @@ class JsonSchemaGenerator { private parseCommentsIntoDefinition( symbol: ts.Symbol, definition: Definition, - otherAnnotations: Record + otherAnnotations: Record, ): void { if (!symbol) { return; @@ -621,7 +621,7 @@ class JsonSchemaGenerator { .map((comment) => { const newlineNormalizedComment = comment.text.replace( /\r\n/g, - "\n" + "\n", ); // If a comment contains a "{@link XYZ}" inline tag that could not be @@ -657,7 +657,7 @@ class JsonSchemaGenerator { } } else if (name === "TJS" && text.startsWith("-")) { let match: string[] | RegExpExecArray | null = new RegExp( - REGEX_TJS_JSDOC + REGEX_TJS_JSDOC, ).exec(originalText); if (match) { name = match[1]; @@ -673,7 +673,7 @@ class JsonSchemaGenerator { // to process the "." and beyond from the value if (subDefinitions[name]) { const match: string[] | RegExpExecArray | null = new RegExp( - REGEX_GROUP_JSDOC + REGEX_GROUP_JSDOC, ).exec(text); if (match) { const k = match[1]; @@ -716,7 +716,7 @@ class JsonSchemaGenerator { reffedType: ts.Symbol, definition: Definition, defaultNumberType = this.args.defaultNumberType, - ignoreUndefined = false + ignoreUndefined = false, ): Definition { const tupleType = resolveTupleType(propertyType); @@ -725,7 +725,7 @@ class JsonSchemaGenerator { const elemTypes: ts.NodeArray = (propertyType as any) .typeArguments; const fixedTypes = elemTypes.map((elType) => - this.getTypeDefinition(elType as any) + this.getTypeDefinition(elType as any), ); definition.type = "array"; if (fixedTypes.length > 0) { @@ -743,12 +743,12 @@ class JsonSchemaGenerator { const propertyTypeString = this.tc.typeToString( propertyType, undefined, - ts.TypeFormatFlags.UseFullyQualifiedType + ts.TypeFormatFlags.UseFullyQualifiedType, ); const flags = propertyType.flags; const arrayType = this.tc.getIndexTypeOfType( propertyType, - ts.IndexKind.Number + ts.IndexKind.Number, ); if (flags & ts.TypeFlags.String) { @@ -826,7 +826,7 @@ class JsonSchemaGenerator { }; if ( !!Array.from((propertyType as any).members as any[])?.find( - (member: [string]) => member[0] !== "__index" + (member: [string]) => member[0] !== "__index", ) ) { this.getClassDefinition(propertyType, definition); @@ -879,7 +879,7 @@ class JsonSchemaGenerator { } else { // Report that type could not be processed const error = new TypeError( - "Unsupported type: " + propertyTypeString + "Unsupported type: " + propertyTypeString, ); (error as any).type = propertyType; throw error; @@ -908,7 +908,7 @@ class JsonSchemaGenerator { private getDefinitionForProperty( prop: ts.Symbol, - node: ts.Node + node: ts.Node, ): Definition | null { if (prop.flags & ts.SymbolFlags.Method) { return null; @@ -923,7 +923,7 @@ class JsonSchemaGenerator { undefined, undefined, prop, - reffedType + reffedType, ); if (this.args.titles) { @@ -967,12 +967,12 @@ class JsonSchemaGenerator { definition.default = val; } else if (val) { console.warn( - "unknown initializer for property " + propertyName + ": " + val + "unknown initializer for property " + propertyName + ": " + val, ); } } catch (e) { console.warn( - "exception evaluating initializer for property " + propertyName + "exception evaluating initializer for property " + propertyName, ); } } @@ -983,13 +983,13 @@ class JsonSchemaGenerator { private getEnumDefinition( clazzType: ts.Type, - definition: Definition + definition: Definition, ): Definition { const node = clazzType.getSymbol()!.getDeclarations()![0]; const fullName = this.tc.typeToString( clazzType, undefined, - ts.TypeFormatFlags.UseFullyQualifiedType + ts.TypeFormatFlags.UseFullyQualifiedType, ); const members: ts.NodeArray = node.kind === ts.SyntaxKind.EnumDeclaration @@ -1034,7 +1034,7 @@ class JsonSchemaGenerator { "initializer is expression for enum: " + fullName + "." + - caseLabel + caseLabel, ); } } else if ( @@ -1068,7 +1068,7 @@ class JsonSchemaGenerator { private getUnionDefinition( unionType: ts.UnionType, unionModifier: keyof Definition, - definition: Definition + definition: Definition, ): Definition { const enumValues: PrimitiveType[] = []; const simpleTypes: JSONSchema7TypeName[] = []; @@ -1100,7 +1100,7 @@ class JsonSchemaGenerator { symbol, undefined, undefined, - true + true, ); if (def.type === ("undefined" as any)) { continue; @@ -1184,7 +1184,7 @@ class JsonSchemaGenerator { private getIntersectionDefinition( intersectionType: ts.IntersectionType, - definition: Definition + definition: Definition, ): Definition { const simpleTypes: JSONSchema7TypeName[] = []; const schemas: Definition[] = []; @@ -1230,7 +1230,7 @@ class JsonSchemaGenerator { private getClassDefinition( clazzType: ts.Type, - definition: Definition + definition: Definition, ): Definition { const node = clazzType.getSymbol()!.getDeclarations()![0]; @@ -1277,7 +1277,7 @@ class JsonSchemaGenerator { const fullName = this.tc.typeToString( clazzType, undefined, - ts.TypeFormatFlags.UseFullyQualifiedType + ts.TypeFormatFlags.UseFullyQualifiedType, ); const modifierFlags = ts.getCombinedModifierFlags(node); @@ -1297,7 +1297,7 @@ class JsonSchemaGenerator { clazz.members == null ? [] : clazz.members.filter( - (x) => x.kind === ts.SyntaxKind.IndexSignature + (x) => x.kind === ts.SyntaxKind.IndexSignature, ); if (indexSignatures.length === 1) { // for case "array-types" @@ -1305,21 +1305,21 @@ class JsonSchemaGenerator { indexSignatures[0] as ts.IndexSignatureDeclaration; if (indexSignature.parameters.length !== 1) { throw new Error( - "Not supported: IndexSignatureDeclaration parameters.length != 1" + "Not supported: IndexSignatureDeclaration parameters.length != 1", ); } const indexSymbol: ts.Symbol = (indexSignature.parameters[0] as any) .symbol; const indexType = this.tc.getTypeOfSymbolAtLocation( indexSymbol, - node + node, ); const isIndexedObject = indexType.flags === ts.TypeFlags.String || indexType.flags === ts.TypeFlags.Number; if (indexType.flags !== ts.TypeFlags.Number && !isIndexedObject) { throw new Error( - "Not supported: IndexSignatureDeclaration with index symbol other than a number or a string" + "Not supported: IndexSignatureDeclaration with index symbol other than a number or a string", ); } @@ -1327,7 +1327,7 @@ class JsonSchemaGenerator { let def: Definition | undefined; if (typ.flags & ts.TypeFlags.IndexedAccess) { const targetName = ts.escapeLeadingUnderscores( - (clazzType as any).mapper?.target?.value + (clazzType as any).mapper?.target?.value, ); const indexedAccessType = typ as ts.IndexedAccessType; const symbols: Map = ( @@ -1339,7 +1339,7 @@ class JsonSchemaGenerator { const targetNode = targetSymbol.getDeclarations()![0]; const targetDef = this.getDefinitionForProperty( targetSymbol, - targetNode + targetNode, ); if (targetDef) { def = targetDef; @@ -1372,7 +1372,7 @@ class JsonSchemaGenerator { } return all; }, - {} + {}, ); if (definition.type === undefined) { @@ -1403,7 +1403,7 @@ class JsonSchemaGenerator { order.push(prop.getName()); return order; }, - [] + [], ); definition.propertyOrder = propertyOrder; @@ -1427,7 +1427,7 @@ class JsonSchemaGenerator { } return required; }, - [] + [], ); if (requiredProps.length > 0) { @@ -1454,9 +1454,9 @@ class JsonSchemaGenerator { typ, undefined, ts.TypeFormatFlags.NoTruncation | - ts.TypeFormatFlags.UseFullyQualifiedType + ts.TypeFormatFlags.UseFullyQualifiedType, ) - .replace(REGEX_FILE_NAME_OR_SPACE, "") + .replace(REGEX_FILE_NAME_OR_SPACE, ""), ); } @@ -1489,7 +1489,7 @@ class JsonSchemaGenerator { reffedType?: ts.Symbol, pairedSymbol?: ts.Symbol, forceNotRef: boolean = false, - ignoreUndefined = false + ignoreUndefined = false, ): Definition { const definition: Definition = {}; // real definition @@ -1574,7 +1574,7 @@ class JsonSchemaGenerator { .getFullyQualifiedName( reffedType!.getFlags() & ts.SymbolFlags.Alias ? this.tc.getAliasedSymbol(reffedType!) - : reffedType! + : reffedType!, ) .replace(REGEX_FILE_NAME_OR_SPACE, ""); if (this.args.uniqueNames && reffedType) { @@ -1582,7 +1582,7 @@ class JsonSchemaGenerator { const relativePath = path.relative(process.cwd(), sourceFile.fileName); fullTypeName = `${typeName}.${generateHashOfNode( getCanonicalDeclaration(reffedType!), - relativePath + relativePath, )}`; } else { fullTypeName = this.makeTypeNameUnique(typ, typeName); @@ -1595,7 +1595,7 @@ class JsonSchemaGenerator { const relativePath = path.relative(process.cwd(), sourceFile.fileName); fullTypeName = `${this.getTypeName(typ)}.${generateHashOfNode( getCanonicalDeclaration(sym), - relativePath + relativePath, )}`; } else if ( reffedType && @@ -1631,20 +1631,20 @@ class JsonSchemaGenerator { this.parseCommentsIntoDefinition( typ.aliasSymbol!, definition, - otherAnnotations + otherAnnotations, ); if (prop) { this.parseCommentsIntoDefinition( prop, returnedDefinition, - otherAnnotations + otherAnnotations, ); } if (pairedSymbol && symbol && this.isFromDefaultLib(symbol)) { this.parseCommentsIntoDefinition( pairedSymbol, definition, - otherAnnotations + otherAnnotations, ); } @@ -1669,7 +1669,7 @@ class JsonSchemaGenerator { true, undefined, symbol, - symbol + symbol, ); } else { reffedDefinition = definition; @@ -1693,7 +1693,7 @@ class JsonSchemaGenerator { this.getUnionDefinition( typ as ts.UnionType, unionModifier, - definition + definition, ); } else if (typ.flags & ts.TypeFlags.Intersection) { if (this.args.noExtraProps) { @@ -1711,7 +1711,7 @@ class JsonSchemaGenerator { undefined, undefined, undefined, - true + true, ); definition.type = other.type; // should always be object definition.properties = { @@ -1722,19 +1722,19 @@ class JsonSchemaGenerator { if (Object.keys(other.default || {}).length > 0) { definition.default = extend( definition.default || {}, - other.default + other.default, ); } if (other.required) { definition.required = unique( - (definition.required || []).concat(other.required) + (definition.required || []).concat(other.required), ).sort(); } } } else { this.getIntersectionDefinition( typ as ts.IntersectionType, - definition + definition, ); } } else if (isRawType) { @@ -1746,7 +1746,7 @@ class JsonSchemaGenerator { reffedType!, definition, undefined, - ignoreUndefined + ignoreUndefined, ); } else if ( node && @@ -1806,7 +1806,7 @@ class JsonSchemaGenerator { public getSchemaForSymbol( symbolName: string, includeReffedDefinitions: boolean = true, - includeAllOverrides: boolean = false + includeAllOverrides: boolean = false, ): Definition { const overrideDefinition = this.schemaOverrides.get(symbolName); if (!this.allSymbols[symbolName] && !overrideDefinition) { @@ -1827,7 +1827,7 @@ class JsonSchemaGenerator { undefined, undefined, undefined, - this.userSymbols[symbolName] || undefined + this.userSymbols[symbolName] || undefined, ); } @@ -1849,7 +1849,7 @@ class JsonSchemaGenerator { public getSchemaForSymbols( symbolNames: string[], includeReffedDefinitions: boolean = true, - includeAllOverrides: boolean = false + includeAllOverrides: boolean = false, ): Definition { const root: { $id?: string; @@ -1875,7 +1875,7 @@ class JsonSchemaGenerator { undefined, undefined, undefined, - this.userSymbols[symbolName] + this.userSymbols[symbolName], ); } if ( @@ -1902,7 +1902,7 @@ class JsonSchemaGenerator { public getMainFileSymbols( program: ts.Program, - onlyIncludeFiles?: string[] + onlyIncludeFiles?: string[], ): string[] { function includeFile(file: ts.SourceFile): boolean { if (onlyIncludeFiles === undefined) { @@ -1940,7 +1940,7 @@ function generateHashOfNode(node: ts.Node, relativePath: string): string { export function buildGenerator( program: ts.Program, - args: PartialArgs = {} + args: PartialArgs = {}, ): JsonSchemaGenerator | null { // Use defaults unless otherwise specified const settings = getDefaultArgs(); @@ -1990,7 +1990,7 @@ export function buildGenerator( var baseName = tc.typeToString( baseType, undefined, - ts.TypeFormatFlags.UseFullyQualifiedType + ts.TypeFormatFlags.UseFullyQualifiedType, ); if (!inheritingTypes[baseName]) { inheritingTypes[baseName] = []; @@ -2011,14 +2011,14 @@ export function buildGenerator( userSymbols, inheritingTypes, typeChecker, - settings + settings, ); } export async function extractGraphSchema( id: string, userPath: string, - exportName: string + exportName: string, ) { const filePath = path.resolve(process.cwd(), userPath); const parentPath = path.dirname(filePath); @@ -2104,7 +2104,7 @@ export async function extractGraphSchema( export type __input = Inspect>; export type __output = Inspect>; export type __config = Inspect>; - ` + `, ); const program = ts.createProgram([typePath], { noEmit: true, @@ -2120,7 +2120,7 @@ export async function extractGraphSchema( } catch (e) { console.error( `Failed to obtain symbol "${symbol}":`, - (e as Error)?.message + (e as Error)?.message, ); } return undefined; diff --git a/libs/langgraph-api/src/logging.mts b/libs/langgraph-api/src/logging.mts index 24e2446..7e3916e 100644 --- a/libs/langgraph-api/src/logging.mts +++ b/libs/langgraph-api/src/logging.mts @@ -50,7 +50,7 @@ export const logger = createLogger({ return JSON.stringify({ timestamp, level, event, ...rest }); }), - ]) + ]), ), transports: [new transports.Console()], }); @@ -61,7 +61,7 @@ const formatStack = (stack: string | undefined | null) => { const [firstFile] = stacktraceParser(stack).filter( (item) => !item.file?.split(path.sep).includes("node_modules") && - !item.file?.startsWith("node:") + !item.file?.startsWith("node:"), ); if (firstFile?.file && firstFile?.lineNumber) { @@ -74,7 +74,7 @@ const formatStack = (stack: string | undefined | null) => { const spliceIndex = messageLines.findIndex((i) => i.includes(filePath)); const padding = " ".repeat( - Math.max(0, messageLines[spliceIndex].indexOf("at")) + Math.max(0, messageLines[spliceIndex].indexOf("at")), ); const highlightCode = process.stdout.isTTY; @@ -82,7 +82,7 @@ const formatStack = (stack: string | undefined | null) => { let codeFrame = codeFrameColumns( readFileSync(filePath, "utf-8"), { start: { line, column } }, - { highlightCode } + { highlightCode }, ); codeFrame = codeFrame @@ -113,7 +113,7 @@ export const logError = ( options?: { context?: Record; prefix?: string; - } + }, ) => { let message; let context = options?.context; diff --git a/libs/langgraph-api/src/schemas.mts b/libs/langgraph-api/src/schemas.mts index 5aaa2cd..c86985e 100644 --- a/libs/langgraph-api/src/schemas.mts +++ b/libs/langgraph-api/src/schemas.mts @@ -171,7 +171,7 @@ export const RunCreate = z z.union([ z.string(), z.object({ node: z.string(), input: z.unknown().optional() }), - ]) + ]), ), ]) .optional(), @@ -210,7 +210,7 @@ export const RunCreate = z "updates", "events", "debug", - ]) + ]), ), z.enum([ "values", diff --git a/libs/langgraph-api/src/server.mts b/libs/langgraph-api/src/server.mts index db2f307..039bbbc 100644 --- a/libs/langgraph-api/src/server.mts +++ b/libs/langgraph-api/src/server.mts @@ -52,7 +52,7 @@ app.post( assistants: z.boolean().optional(), checkpointer: z.boolean().optional(), store: z.boolean().optional(), - }) + }), ), (c) => { const { runs, threads, assistants, checkpointer, store } = @@ -60,7 +60,7 @@ app.post( truncate({ runs, threads, assistants, checkpointer, store }); return c.json({ ok: true }); - } + }, ); export const StartServerSchema = z.object({ @@ -96,8 +96,8 @@ export async function startServer(options: z.infer) { { fetch: app.fetch, port: options.port, hostname: options.host }, (c) => { resolve({ host: `${c.address}:${c.port}`, cleanup }); - } + }, ); - } + }, ); } diff --git a/libs/langgraph-api/src/state.mts b/libs/langgraph-api/src/state.mts index a10d013..6e7f89d 100644 --- a/libs/langgraph-api/src/state.mts +++ b/libs/langgraph-api/src/state.mts @@ -7,13 +7,13 @@ import { runnableConfigToCheckpoint } from "./utils/runnableConfig.mjs"; import { serializeError } from "./utils/serde.mjs"; const isStateSnapshot = ( - state: StateSnapshot | LangGraphRunnableConfig + state: StateSnapshot | LangGraphRunnableConfig, ): state is StateSnapshot => { return "values" in state && "next" in state; }; export const stateSnapshotToThreadState = ( - state: StateSnapshot + state: StateSnapshot, ): ThreadState => { return { values: state.values, diff --git a/libs/langgraph-api/src/storage/checkpoint.mts b/libs/langgraph-api/src/storage/checkpoint.mts index c5cfa63..e4b5123 100644 --- a/libs/langgraph-api/src/storage/checkpoint.mts +++ b/libs/langgraph-api/src/storage/checkpoint.mts @@ -77,18 +77,18 @@ class InMemorySaver extends MemorySaver { async put( config: RunnableConfig, checkpoint: Checkpoint, - metadata: CheckpointMetadata + metadata: CheckpointMetadata, ): Promise { return await conn.with(() => super.put(config, checkpoint, { ...Object.fromEntries( Object.entries(config.configurable ?? {}).filter( - ([key]) => !key.startsWith("__") && !EXCLUDED_KEYS.includes(key) - ) + ([key]) => !key.startsWith("__") && !EXCLUDED_KEYS.includes(key), + ), ), ...config.metadata, ...metadata, - }) + }), ); } diff --git a/libs/langgraph-api/src/storage/ops.mts b/libs/langgraph-api/src/storage/ops.mts index 5a65cc9..eb8e59e 100644 --- a/libs/langgraph-api/src/storage/ops.mts +++ b/libs/langgraph-api/src/storage/ops.mts @@ -135,7 +135,7 @@ export const conn = new FileSystemPersistence( assistants: {}, assistant_versions: [], retry_counter: {}, - }) + }), ); class TimeoutError extends Error {} @@ -255,8 +255,8 @@ export const truncate = (flags: { Object.entries(STORE.assistants).filter( ([key, assistant]) => assistant.metadata?.created_by === "system" && - uuid5(assistant.graph_id, NAMESPACE_GRAPH) === key - ) + uuid5(assistant.graph_id, NAMESPACE_GRAPH) === key, + ), ); } @@ -271,7 +271,7 @@ const isObject = (value: unknown): value is Record => { const isJsonbContained = ( superset: Record | undefined, - subset: Record | undefined + subset: Record | undefined, ): boolean => { if (superset == null || subset == null) return true; for (const [key, value] of Object.entries(subset)) { @@ -321,7 +321,7 @@ export class Assistants { for (const assistant of filtered.slice( options.offset, - options.offset + options.limit + options.offset + options.limit, )) { yield { ...assistant, name: assistant.name ?? assistant.graph_id }; } @@ -345,7 +345,7 @@ export class Assistants { metadata?: Metadata; if_exists: OnConflictBehavior; name?: string; - } + }, ): Promise { return conn.with((STORE) => { if (STORE.assistants[assistantId] != null) { @@ -389,7 +389,7 @@ export class Assistants { graph_id?: string; metadata?: Metadata; name?: string; - } + }, ): Promise { return conn.with((STORE) => { const assistant = STORE.assistants[assistantId]; @@ -428,7 +428,7 @@ export class Assistants { Math.max( ...STORE.assistant_versions .filter((v) => v["assistant_id"] === assistantId) - .map((v) => v["version"]) + .map((v) => v["version"]), ) + 1; assistant.version = newVersion; @@ -458,7 +458,7 @@ export class Assistants { // Cascade delete for assistant versions and crons STORE.assistant_versions = STORE.assistant_versions.filter( - (v) => v["assistant_id"] !== assistantId + (v) => v["assistant_id"] !== assistantId, ); for (const run of Object.values(STORE.runs)) { @@ -473,7 +473,7 @@ export class Assistants { static async setLatest( assistantId: string, - version: number + version: number, ): Promise { return conn.with((STORE) => { const assistant = STORE.assistants[assistantId]; @@ -481,7 +481,7 @@ export class Assistants { throw new HTTPException(404, { message: "Assistant not found" }); const assistantVersion = STORE.assistant_versions.find( - (v) => v["assistant_id"] === assistantId && v["version"] === version + (v) => v["assistant_id"] === assistantId && v["version"] === version, ); if (!assistantVersion) @@ -509,7 +509,7 @@ export class Assistants { limit: number; offset: number; metadata?: Metadata; - } + }, ) { return conn.with((STORE) => { const versions = STORE.assistant_versions @@ -620,7 +620,7 @@ export class Threads { for (const thread of filtered.slice( options.offset, - options.offset + options.limit + options.offset + options.limit, )) { yield thread; } @@ -644,7 +644,7 @@ export class Threads { options?: { metadata?: Metadata; if_exists: OnConflictBehavior; - } + }, ): Promise { return conn.with((STORE) => { const now = new Date(); @@ -674,7 +674,7 @@ export class Threads { threadId: string, options?: { metadata?: Metadata; - } + }, ): Promise { return conn.with((STORE) => { const thread = STORE.threads[threadId]; @@ -699,7 +699,7 @@ export class Threads { options: { checkpoint?: CheckpointPayload; exception?: Error; - } + }, ) { return conn.with((STORE) => { const thread = STORE.threads[threadId]; @@ -712,7 +712,7 @@ export class Threads { } const hasPendingRuns = Object.values(STORE.runs).some( - (run) => run["thread_id"] === threadId && run["status"] === "pending" + (run) => run["thread_id"] === threadId && run["status"] === "pending", ); let status: ThreadStatus = "idle"; @@ -737,7 +737,7 @@ export class Threads { if (task.interrupts) acc[task.id] = task.interrupts; return acc; }, - {} + {}, ) : undefined; }); @@ -790,7 +790,7 @@ export class Threads { config: RunnableConfig, options: { subgraphs?: boolean; - } + }, ): Promise { const subgraphs = options.subgraphs ?? false; const threadId = config.configurable?.thread_id; @@ -831,7 +831,7 @@ export class Threads { | Record | null | undefined, - asNode?: string | undefined + asNode?: string | undefined, ) { const threadId = config.configurable?.thread_id; const thread = threadId ? await Threads.get(threadId) : undefined; @@ -880,7 +880,7 @@ export class Threads { limit?: number; before?: string | RunnableConfig; metadata?: Metadata; - } + }, ) { const threadId = config.configurable?.thread_id; if (!threadId) return []; @@ -932,7 +932,7 @@ export class Runs { if (!thread) { await console.warn( - `Unexpected missing thread in Runs.next: ${threadId}` + `Unexpected missing thread in Runs.next: ${threadId}`, ); continue; } @@ -965,7 +965,7 @@ export class Runs { multitaskStrategy?: MultitaskStrategy; ifNotExists?: IfNotExists; afterSeconds?: number; - } + }, ): Promise { return conn.with(async (STORE) => { const assistant = STORE.assistants[assistantId]; @@ -985,7 +985,7 @@ export class Runs { const config: RunnableConfig = kwargs.config ?? {}; const existingThread = Object.values(STORE.threads).find( - (thread) => thread.thread_id === threadId + (thread) => thread.thread_id === threadId, ); const now = new Date(); @@ -1000,7 +1000,7 @@ export class Runs { configurable: Object.assign( {}, assistant.config?.configurable, - config?.configurable + config?.configurable, ), }), created_at: now, @@ -1025,9 +1025,9 @@ export class Runs { {}, assistant.config?.configurable, existingThread?.config?.configurable, - config?.configurable + config?.configurable, ), - } + }, ); existingThread.updated_at = now; @@ -1039,7 +1039,7 @@ export class Runs { // if multitask_mode = reject, check for inflight runs // and if there are any, return them to reject putting a new run const inflightRuns = Object.values(STORE.runs).filter( - (run) => run.thread_id === threadId && run.status === "pending" + (run) => run.thread_id === threadId && run.status === "pending", ); if (options?.preventInsertInInflight) { @@ -1062,14 +1062,14 @@ export class Runs { existingThread?.config?.configurable?.user_id ?? assistant.config?.configurable?.user_id ?? options?.userId, - } + }, ); const mergedMetadata = Object.assign( {}, assistant.metadata, existingThread?.metadata, - metadata + metadata, ); const newRun: Run = { @@ -1084,7 +1084,7 @@ export class Runs { assistant.config, config, { configurable }, - { metadata: mergedMetadata } + { metadata: mergedMetadata }, ), }), multitask_strategy: multitaskStrategy, @@ -1099,7 +1099,7 @@ export class Runs { static async get( runId: string, - threadId: string | undefined + threadId: string | undefined, ): Promise { return conn.with(async (STORE) => { const run = STORE.runs[runId]; @@ -1115,7 +1115,7 @@ export class Runs { static async delete( runId: string, - threadId: string | undefined + threadId: string | undefined, ): Promise { return conn.with(async (STORE) => { const run = STORE.runs[runId]; @@ -1167,7 +1167,7 @@ export class Runs { runIds: string[], options: { action?: "interrupt" | "rollback"; - } + }, ) { return conn.with(async (STORE) => { const action = options.action ?? "interrupt"; @@ -1194,7 +1194,7 @@ export class Runs { { run_id: runId, thread_id: threadId, - } + }, ); promises.push(Runs.delete(runId, threadId)); @@ -1228,7 +1228,7 @@ export class Runs { offset?: number | null; status?: string | null; metadata?: Metadata | null; - } + }, ) { return conn.with(async (STORE) => { const runs = Object.values(STORE.runs).filter((run) => { @@ -1263,7 +1263,7 @@ export class Runs { options?: { ignore404?: boolean; cancelOnDisconnect?: AbortSignal; - } + }, ): AsyncGenerator<{ event: string; data: unknown }> { // TODO: what if we're joining an already completed run? Should we check before? const signal = options?.cancelOnDisconnect; @@ -1276,7 +1276,7 @@ export class Runs { if (message.data === "done") break; } else { const streamTopic = message.topic.substring( - `run:${runId}:stream:`.length + `run:${runId}:stream:`.length, ); yield { event: streamTopic, data: message.data }; diff --git a/libs/langgraph-api/src/storage/persist.mts b/libs/langgraph-api/src/storage/persist.mts index 36a8aea..c3931ed 100644 --- a/libs/langgraph-api/src/storage/persist.mts +++ b/libs/langgraph-api/src/storage/persist.mts @@ -11,7 +11,7 @@ superjson.registerCustom( serialize: (v) => Buffer.from(v).toString("base64"), deserialize: (v) => new Uint8Array(Buffer.from(v, "base64")), }, - "Uint8Array" + "Uint8Array", ); export function serialize(data: unknown) { @@ -81,7 +81,7 @@ export class FileSystemPersistence { } async *withGenerator>( - fn: ((data: Schema) => T) | T + fn: ((data: Schema) => T) | T, ) { if (this.filepath == null || this.data == null) { throw new Error(`${this.name} not initialized`); diff --git a/libs/langgraph-api/src/storage/store.mts b/libs/langgraph-api/src/storage/store.mts index c48d5e8..b87f1c9 100644 --- a/libs/langgraph-api/src/storage/store.mts +++ b/libs/langgraph-api/src/storage/store.mts @@ -30,7 +30,7 @@ class InMemoryStore extends BaseMemoryStore { } async batch( - operations: Op + operations: Op, ): Promise> { return await conn.with(() => super.batch(operations)); } diff --git a/libs/langgraph-api/src/stream.mts b/libs/langgraph-api/src/stream.mts index eb4e95b..1e8b446 100644 --- a/libs/langgraph-api/src/stream.mts +++ b/libs/langgraph-api/src/stream.mts @@ -112,7 +112,7 @@ function preprocessDebugCheckpointTask(task: DebugTask): StreamTaskResult { } const isConfigurablePresent = ( - config: unknown + config: unknown, ): config is { [key: string]: unknown; callbacks?: unknown; @@ -130,8 +130,8 @@ const deleteInternalConfigurableFields = (config: unknown) => { ...config, configurable: Object.fromEntries( Object.entries(config.configurable).filter( - ([key]) => !key.startsWith("__") - ) + ([key]) => !key.startsWith("__"), + ), ), }; @@ -168,7 +168,7 @@ export async function* streamState( onCheckpoint?: (checkpoint: StreamCheckpoint) => void; onTaskResult?: (taskResult: StreamTaskResult) => void; signal?: AbortSignal; - } + }, ): AsyncGenerator<{ event: string; data: unknown }> { const kwargs = run.kwargs; const graphId = kwargs.config?.configurable?.graph_id; @@ -185,8 +185,8 @@ export async function* streamState( const libStreamMode: Set = new Set( userStreamMode.filter( - (mode) => mode !== "events" && mode !== "messages-tuple" - ) ?? [] + (mode) => mode !== "events" && mode !== "messages-tuple", + ) ?? [], ); if (userStreamMode.includes("messages-tuple")) { @@ -232,7 +232,7 @@ export async function* streamState( runId: run.run_id, streamMode: [...libStreamMode], signal: options?.signal, - } + }, ); const messages: Record = {}; @@ -344,11 +344,11 @@ export async function* streamState( kwargs.feedback_keys.map(async (feedback) => { const { url } = await client.createPresignedFeedbackToken( run.run_id, - feedback + feedback, ); return [feedback, url]; - }) - ) + }), + ), ); yield { event: "feedback", data }; diff --git a/libs/langgraph-api/src/utils/abort.mts b/libs/langgraph-api/src/utils/abort.mts index c38c861..cf3a5dd 100644 --- a/libs/langgraph-api/src/utils/abort.mts +++ b/libs/langgraph-api/src/utils/abort.mts @@ -7,7 +7,7 @@ export const combineAbortSignals = ( const abortController = new AbortController(); signals.forEach((signal) => - signal.addEventListener("abort", () => abortController.abort()) + signal.addEventListener("abort", () => abortController.abort()), ); return abortController.signal; }; diff --git a/libs/langgraph-api/src/utils/runnableConfig.mts b/libs/langgraph-api/src/utils/runnableConfig.mts index ebe58a2..14d59ce 100644 --- a/libs/langgraph-api/src/utils/runnableConfig.mts +++ b/libs/langgraph-api/src/utils/runnableConfig.mts @@ -11,7 +11,7 @@ const ConfigSchema = z.object({ }); export const runnableConfigToCheckpoint = ( - config: RunnableConfig | null | undefined + config: RunnableConfig | null | undefined, ): Checkpoint | null => { if (!config || !config.configurable || !config.configurable.thread_id) { return null; @@ -38,7 +38,7 @@ const TaskConfigSchema = z.object({ }); export const taskRunnableConfigToCheckpoint = ( - config: RunnableConfig | null | undefined + config: RunnableConfig | null | undefined, ): Partial | null => { if (!config || !config.configurable || !config.configurable.thread_id) { return null; diff --git a/libs/langgraph-api/src/utils/serde.mts b/libs/langgraph-api/src/utils/serde.mts index a09e725..2df4b4f 100644 --- a/libs/langgraph-api/src/utils/serde.mts +++ b/libs/langgraph-api/src/utils/serde.mts @@ -16,7 +16,7 @@ export const serialiseAsDict = (obj: unknown) => { return value; }, - 2 + 2, ); }; @@ -26,5 +26,3 @@ export const serializeError = (error: unknown) => { } return { error: "Error", message: JSON.stringify(error) }; }; - - diff --git a/libs/langgraph-api/tests/api.test.mts b/libs/langgraph-api/tests/api.test.mts index ca6ac51..e8c6179 100644 --- a/libs/langgraph-api/tests/api.test.mts +++ b/libs/langgraph-api/tests/api.test.mts @@ -41,7 +41,7 @@ const truncate = async ( store?: boolean; checkpoint?: boolean; } - | "all" + | "all", ) => { const flags = options === "all" @@ -81,7 +81,7 @@ describe("assistants", () => { await client.assistants.delete(res.assistant_id); await expect(() => client.assistants.get(res.assistant_id)).rejects.toThrow( - "HTTP 404: Assistant not found" + "HTTP 404: Assistant not found", ); }); @@ -159,7 +159,7 @@ describe("assistants", () => { await client.assistants.delete(res.assistant_id); await expect(() => client.assistants.get(res.assistant_id)).rejects.toThrow( - "HTTP 404: Assistant not found" + "HTTP 404: Assistant not found", ); }); @@ -184,7 +184,7 @@ describe("assistants", () => { }); expect(search.length).toBeGreaterThanOrEqual(1); expect(search.every((i) => i.assistant_id !== create.assistant_id)).toBe( - true + true, ); }); @@ -193,7 +193,7 @@ describe("assistants", () => { // (1) initial version expect( - await client.assistants.getVersions(assistant.assistant_id) + await client.assistants.getVersions(assistant.assistant_id), ).toMatchObject([{ version: 1 }]); // (2) update and create a new version @@ -201,7 +201,7 @@ describe("assistants", () => { config: { configurable: { foo: "bar" } }, }); expect( - await client.assistants.getVersions(assistant.assistant_id) + await client.assistants.getVersions(assistant.assistant_id), ).toMatchObject([ { version: 2, config: { configurable: { foo: "bar" } } }, { version: 1 }, @@ -211,14 +211,14 @@ describe("assistants", () => { expect( await client.assistants.getVersions(assistant.assistant_id, { limit: 1, - }) + }), ).toMatchObject([{ version: 2 }]); // descending order expect( await client.assistants.getVersions(assistant.assistant_id, { offset: 1, - }) + }), ).toMatchObject([{ version: 1 }]); // (3) create a version with metadata @@ -229,14 +229,14 @@ describe("assistants", () => { expect( await client.assistants.getVersions(assistant.assistant_id, { metadata: { foo: "baz" }, - }) + }), ).toMatchObject([{ version: 3 }]); // (4) noop update await client.assistants.update(assistant.assistant_id, {}); expect( - await client.assistants.getVersions(assistant.assistant_id) + await client.assistants.getVersions(assistant.assistant_id), ).toMatchObject([ { version: 4 }, { version: 3 }, @@ -246,7 +246,7 @@ describe("assistants", () => { await client.assistants.delete(assistant.assistant_id); expect( - await client.assistants.getVersions(assistant.assistant_id) + await client.assistants.getVersions(assistant.assistant_id), ).toMatchObject([]); }); @@ -260,12 +260,12 @@ describe("assistants", () => { const updatedAgain = await client.assistants.update( created.assistant_id, - {} + {}, ); expect(updatedAgain.version).toBe(3); await expect( - client.assistants.setLatest(created.assistant_id, 4) + client.assistants.setLatest(created.assistant_id, 4), ).rejects.toThrow(); }); @@ -388,7 +388,7 @@ describe("threads copy", () => { const copiedThread = await client.threads.copy(thread.thread_id); const copiedThreadState = await client.threads.getState( - copiedThread.thread_id + copiedThread.thread_id, ); // check copied thread state matches expected output @@ -414,7 +414,7 @@ describe("threads copy", () => { // For in-memory connections, check the thread history const originalHistory = await client.threads.getHistory(thread.thread_id); const copiedHistory = await client.threads.getHistory( - copiedThread.thread_id + copiedThread.thread_id, ); expect(originalHistory.length).toBe(copiedHistory.length); @@ -443,7 +443,7 @@ describe("threads copy", () => { } else { const sql = postgres( process.env.POSTGRES_URI ?? - "postgres://postgres:postgres@127.0.0.1:5433/postgres?sslmode=disable" + "postgres://postgres:postgres@127.0.0.1:5433/postgres?sslmode=disable", ); // check checkpoints in DB @@ -504,11 +504,11 @@ describe("threads copy", () => { // test that copied thread has original as well as new values const copiedThreadState = await client.threads.getState( - copiedThread.thread_id + copiedThread.thread_id, ); const copiedThreadStateMessages = copiedThreadState.values.messages.map( - (m) => m.content + (m) => m.content, ); expect(copiedThreadStateMessages).toEqual([ // original messages @@ -525,7 +525,7 @@ describe("threads copy", () => { // test that the new run on the copied thread doesn't affect the original one const currentOriginalThreadState = await client.threads.getState( - thread.thread_id + thread.thread_id, ); expect(currentOriginalThreadState).toEqual(originalThreadState); }); @@ -544,7 +544,7 @@ describe("threads copy", () => { }); const history = await client.threads.getHistory( - thread.thread_id + thread.thread_id, ); expect(history.length).toBe(5); expect(history[0].values.messages.length).toBe(4); @@ -560,11 +560,11 @@ describe("threads copy", () => { }); const fullHistory = await client.threads.getHistory( - thread.thread_id + thread.thread_id, ); const filteredHistory = await client.threads.getHistory( thread.thread_id, - { metadata: runMetadata } + { metadata: runMetadata }, ); expect(fullHistory.length).toBe(10); @@ -595,13 +595,13 @@ describe("threads copy", () => { }); const copiedThreadState = await client.threads.getState( - copyThread.thread_id + copyThread.thread_id, ); expect(copiedThreadState.values.messages[0].content).toBe("bar"); // test that updating the copied thread doesn't affect the original one const currentOriginalThreadState = await client.threads.getState( - thread.thread_id + thread.thread_id, ); expect(currentOriginalThreadState).toEqual(originalState); }); @@ -625,7 +625,7 @@ describe("runs", () => { input: { messages: [{ type: "human", content: "bar" }] }, config: globalConfig, afterSeconds: 10, - } + }, ); let runs = await client.runs.list(thread.thread_id); @@ -649,7 +649,7 @@ describe("runs", () => { const stream = client.runs.stream( thread.thread_id, assistant.assistant_id, - { input, streamMode: "values", config: globalConfig } + { input, streamMode: "values", config: globalConfig }, ); let runId: string | null = null; @@ -666,7 +666,7 @@ describe("runs", () => { if (chunk.event === "values") { const messageIds = chunk.data.messages.map( - (message: { id: string }) => message.id + (message: { id: string }) => message.id, ); expect(messageIds.slice(0, -1)).toEqual(previousMessageIds); previousMessageIds = messageIds; @@ -686,7 +686,7 @@ describe("runs", () => { } else { const sql = postgres( process.env.POSTGRES_URI ?? - "postgres://postgres:postgres@127.0.0.1:5433/postgres?sslmode=disable" + "postgres://postgres:postgres@127.0.0.1:5433/postgres?sslmode=disable", ); let cur = await sql`SELECT * FROM checkpoints WHERE run_id is null`; @@ -709,7 +709,7 @@ describe("runs", () => { client.runs.wait(thread.thread_id, assistant.assistant_id, { input, config: { ...globalConfig, recursion_limit: 1 }, - }) + }), ).rejects.toThrowError(/GraphRecursionError/); const threadUpdated = await client.threads.get(thread.thread_id); expect(threadUpdated.status).toBe("error"); @@ -724,7 +724,7 @@ describe("runs", () => { const values = await client.runs.wait( thread.thread_id, assistant.assistant_id, - { input, config: globalConfig } + { input, config: globalConfig }, ); expect(Array.isArray((values as any).messages)).toBe(true); @@ -741,7 +741,7 @@ describe("runs", () => { const stream = client.runs.stream( thread.thread_id, assistant.assistant_id, - { input, streamMode: "updates", config: globalConfig } + { input, streamMode: "updates", config: globalConfig }, ); let runId: string | null = null; @@ -781,18 +781,18 @@ describe("runs", () => { const stream = client.runs.stream( thread.thread_id, assistant.assistant_id, - { input, streamMode: "events", config: globalConfig } + { input, streamMode: "events", config: globalConfig }, ); const events = await gatherIterator(stream); expect(new Set(events.map((i) => i.event))).toEqual( - new Set(["metadata", "events"]) + new Set(["metadata", "events"]), ); expect( new Set( - events.filter((i) => i.event === "events").map((i) => i.data.event) - ) + events.filter((i) => i.event === "events").map((i) => i.data.event), + ), ).toEqual( new Set([ "on_chain_start", @@ -800,7 +800,7 @@ describe("runs", () => { "on_chat_model_end", "on_chat_model_start", "on_chat_model_stream", - ]) + ]), ); }); @@ -813,7 +813,7 @@ describe("runs", () => { const stream = client.runs.stream( thread.thread_id, assistant.assistant_id, - { input, streamMode: "messages", config: globalConfig } + { input, streamMode: "messages", config: globalConfig }, ); let runId: string | null = null; @@ -854,7 +854,7 @@ describe("runs", () => { "messages/metadata", "messages/partial", "messages/complete", - ]) + ]), ); expect(runId).not.toBeNull(); @@ -871,7 +871,7 @@ describe("runs", () => { const stream = await client.runs.stream( thread.thread_id, assistant.assistant_id, - { input, streamMode: "messages-tuple", config: globalConfig } + { input, streamMode: "messages-tuple", config: globalConfig }, ); const chunks = await gatherIterator(stream); @@ -905,7 +905,7 @@ describe("runs", () => { const stream = await client.runs.stream( thread.thread_id, assistant.assistant_id, - { input, streamMode: ["messages", "values"], config: globalConfig } + { input, streamMode: ["messages", "values"], config: globalConfig }, ); const chunks = await gatherIterator(stream); @@ -914,7 +914,7 @@ describe("runs", () => { const messages: BaseMessage[] = findLast( chunks, - (i) => i.event === "values" + (i) => i.event === "values", )?.data.messages; expect(messages.length).toBe(4); @@ -931,7 +931,7 @@ describe("runs", () => { "messages/partial", "messages/complete", "values", - ]) + ]), ); const run = await client.runs.get(thread.thread_id, runId); @@ -956,7 +956,7 @@ describe("runs", () => { input, interruptBefore: ["tool"], config: globalConfig, - }) + }), ); expect(chunks.filter((i) => i.event === "error").length).toBe(0); @@ -976,7 +976,7 @@ describe("runs", () => { client.runs.stream(thread.thread_id, assistant.assistant_id, { input: null, config: globalConfig, - }) + }), ); expect(chunks.filter((i) => i.event === "error").length).toBe(0); @@ -988,7 +988,7 @@ describe("runs", () => { const threadAfterContinue = await client.threads.get(thread.thread_id); expect(threadAfterContinue.status).toBe("idle"); - } + }, ); it.concurrent("human in the loop - modification", async () => { @@ -1006,7 +1006,7 @@ describe("runs", () => { input, interruptBefore: ["tool"], config: globalConfig, - }) + }), ); expect(chunks.filter((i) => i.event === "error").length).toBe(0); @@ -1014,7 +1014,7 @@ describe("runs", () => { // edit the last message const lastMessage = findLast( chunks, - (i) => i.event === "values" + (i) => i.event === "values", )?.data.messages.at(-1); lastMessage.content = "modified"; @@ -1031,7 +1031,7 @@ describe("runs", () => { expect(modifiedThread.metadata?.modified).toBe(true); const stateAfterModify = await client.threads.getState( - thread.thread_id + thread.thread_id, ); expect(stateAfterModify.values.messages.at(-1)?.content).toBe("modified"); expect(stateAfterModify.next).toEqual(["tool"]); @@ -1044,7 +1044,7 @@ describe("runs", () => { client.runs.stream(thread.thread_id, assistant.assistant_id, { input: null, config: globalConfig, - }) + }), ); const threadAfterContinue = await client.threads.get(thread.thread_id); @@ -1059,7 +1059,7 @@ describe("runs", () => { // get the history const history = await client.threads.getHistory( - thread.thread_id + thread.thread_id, ); expect(history.length).toBe(6); expect(history[0].next.length).toBe(0); @@ -1091,13 +1091,13 @@ describe("runs", () => { }; await expect( - client.runs.wait(thread.thread_id, "non-existent", { input }) + client.runs.wait(thread.thread_id, "non-existent", { input }), ).rejects.toThrow(/No assistant found for/); await expect( gatherIterator( - client.runs.stream(thread.thread_id, "non-existent", { input }) - ) + client.runs.stream(thread.thread_id, "non-existent", { input }), + ), ).rejects.toThrow(/No assistant found for/); }); }); @@ -1120,7 +1120,7 @@ describe("shared state", () => { const res1 = (await client.runs.wait( thread.thread_id, assistant.assistant_id, - { input, config } + { input, config }, )) as Awaited>; expect(res1.sharedStateValue).toBe(null); @@ -1128,7 +1128,7 @@ describe("shared state", () => { const res2 = (await client.runs.wait( thread.thread_id, assistant.assistant_id, - { input, config } + { input, config }, )) as Awaited>; expect(res2.sharedStateValue).toBe(config.configurable.user_id); }); @@ -1146,7 +1146,7 @@ describe("shared state", () => { const res1 = (await client.runs.wait( thread.thread_id, assistant.assistant_id, - { input, config: config1 } + { input, config: config1 }, )) as Awaited>; // Run with the same thread id but a new config @@ -1154,7 +1154,7 @@ describe("shared state", () => { const res2 = (await client.runs.wait( thread.thread_id, assistant.assistant_id, - { input, config: config2 } + { input, config: config2 }, )) as Awaited>; expect(res1.sharedStateValue).toBe(config1.configurable.user_id); @@ -1180,12 +1180,12 @@ describe("shared state", () => { const res1 = (await client.runs.wait( thread.thread_id, assistant.assistant_id, - { input, config } + { input, config }, )) as Awaited>; expect(res1.sharedStateFromStoreConfig).toBeDefined(); expect(res1.sharedStateFromStoreConfig.id).toBeDefined(); expect(res1.sharedStateFromStoreConfig.id).toBe( - config.configurable.user_id + config.configurable.user_id, ); }); @@ -1210,12 +1210,12 @@ describe("shared state", () => { const res1 = (await client.runs.wait( thread.thread_id, assistant.assistant_id, - { input, config } + { input, config }, )) as Awaited>; expect(res1.sharedStateFromStoreConfig).toBeDefined(); expect(res1.sharedStateFromStoreConfig.id).toBeDefined(); expect(res1.sharedStateFromStoreConfig.id).toBe( - config.configurable.user_id + config.configurable.user_id, ); // Fetch data from store client @@ -1305,10 +1305,10 @@ describe("StoreClient", () => { expect(searchResAfterPut.items[0].createdAt).toBeDefined(); expect(searchResAfterPut.items[0].updatedAt).toBeDefined(); expect( - new Date(searchResAfterPut.items[0].createdAt).getTime() + new Date(searchResAfterPut.items[0].createdAt).getTime(), ).toBeLessThanOrEqual(Date.now()); expect( - new Date(searchResAfterPut.items[0].updatedAt).getTime() + new Date(searchResAfterPut.items[0].updatedAt).getTime(), ).toBeLessThanOrEqual(Date.now()); const updatedValue = { foo: "baz" }; @@ -1325,7 +1325,7 @@ describe("StoreClient", () => { expect(searchResAfterUpdate.items[0].value).toEqual(updatedValue); expect( - new Date(searchResAfterUpdate.items[0].updatedAt).getTime() + new Date(searchResAfterUpdate.items[0].updatedAt).getTime(), ).toBeGreaterThan(new Date(searchResAfterPut.items[0].updatedAt).getTime()); const listResAfterPut = await client.store.listNamespaces(); @@ -1349,12 +1349,12 @@ describe("subgraphs", () => { const assistant = await client.assistants.create({ graphId: "nested" }); expect( - Object.keys(await client.assistants.getSubgraphs(assistant.assistant_id)) + Object.keys(await client.assistants.getSubgraphs(assistant.assistant_id)), ).toEqual(["gp_two"]); const subgraphs = await client.assistants.getSubgraphs( assistant.assistant_id, - { recurse: true } + { recurse: true }, ); expect(Object.keys(subgraphs)).toEqual(["gp_two", "gp_two|p_two"]); @@ -1399,7 +1399,7 @@ describe("subgraphs", () => { messages: [{ role: "human", content: "SF", id: "initial-message" }], }, interruptBefore: ["tool"], - }) + }), ); for (const chunk of chunks) { @@ -1468,7 +1468,7 @@ describe("subgraphs", () => { const stateRecursive = await client.threads.getState( thread.thread_id, undefined, - { subgraphs: true } + { subgraphs: true }, ); expect(stateRecursive.next).toEqual(["weather_graph"]); @@ -1527,7 +1527,7 @@ describe("subgraphs", () => { input: null, streamMode: ["values", "updates"], streamSubgraphs: true, - }) + }), ); expect(chunks.filter((i) => i.event === "error")).toEqual([]); @@ -1681,7 +1681,7 @@ describe("subgraphs", () => { // run until the interrupt (same as before) let chunks = await gatherIterator( - client.runs.stream(thread.thread_id, assistant.assistant_id, { input }) + client.runs.stream(thread.thread_id, assistant.assistant_id, { input }), ); expect(chunks.filter((i) => i.event === "error")).toEqual([]); @@ -1713,7 +1713,7 @@ describe("subgraphs", () => { // get inner state after update const innerState = await client.threads.getState<{ city: string }>( thread.thread_id, - state.tasks[0].checkpoint ?? undefined + state.tasks[0].checkpoint ?? undefined, ); expect(innerState.values.city).toBe("LA"); @@ -1735,7 +1735,7 @@ describe("subgraphs", () => { chunks = await gatherIterator( client.runs.stream(thread.thread_id, assistant.assistant_id, { input: null, - }) + }), ); expect(chunks.filter((i) => i.event === "error")).toEqual([]); @@ -1820,7 +1820,7 @@ describe("subgraphs", () => { const stream = await gatherIterator( client.runs.stream(thread.thread_id, assistant.assistant_id, { command: { resume: "i want to resume" }, - }) + }), ); expect(stream.at(-1)?.event).toBe("values"); @@ -1837,7 +1837,7 @@ describe("errors", () => { client.runs.stream(thread.thread_id, assistant.assistant_id, { input: { messages: [] }, streamMode: ["debug", "events"], - }) + }), ); expect(stream.at(-1)).toMatchObject({ @@ -1856,7 +1856,7 @@ describe("errors", () => { const run = await client.runs.create( thread.thread_id, assistant.assistant_id, - { input: { messages: [] } } + { input: { messages: [] } }, ); await client.runs.join(thread.thread_id, run.run_id); @@ -1871,11 +1871,11 @@ describe("errors", () => { const run = await client.runs.create( thread.thread_id, assistant.assistant_id, - { input: { messages: [] } } + { input: { messages: [] } }, ); const stream = await gatherIterator( - client.runs.joinStream(thread.thread_id, run.run_id) + client.runs.joinStream(thread.thread_id, run.run_id), ); expect(stream.at(-1)).toMatchObject({ @@ -1905,7 +1905,7 @@ describe("long running tasks", () => { { input: { messages: [], delay }, config: globalConfig, - } + }, ); await client.runs.join(thread.thread_id, run.run_id); @@ -1921,7 +1921,7 @@ describe("long running tasks", () => { expect(runResult.values.messages).toMatchObject([ { content: `finished after ${delay}ms` }, ]); - } + }, ); }); @@ -1947,7 +1947,7 @@ describe("command update state", () => { client.runs.stream(thread.thread_id, assistant.assistant_id, { command: { update: { keyOne: "value3", keyTwo: "value4" } }, config: globalConfig, - }) + }), ); expect(stream.filter((chunk) => chunk.event === "error")).toEqual([]); @@ -1982,7 +1982,7 @@ describe("command update state", () => { ], }, config: globalConfig, - }) + }), ); expect(stream.filter((chunk) => chunk.event === "error")).toEqual([]); @@ -2005,7 +2005,7 @@ it("stream debug checkpoint", async () => { { input, streamMode: "debug", - } + }, ); const stream = []; @@ -2024,13 +2024,13 @@ it("stream debug checkpoint", async () => { step: i.metadata?.step, checkpoint: i.checkpoint, parent_checkpoint: i.parent_checkpoint, - })) + })), ).toEqual( history.map((i) => ({ step: i.metadata?.step, checkpoint: i.checkpoint, parent_checkpoint: i.parent_checkpoint, - })) + })), ); }); @@ -2047,7 +2047,7 @@ it("continue after interrupt must have checkpoint present", async () => { input, streamMode: "debug", interruptBefore: ["router_node"], - }) + }), ); const initialStream = stream @@ -2062,7 +2062,7 @@ it("continue after interrupt must have checkpoint present", async () => { client.runs.stream(thread.thread_id, assistant.assistant_id, { streamMode: "debug", checkpoint, - }) + }), ); const continueHistory = ( @@ -2078,13 +2078,13 @@ it("continue after interrupt must have checkpoint present", async () => { step: i.metadata?.step, checkpoint: i.checkpoint, parent_checkpoint: i.parent_checkpoint, - })) + })), ).toEqual( continueHistory.map((i) => ({ step: i.metadata?.step, checkpoint: i.checkpoint, parent_checkpoint: i.parent_checkpoint, - })) + })), ); }); @@ -2093,7 +2093,7 @@ describe("multitasking", () => { const pollRun = async ( threadId: string, runId: string, - maxIter: number = 600 + maxIter: number = 600, ) => { let lastStatus: | Awaited>["status"] @@ -2128,7 +2128,7 @@ describe("multitasking", () => { const run = await client.runs.create( thread.thread_id, assistant.assistant_id, - { input, config: globalConfig } + { input, config: globalConfig }, ); // Attempt another run that should be rejected @@ -2137,7 +2137,7 @@ describe("multitasking", () => { input, multitaskStrategy: "reject", config: globalConfig, - }) + }), ).rejects.toThrow(); const runStatus = await pollRun(thread.thread_id, run.run_id); @@ -2156,7 +2156,7 @@ describe("multitasking", () => { const run1 = await client.runs.create( thread.thread_id, assistant.assistant_id, - { input: input1, config: globalConfig } + { input: input1, config: globalConfig }, ); // Start second run that should interrupt first @@ -2171,7 +2171,7 @@ describe("multitasking", () => { input: input2, multitaskStrategy: "interrupt", config: globalConfig, - } + }, ); const run1Status = await pollRun(thread.thread_id, run1.run_id); @@ -2204,7 +2204,7 @@ describe("multitasking", () => { const run1 = await client.runs.create( thread.thread_id, assistant.assistant_id, - { input: input1, config: globalConfig } + { input: input1, config: globalConfig }, ); // Start second run that should rollback first @@ -2214,12 +2214,12 @@ describe("multitasking", () => { const run2 = await client.runs.create( thread.thread_id, assistant.assistant_id, - { input: input2, multitaskStrategy: "rollback", config: globalConfig } + { input: input2, multitaskStrategy: "rollback", config: globalConfig }, ); // First run should be deleted await expect(() => - pollRun(thread.thread_id, run1.run_id) + pollRun(thread.thread_id, run1.run_id), ).rejects.toThrow(); const run2Status = await pollRun(thread.thread_id, run2.run_id); @@ -2242,7 +2242,7 @@ describe("multitasking", () => { const run1 = await client.runs.create( thread.thread_id, assistant.assistant_id, - { input: input1, config: globalConfig } + { input: input1, config: globalConfig }, ); // Start second run that should be enqueued @@ -2257,7 +2257,7 @@ describe("multitasking", () => { input: input2, multitaskStrategy: "enqueue", config: globalConfig, - } + }, ); const run1Status = await pollRun(thread.thread_id, run1.run_id); @@ -2283,7 +2283,7 @@ describe("RemoteGraph", () => { }); const stream = await graph.stream( { messages: [{ type: "human", content: "foo", id: "initial-message" }] }, - { streamMode: "values", ...globalConfig } + { streamMode: "values", ...globalConfig }, ); const chunks = await gatherIterator(stream); diff --git a/libs/langgraph-api/tests/graphs/agent.mts b/libs/langgraph-api/tests/graphs/agent.mts index f28fd1f..b352e4b 100644 --- a/libs/langgraph-api/tests/graphs/agent.mts +++ b/libs/langgraph-api/tests/graphs/agent.mts @@ -37,7 +37,7 @@ class StableFakeListChatModel extends FakeListChatModel { async *_streamResponseChunks( _messages: BaseMessage[], options: this["ParsedCallOptions"], - runManager?: CallbackManagerForLLMRun + runManager?: CallbackManagerForLLMRun, ): AsyncGenerator { const response = this._currentResponse(); this._incrementResponse(); @@ -68,7 +68,7 @@ class StableFakeListChatModel extends FakeListChatModel { undefined, undefined, undefined, - { chunk } + { chunk }, ); } } @@ -88,7 +88,7 @@ const getModel = (threadId: string) => { const agentNode = async ( state: typeof GraphAnnotationInput.State, - config: LangGraphRunnableConfig + config: LangGraphRunnableConfig, ) => { if (state.interrupt) interrupt("i want to interrupt"); @@ -120,7 +120,7 @@ const agentNode = async ( const toolNode = async ( state: typeof GraphAnnotationInput.State, - config: LangGraphRunnableConfig + config: LangGraphRunnableConfig, ) => { const store = config.store; let sharedStateFromStoreConfig: Record | null = null; @@ -144,7 +144,7 @@ const toolNode = async ( const checkSharedStateNode = async ( _: typeof GraphAnnotationInput.State, - config: LangGraphRunnableConfig + config: LangGraphRunnableConfig, ): Promise> => { const store = config.store; const namespace = ["inputtedState", "data"]; @@ -174,7 +174,7 @@ const workflow = new StateGraph( input: GraphAnnotationInput, output: GraphAnnotationOutput, }, - Annotation.Root({ model_name: Annotation }) + Annotation.Root({ model_name: Annotation }), ) .addNode("agent", agentNode) .addNode("tool", toolNode) diff --git a/libs/langgraph-api/tests/graphs/delay.mts b/libs/langgraph-api/tests/graphs/delay.mts index 6755a1e..7807baf 100644 --- a/libs/langgraph-api/tests/graphs/delay.mts +++ b/libs/langgraph-api/tests/graphs/delay.mts @@ -12,7 +12,7 @@ const StateSchema = Annotation.Root({ }); const longRunning = async ( - state: typeof StateSchema.State + state: typeof StateSchema.State, ): Promise => { await new Promise((resolve) => setTimeout(resolve, state.delay)); return { messages: [`finished after ${state.delay}ms`] }; diff --git a/libs/langgraph-api/tests/graphs/nested.mts b/libs/langgraph-api/tests/graphs/nested.mts index 93e26dd..26aaad4 100644 --- a/libs/langgraph-api/tests/graphs/nested.mts +++ b/libs/langgraph-api/tests/graphs/nested.mts @@ -6,7 +6,7 @@ const child = new StateGraph( reducer: (a, b) => a.concat(b), }), child: Annotation<"child_one" | "child_two">, - }) + }), ) .addNode("c_one", () => ({ messages: ["Entered c_one node"] })) .addNode("c_two", () => ({ messages: ["Entered c_two node"] })) @@ -20,7 +20,7 @@ const parent = new StateGraph( reducer: (a, b) => a.concat(b), }), parent: Annotation<"parent_one" | "parent_two">, - }) + }), ) .addNode("p_one", () => ({ messages: ["Entered p_one node"] })) .addNode("p_two", child.compile()) @@ -33,7 +33,7 @@ const grandParent = new StateGraph( messages: Annotation({ reducer: (a, b) => a.concat(b), }), - }) + }), ) .addNode("gp_one", () => ({ messages: ["Entered gp_one node"] })) .addNode("gp_two", parent.compile()) diff --git a/libs/langgraph-api/tests/graphs/package.json b/libs/langgraph-api/tests/graphs/package.json index 1f9655a..2433161 100644 --- a/libs/langgraph-api/tests/graphs/package.json +++ b/libs/langgraph-api/tests/graphs/package.json @@ -4,4 +4,4 @@ "@langchain/core": "^0.3.22", "@langchain/langgraph": "^0.2.31" } -} \ No newline at end of file +} diff --git a/libs/langgraph-api/tests/graphs/weather.mts b/libs/langgraph-api/tests/graphs/weather.mts index 8ec4560..015b0a6 100644 --- a/libs/langgraph-api/tests/graphs/weather.mts +++ b/libs/langgraph-api/tests/graphs/weather.mts @@ -49,7 +49,7 @@ const router = new StateGraph(routerState) if (route === "weather") return "weather_graph"; return "normal_llm_node"; }, - ["weather_graph", "normal_llm_node"] + ["weather_graph", "normal_llm_node"], ) .addEdge("weather_graph", END) .addEdge("normal_llm_node", END); diff --git a/libs/langgraph-api/tests/parser.test.mts b/libs/langgraph-api/tests/parser.test.mts index df8f7ff..57181c3 100644 --- a/libs/langgraph-api/tests/parser.test.mts +++ b/libs/langgraph-api/tests/parser.test.mts @@ -56,7 +56,7 @@ describe.concurrent("graph factories", () => { ])("%s", ([prop]) => { const schemas = SubgraphExtractor.extractSchemas( { contents: `${common}\n\nexport const graph = ${prop};` }, - "graph" + "graph", ); expect(schemas.graph.input).toMatchObject(MessagesSchema); @@ -107,7 +107,7 @@ describe.concurrent("subgraphs", () => { .compile(); `, }, - "graph" + "graph", ); expect(schemas["graph|child"].input).toMatchObject({ type: "object", @@ -226,7 +226,7 @@ describe.concurrent("subgraphs", () => { .compile(); `, }, - "parent" + "parent", ); expect(Object.keys(schemas)).toEqual( @@ -234,7 +234,7 @@ describe.concurrent("subgraphs", () => { "parent", "parent|parent_two", "parent|parent_two|child_two", - ]) + ]), ); expect(schemas.parent.state).toMatchObject({ @@ -352,10 +352,10 @@ describe.concurrent("subgraphs", () => { `, }, "parent", - { strict: true } + { strict: true }, ); }).toThrowError( - `Multiple unique subgraph invocations found for "parent|parent_one"` + `Multiple unique subgraph invocations found for "parent|parent_one"`, ); }); @@ -414,11 +414,11 @@ describe.concurrent("subgraphs", () => { ], ], }, - "graph" + "graph", ); expect(Object.keys(schemas)).toEqual( - expect.arrayContaining(["graph", "graph|child"]) + expect.arrayContaining(["graph", "graph|child"]), ); expect(schemas["graph|child"].input).toMatchObject({ @@ -547,11 +547,11 @@ describe.concurrent("subgraphs", () => { ], ], }, - "graph" + "graph", ); expect(Object.keys(schemas)).toEqual( - expect.arrayContaining(["graph", "graph|child"]) + expect.arrayContaining(["graph", "graph|child"]), ); expect(schemas["graph|child"].input).toMatchObject({ @@ -665,7 +665,7 @@ describe.concurrent("subgraphs", () => { export const graph = parent.compile() `, }, - "graph" + "graph", ); expect(schemas["graph|child"].input).toMatchObject({ type: "object", @@ -803,11 +803,11 @@ test.concurrent("weather", () => { export const graph = router.compile(); `, }, - "graph" + "graph", ); expect(Object.keys(schemas)).toEqual( - expect.arrayContaining(["graph", "graph|weather_graph"]) + expect.arrayContaining(["graph", "graph|weather_graph"]), ); }); @@ -861,10 +861,10 @@ test.concurrent("nested", () => { export const graph = grandParent.compile(); `, }, - "graph" + "graph", ); expect(Object.keys(schemas)).toEqual( - expect.arrayContaining(["graph", "graph|gp_two", "graph|gp_two|p_two"]) + expect.arrayContaining(["graph", "graph|gp_two", "graph|gp_two|p_two"]), ); }); diff --git a/libs/langgraph-api/tests/utils.server.mts b/libs/langgraph-api/tests/utils.server.mts index ff5b0dc..d9ea926 100644 --- a/libs/langgraph-api/tests/utils.server.mts +++ b/libs/langgraph-api/tests/utils.server.mts @@ -5,7 +5,7 @@ import { readFile } from "node:fs/promises"; import { dirname } from "node:path"; const configPath = fileURLToPath( - new URL("./graphs/langgraph.json", import.meta.url) + new URL("./graphs/langgraph.json", import.meta.url), ); const config = JSON.parse(await readFile(configPath, "utf-8")); @@ -20,5 +20,5 @@ await spawnServer( env: config.env, hostUrl: "https://smith.langchain.com", }, - { pid: process.pid, projectCwd: dirname(configPath) } + { pid: process.pid, projectCwd: dirname(configPath) }, ); diff --git a/libs/langgraph-cli/.prettierrc b/libs/langgraph-cli/.prettierrc new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/libs/langgraph-cli/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/libs/langgraph-cli/README.md b/libs/langgraph-cli/README.md index 38444d4..33fff02 100644 --- a/libs/langgraph-cli/README.md +++ b/libs/langgraph-cli/README.md @@ -51,18 +51,18 @@ The CLI uses a `langgraph.json` configuration file with these key settings: ```json5 { // Required: Graph definitions - "graphs": { - "graph": "./src/graph.ts:graph" + graphs: { + graph: "./src/graph.ts:graph", }, // Optional: Node version (20 only at the moment) - "node_version": "20", + node_version: "20", // Optional: Environment variables - "env": ".env", - + env: ".env", + // Optional: Additional Dockerfile commands - "dockerfile_lines": [] + dockerfile_lines: [], } ``` diff --git a/libs/langgraph-cli/package.json b/libs/langgraph-cli/package.json index 0376038..6485d48 100644 --- a/libs/langgraph-cli/package.json +++ b/libs/langgraph-cli/package.json @@ -15,12 +15,15 @@ "dist/" ], "scripts": { + "clean": "npx -y bun scripts/clean.mjs", "build": "npx -y bun scripts/build.mjs", "prepack": "pnpm run build", "typecheck": "tsc --noEmit", "cli": "tsx src/cli/cli.mts", "cli:watch": "tsx watch src/cli/cli.mts", - "test": "vitest" + "test": "vitest", + "format": "prettier --write .", + "format:check": "prettier --check ." }, "dependencies": { "@commander-js/extra-typings": "^13.0.0", diff --git a/libs/langgraph-cli/scripts/clean.mjs b/libs/langgraph-cli/scripts/clean.mjs new file mode 100644 index 0000000..c24ba6a --- /dev/null +++ b/libs/langgraph-cli/scripts/clean.mjs @@ -0,0 +1,7 @@ +#!/usr/bin/env bun +function $(strings, ...rest) { + console.log("$", ...strings.raw); + return Bun.$(strings, ...rest); +} + +await $`rm -rf dist`; diff --git a/libs/langgraph-cli/src/cli/build.mts b/libs/langgraph-cli/src/cli/build.mts index a20529a..f7fa9be 100644 --- a/libs/langgraph-cli/src/cli/build.mts +++ b/libs/langgraph-cli/src/cli/build.mts @@ -26,7 +26,7 @@ builder .option("-c, --config ", "Path to configuration file", process.cwd()) .option( "--no-pull", - "Running the server with locally-built images. By default LangGraph will pull the latest images from the registry" + "Running the server with locally-built images. By default LangGraph will pull the latest images from the registry", ) .argument("[args...]") .passThroughOptions() @@ -35,7 +35,7 @@ builder withAnalytics((command) => ({ config: command.opts().config !== process.cwd(), pull: command.opts().pull, - })) + })), ) .action(async (pass, params) => { const configPath = await getProjectPath(params.config); @@ -63,6 +63,6 @@ builder exec = $({ ...opts, input }); await stream( - exec`docker build -f - -t ${params.tag} ${projectDir} ${pass}` + exec`docker build -f - -t ${params.tag} ${projectDir} ${pass}`, ); }); diff --git a/libs/langgraph-cli/src/cli/dev.mts b/libs/langgraph-cli/src/cli/dev.mts index 96eda75..0e8c966 100644 --- a/libs/langgraph-cli/src/cli/dev.mts +++ b/libs/langgraph-cli/src/cli/dev.mts @@ -17,7 +17,7 @@ import { withAnalytics } from "./utils/analytics.mjs"; builder .command("dev") .description( - "Run LangGraph API server in development mode with hot reloading." + "Run LangGraph API server in development mode with hot reloading.", ) .option("-p, --port ", "port to run the server on", "2024") .option("-h, --host ", "host to bind to", "localhost") @@ -33,7 +33,7 @@ builder port: command.opts().port !== "2024", host: command.opts().host !== "localhost", n_jobs_per_worker: command.opts().nJobsPerWorker !== "10", - })) + })), ) .action(async (options, { args }) => { try { @@ -65,11 +65,11 @@ builder if (!gitignoreContent.includes(".langgraph_api")) { logger.info( - "Updating .gitignore to prevent `.langgraph_api` from being committed." + "Updating .gitignore to prevent `.langgraph_api` from being committed.", ); await fs.appendFile( gitignorePath, - "\n# LangGraph API\n.langgraph_api\n" + "\n# LangGraph API\n.langgraph_api\n", ); } @@ -96,15 +96,15 @@ builder const oldWatch = Object.entries(watcher.getWatched()).flatMap( ([dir, files]) => - files.map((file) => path.resolve(projectCwd, dir, file)) + files.map((file) => path.resolve(projectCwd, dir, file)), ); const addedTarget = newWatch.filter( - (target) => !oldWatch.includes(target) + (target) => !oldWatch.includes(target), ); const removedTarget = oldWatch.filter( - (target) => !newWatch.includes(target) + (target) => !newWatch.includes(target), ); watcher.unwatch(removedTarget).add(addedTarget); @@ -130,21 +130,21 @@ builder if ("python_version" in config) { logger.warn( - "Launching Python server from @langchain/langgraph-cli is experimental. Please use the `langgraph-cli` package from PyPi instead." + "Launching Python server from @langchain/langgraph-cli is experimental. Please use the `langgraph-cli` package from PyPi instead.", ); const { spawnPythonServer } = await import("./dev.python.mjs"); child = await spawnPythonServer( { ...options, rest: args }, { configPath, config, env, hostUrl }, - { pid, projectCwd } + { pid, projectCwd }, ); } else { const { spawnServer } = await import("@langchain/langgraph-api"); child = await spawnServer( options, { config, env, hostUrl }, - { pid, projectCwd } + { pid, projectCwd }, ); } }; diff --git a/libs/langgraph-cli/src/cli/dev.python.mts b/libs/langgraph-cli/src/cli/dev.python.mts index 30559fc..e866d38 100644 --- a/libs/langgraph-cli/src/cli/dev.python.mts +++ b/libs/langgraph-cli/src/cli/dev.python.mts @@ -79,7 +79,7 @@ function getDownloadUrl(info: UvBinaryInfo): string { async function downloadAndExtract( url: string, destPath: string, - info: UvBinaryInfo + info: UvBinaryInfo, ): Promise { const response = await fetch(url); if (!response.ok) @@ -100,7 +100,7 @@ async function downloadAndExtract( await tarExtract({ file: tempFilePath, cwd: tempDirPath }); sourceBinaryPath = path.resolve( sourceBinaryPath, - path.basename(tempFilePath).slice(0, ".tar.gz".length * -1) + path.basename(tempFilePath).slice(0, ".tar.gz".length * -1), ); } sourceBinaryPath = path.resolve(sourceBinaryPath, info.binaryName); @@ -151,7 +151,7 @@ export async function spawnPythonServer( options: { pid: number; projectCwd: string; - } + }, ) { const deps = await assembleLocalDeps(context.configPath, context.config); const requirements = deps.rebuildFiles.filter((i) => i.endsWith(".txt")); @@ -180,6 +180,6 @@ export async function spawnPythonServer( stdio: ["inherit", "inherit", "inherit"], env: context.env, cwd: options.projectCwd, - } + }, ); } diff --git a/libs/langgraph-cli/src/cli/docker.mts b/libs/langgraph-cli/src/cli/docker.mts index bb51eb0..71a3828 100644 --- a/libs/langgraph-cli/src/cli/docker.mts +++ b/libs/langgraph-cli/src/cli/docker.mts @@ -25,12 +25,12 @@ const fileExists = async (path: string) => { builder .command("dockerfile") .description( - "Generate a Dockerfile for the LangGraph API server, with Docker Compose options." + "Generate a Dockerfile for the LangGraph API server, with Docker Compose options.", ) .argument("", "Path to save the Dockerfile") .option( "--add-docker-compose", - "Add additional files for running the LangGraph API server with docker-compose. These files include a docker-compose.yml, .env file, and a .dockerignore file." + "Add additional files for running the LangGraph API server with docker-compose. These files include a docker-compose.yml, .env file, and a .dockerignore file.", ) .option("-c, --config ", "Path to configuration file", process.cwd()) .hook( @@ -38,7 +38,7 @@ builder withAnalytics((command) => ({ config: command.opts().config !== process.cwd(), add_docker_compose: !!command.opts().addDockerCompose, - })) + })), ) .action(async (savePath, options) => { const configPath = await getProjectPath(options.config); @@ -67,7 +67,7 @@ builder const composePath = path.resolve( path.dirname(targetPath), - "docker-compose.yml" + "docker-compose.yml", ); await fs.writeFile(composePath, compose); @@ -75,7 +75,7 @@ builder const dockerignorePath = path.resolve( path.dirname(targetPath), - ".dockerignore" + ".dockerignore", ); if (!fileExists(dockerignorePath)) { @@ -124,7 +124,7 @@ builder *.test.js *.spec.js tests - ` + `, ); logger.info(`βœ… Created: ${path.basename(dockerignorePath)}`); } @@ -139,7 +139,7 @@ builder # Or if you have a LangGraph Cloud license key, then uncomment the following line: # LANGGRAPH_CLOUD_LICENSE_KEY=your-license-key # Add any other environment variables go below... - ` + `, ); logger.info(`βœ… Created: ${path.basename(envPath)}`); } diff --git a/libs/langgraph-cli/src/cli/up.mts b/libs/langgraph-cli/src/cli/up.mts index 35cbd95..2967fde 100644 --- a/libs/langgraph-cli/src/cli/up.mts +++ b/libs/langgraph-cli/src/cli/up.mts @@ -30,7 +30,7 @@ const waitForHealthcheck = async (port: number) => { while (Date.now() - now < 10_000) { const ok = await fetch(`http://localhost:${port}/ok`).then( (res) => res.ok, - () => false + () => false, ); await new Promise((resolve) => setTimeout(resolve, 100)); @@ -46,23 +46,23 @@ builder .option("-c, --config ", "Path to configuration file", process.cwd()) .option( "-d, --docker-compose ", - "Advanced: Path to docker-compose.yml file with additional services to launch" + "Advanced: Path to docker-compose.yml file with additional services to launch", ) .option("-p, --port ", "Port to run the server on", "8123") .option("--recreate", "Force recreate containers and volumes", false) .option( "--no-pull", - "Running the server with locally-built images. By default LangGraph will pull the latest images from the registry" + "Running the server with locally-built images. By default LangGraph will pull the latest images from the registry", ) .option("--watch", "Restart on file changes", false) .option( "--wait", "Wait for services to start before returning. Implies --detach", - false + false, ) .option( "--postgres-uri ", - "Postgres URI to use for the database. Defaults to launching a local database" + "Postgres URI to use for the database. Defaults to launching a local database", ) .hook( "preAction", @@ -75,7 +75,7 @@ builder pull: command.opts().pull, watch: command.opts().watch, wait: command.opts().wait, - })) + })), ) .action(async (params) => { logger.info("Starting LangGraph API server..."); @@ -83,7 +83,7 @@ builder dedent` For local dev, requires env var LANGSMITH_API_KEY with access to LangGraph Cloud closed beta. For production use, requires a license key in env var LANGGRAPH_CLOUD_LICENSE_KEY. - ` + `, ); const configPath = await getProjectPath(params.config); @@ -118,13 +118,13 @@ builder // remove dangling images logger.info(`Pruning dangling images...`); await stream( - exec`docker image prune -f --filter ${`label=com.docker.compose.project=${name}`}` + exec`docker image prune -f --filter ${`label=com.docker.compose.project=${name}`}`, ); // remove stale containers logger.info(`Pruning stale containers...`); await stream( - exec`docker container prune -f --filter ${`label=com.docker.compose.project=${name}`}` + exec`docker container prune -f --filter ${`label=com.docker.compose.project=${name}`}`, ); const input = createCompose(capabilities, { @@ -148,7 +148,7 @@ builder args.push("--watch"); } else { logger.warn( - "Watch mode is not available. Please upgrade your Docker Engine." + "Watch mode is not available. Please upgrade your Docker Engine.", ); } } else if (params.wait) { @@ -178,7 +178,7 @@ builder - LangGraph Studio: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:${params.port} `); }, - () => void 0 + () => void 0, ); await up.catch(() => void 0); diff --git a/libs/langgraph-cli/src/cli/utils/analytics.mts b/libs/langgraph-cli/src/cli/utils/analytics.mts index 72668a6..fd30e88 100644 --- a/libs/langgraph-cli/src/cli/utils/analytics.mts +++ b/libs/langgraph-cli/src/cli/utils/analytics.mts @@ -34,7 +34,7 @@ async function logData(data: LogData): Promise { let analyticsPromise = Promise.resolve(); export function withAnalytics>( - fn?: (command: TCommand) => Record + fn?: (command: TCommand) => Record, ) { if (process.env.LANGGRAPH_CLI_NO_ANALYTICS === "1") { return () => void 0; @@ -49,7 +49,7 @@ export function withAnalytics>( cli_version: version, cli_command: actionCommand.name(), params: fn?.(actionCommand) ?? {}, - }).catch(() => {}) + }).catch(() => {}), ); }; } diff --git a/libs/langgraph-cli/src/cli/utils/ipc/server.mts b/libs/langgraph-cli/src/cli/utils/ipc/server.mts index dc7c882..fc53d50 100644 --- a/libs/langgraph-cli/src/cli/utils/ipc/server.mts +++ b/libs/langgraph-cli/src/cli/utils/ipc/server.mts @@ -53,7 +53,7 @@ export const createIpcServer = async () => { bufferData((message: Buffer) => { const data = JSON.parse(message.toString()); server.emit("data", data); - }) + }), ); }); diff --git a/libs/langgraph-cli/src/cli/utils/ipc/utils/temporary-directory.mts b/libs/langgraph-cli/src/cli/utils/ipc/utils/temporary-directory.mts index 1d8af09..a0cd9ac 100644 --- a/libs/langgraph-cli/src/cli/utils/ipc/utils/temporary-directory.mts +++ b/libs/langgraph-cli/src/cli/utils/ipc/utils/temporary-directory.mts @@ -1,17 +1,17 @@ // MIT License -// +// // Copyright (c) Hiroki Osame -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -19,7 +19,7 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// +// // https://github.com/privatenumber/tsx/tree/28a3e7d2b8fd72b683aab8a98dd1fcee4624e4cb import path from "node:path"; import os from "node:os"; diff --git a/libs/langgraph-cli/src/cli/utils/version.mts b/libs/langgraph-cli/src/cli/utils/version.mts index 419cc95..246306a 100644 --- a/libs/langgraph-cli/src/cli/utils/version.mts +++ b/libs/langgraph-cli/src/cli/utils/version.mts @@ -4,7 +4,7 @@ import * as url from "node:url"; async function getVersion() { try { const packageJson = url.fileURLToPath( - new URL("../../../package.json", import.meta.url) + new URL("../../../package.json", import.meta.url), ); const { version } = JSON.parse(await fs.readFile(packageJson, "utf-8")); return version + "+js"; diff --git a/libs/langgraph-cli/src/docker/compose.mts b/libs/langgraph-cli/src/docker/compose.mts index 09c9e6e..728e4b2 100644 --- a/libs/langgraph-cli/src/docker/compose.mts +++ b/libs/langgraph-cli/src/docker/compose.mts @@ -59,7 +59,7 @@ function parseVersion(input: string): Version { const patchStr = parts[2] ?? "0"; const major = Number.parseInt( - majorStr.startsWith("v") ? majorStr.slice(1) : majorStr + majorStr.startsWith("v") ? majorStr.slice(1) : majorStr, ); const minor = Number.parseInt(minorStr); const patch = Number.parseInt(patchStr.split("-").at(0) ?? "0"); @@ -96,7 +96,7 @@ export async function getDockerCapabilities(): Promise { z.object({ Name: z.string(), Version: z.string().optional(), - }) + }), ), }), }) @@ -108,11 +108,11 @@ export async function getDockerCapabilities(): Promise { const composePlugin = info.data.ClientInfo.Plugins.find( (i): i is { Name: string; Version: string } => - i.Name === "compose" && i.Version != null + i.Name === "compose" && i.Version != null, ); const buildxPlugin = info.data.ClientInfo.Plugins.find( (i): i is { Name: string; Version: string } => - i.Name === "buildx" && i.Version != null + i.Name === "buildx" && i.Version != null, ); let composeRes: Pick; @@ -124,7 +124,7 @@ export async function getDockerCapabilities(): Promise { } else { try { const standalone = await $( - await getExecaOptions() + await getExecaOptions(), )`docker-compose --version --short`; composeRes = { composeType: "standalone", @@ -159,7 +159,11 @@ function isPlainObject(value: unknown): value is Record { export function createCompose( capabilities: DockerCapabilities, - options: { port?: number; postgresUri?: string; apiDef?: Record } + options: { + port?: number; + postgresUri?: string; + apiDef?: Record; + }, ) { let includeDb = false; let postgresUri = options.postgresUri; diff --git a/libs/langgraph-cli/src/docker/docker.mts b/libs/langgraph-cli/src/docker/docker.mts index 512c8be..e38e98e 100644 --- a/libs/langgraph-cli/src/docker/docker.mts +++ b/libs/langgraph-cli/src/docker/docker.mts @@ -25,7 +25,7 @@ async function exists(path: string) { export async function assembleLocalDeps( configPath: string, - config: Config + config: Config, ): Promise { const reserved = new Set([ "src", @@ -46,7 +46,7 @@ export async function assembleLocalDeps( function checkReserved(name: string, ref: string) { if (reserved.has(name)) { throw new Error( - `Package name '${name}' used in local dep '${ref}' is reserved. Rename the directory.` + `Package name '${name}' used in local dep '${ref}' is reserved. Rename the directory.`, ); } reserved.add(name); @@ -71,7 +71,7 @@ export async function assembleLocalDeps( throw new Error(`Local dependency must be a directory: ${resolved}`); } else if (!resolved.startsWith(path.dirname(configPath))) { throw new Error( - `Local dependency must be a subdirectory of the config file: ${resolved}` + `Local dependency must be a subdirectory of the config file: ${resolved}`, ); } @@ -98,7 +98,7 @@ export async function assembleLocalDeps( // flat layout if (path.basename(resolved).includes("-")) { throw new Error( - `Package name '${path.basename(resolved)}' contains a hyphen. Rename the directory to use it as flat-layout package.` + `Package name '${path.basename(resolved)}' contains a hyphen. Rename the directory to use it as flat-layout package.`, ); } @@ -167,13 +167,13 @@ export async function assembleLocalDeps( async function updateGraphPaths( configPath: string, config: Config, - localDeps: LocalDeps + localDeps: LocalDeps, ) { for (const [graphId, importStr] of Object.entries(config.graphs)) { let [moduleStr, attrStr] = importStr.split(":", 2); if (!moduleStr || !attrStr) { throw new Error( - `Import string "${importStr}" must be in format ":".` + `Import string "${importStr}" must be in format ":".`, ); } @@ -193,7 +193,7 @@ async function updateGraphPaths( } for (const [fauxPkg, [_, destPath]] of Object.entries( - localDeps.fauxPkgs + localDeps.fauxPkgs, )) { if (resolved.startsWith(fauxPkg)) { moduleStr = `${destPath}/${path.relative(fauxPkg, resolved)}`; @@ -201,7 +201,7 @@ async function updateGraphPaths( } throw new Error( - `Module '${importStr}' not found in 'dependencies' list. Add its containing package to 'dependencies' list.` + `Module '${importStr}' not found in 'dependencies' list. Add its containing package to 'dependencies' list.`, ); } } @@ -232,7 +232,7 @@ export async function configToDocker( watch: boolean; dockerCommand?: string; onWorkingDir?: (workingDir: string | undefined) => void; - } + }, ) { // figure out the package manager used here const testFile = async (file: string) => @@ -264,16 +264,16 @@ export async function configToDocker( : undefined; const pipReqs = localDeps.pipReqs.map( - ([reqpath, destpath]) => `ADD ${reqpath} ${destpath}` + ([reqpath, destpath]) => `ADD ${reqpath} ${destpath}`, ); if (pipReqs.length) { pipReqs.push( - `RUN ${pipInstall} ${localDeps.pipReqs.map(([, r]) => `-r ${r}`).join(" ")}` + `RUN ${pipInstall} ${localDeps.pipReqs.map(([, r]) => `-r ${r}`).join(" ")}`, ); } const localPkg = Object.entries(localDeps.realPkgs).map( - ([fullpath, relpath]) => `ADD ${relpath} /deps/${path.basename(fullpath)}` + ([fullpath, relpath]) => `ADD ${relpath} /deps/${path.basename(fullpath)}`, ); const fauxPkgs = Object.entries(localDeps.fauxPkgs).flatMap( @@ -289,7 +289,7 @@ export async function configToDocker( echo "${options?.dockerCommand === "build" ? "$line" : "$$line"}" >> /deps/__outer_${path.basename(fullpath)}/pyproject.toml; \ done `, - ] + ], ); if ( @@ -344,7 +344,7 @@ export async function configToDocker( if (options?.watch && (localDeps.workingDir || localDeps.reloadDir)) { // TODO: hacky, should add as entrypoint to the langgraph-api base image lines.push( - `CMD exec uvicorn langgraph_api.server:app --log-config /api/logging.json --no-access-log --host 0.0.0.0 --port 8000 --reload --reload-dir ${localDeps.workingDir || localDeps.reloadDir}` + `CMD exec uvicorn langgraph_api.server:app --log-config /api/logging.json --no-access-log --host 0.0.0.0 --port 8000 --reload --reload-dir ${localDeps.workingDir || localDeps.reloadDir}`, ); } @@ -354,7 +354,7 @@ export async function configToDocker( export async function configToWatch( configPath: string, config: Config, - localDeps: LocalDeps + localDeps: LocalDeps, ) { const projectDir = path.dirname(configPath); const watch: Array<{ @@ -405,7 +405,7 @@ export async function configToCompose( options?: { watch: boolean; extendEnv?: Record; - } + }, ): Promise<{ apiDef: Record; rewrite: { source: string; target: string } | undefined; diff --git a/libs/langgraph-cli/src/docker/shell.mts b/libs/langgraph-cli/src/docker/shell.mts index 7354464..7f89bf1 100644 --- a/libs/langgraph-cli/src/docker/shell.mts +++ b/libs/langgraph-cli/src/docker/shell.mts @@ -53,8 +53,8 @@ async function getLoginPath() { const [fromShell, fromBackup] = await Promise.allSettled( [extractPathFromShell(), guessUserPath()].map((promise) => - promise.then(verifyDockerPath) - ) + promise.then(verifyDockerPath), + ), ); if (fromShell.status === "fulfilled") { @@ -65,7 +65,7 @@ async function getLoginPath() { console.error( "Failed to get PATH from shell or backup", fromShell.reason, - fromBackup.reason + fromBackup.reason, ); throw fromShell.reason || fromBackup.reason; } @@ -76,7 +76,7 @@ async function getLoginPath() { type CommonOptions = Exclude[1], undefined>; export async function getExecaOptions( - options?: T + options?: T, ) { const env = await getLoginPath(); return { ...options, env } as T & { env: typeof env }; diff --git a/libs/langgraph-cli/src/utils/config.mts b/libs/langgraph-cli/src/utils/config.mts index 70ef0fb..6357430 100644 --- a/libs/langgraph-cli/src/utils/config.mts +++ b/libs/langgraph-cli/src/utils/config.mts @@ -7,7 +7,7 @@ const BaseConfigSchema = z.object({ graphs: z.record( z.string().refine((i) => i.includes(":"), { message: "Import string must be in format ':'", - }) + }), ), _INTERNAL_docker_tag: z.string().optional(), env: z @@ -45,16 +45,16 @@ const PythonConfigSchema = BaseConfigSchema.merge( dependencies: z .array(z.string()) .nonempty("You need to specify at least one dependency"), - }) + }), ).merge( z.object({ python_version: PythonVersionSchema.default(DEFAULT_PYTHON_VERSION), node_version: NodeVersionSchema.optional(), - }) + }), ); const NodeConfigSchema = BaseConfigSchema.merge( - z.object({ node_version: NodeVersionSchema.default(DEFAULT_NODE_VERSION) }) + z.object({ node_version: NodeVersionSchema.default(DEFAULT_NODE_VERSION) }), ); const ConfigSchema = z.union([NodeConfigSchema, PythonConfigSchema]); @@ -66,7 +66,7 @@ export const getConfig = (config: z.input | string) => { const { graphs } = BaseConfigSchema.parse(input); const isPython = Object.values(graphs).map((i) => - PYTHON_EXTENSIONS.includes(extname(i.split(":")[0])) + PYTHON_EXTENSIONS.includes(extname(i.split(":")[0])), ); const somePython = isPython.some((i) => i); const someNode = !isPython.every((i) => i); diff --git a/libs/langgraph-cli/src/utils/logging.mts b/libs/langgraph-cli/src/utils/logging.mts index 1e745ea..30f2508 100644 --- a/libs/langgraph-cli/src/utils/logging.mts +++ b/libs/langgraph-cli/src/utils/logging.mts @@ -48,7 +48,7 @@ export const logger = createLogger({ return JSON.stringify({ timestamp, level, event, ...rest }); }), - ]) + ]), ), transports: [new transports.Console()], }); @@ -59,7 +59,7 @@ const formatStack = (stack: string | undefined | null) => { const [firstFile] = stacktraceParser(stack).filter( (item) => !item.file?.split(path.sep).includes("node_modules") && - !item.file?.startsWith("node:") + !item.file?.startsWith("node:"), ); if (firstFile?.file && firstFile?.lineNumber) { @@ -72,7 +72,7 @@ const formatStack = (stack: string | undefined | null) => { const spliceIndex = messageLines.findIndex((i) => i.includes(filePath)); const padding = " ".repeat( - Math.max(0, messageLines[spliceIndex].indexOf("at")) + Math.max(0, messageLines[spliceIndex].indexOf("at")), ); const highlightCode = process.stdout.isTTY; @@ -80,7 +80,7 @@ const formatStack = (stack: string | undefined | null) => { let codeFrame = codeFrameColumns( readFileSync(filePath, "utf-8"), { start: { line, column } }, - { highlightCode } + { highlightCode }, ); codeFrame = codeFrame @@ -111,7 +111,7 @@ export const logError = ( options?: { context?: Record; prefix?: string; - } + }, ) => { let message; let context = options?.context; diff --git a/libs/langgraph-cli/tests/config.test.mts b/libs/langgraph-cli/tests/config.test.mts index c3d9e10..7c21016 100644 --- a/libs/langgraph-cli/tests/config.test.mts +++ b/libs/langgraph-cli/tests/config.test.mts @@ -35,13 +35,13 @@ describe("config to watch", () => { const localDeps = await assembleLocalDeps( path.resolve(__dirname, "./unit_tests/langgraph.json"), - config + config, ); const watch = await configToWatch( path.resolve(__dirname, "./unit_tests/langgraph.json"), config, - localDeps + localDeps, ); expect(watch).toEqual([ @@ -65,13 +65,13 @@ describe("config to watch", () => { const localDeps = await assembleLocalDeps( path.resolve(__dirname, "./unit_tests/langgraph.json"), - config + config, ); const watch = await configToWatch( path.resolve(__dirname, "./unit_tests/langgraph.json"), config, - localDeps + localDeps, ); expect(watch).toEqual([ @@ -113,7 +113,7 @@ describe("config to docker", () => { const actual = await configToDocker( PATH_TO_CONFIG, config, - await assembleLocalDeps(PATH_TO_CONFIG, config) + await assembleLocalDeps(PATH_TO_CONFIG, config), ); expect(actual).toEqual(dedenter` @@ -144,7 +144,7 @@ describe("config to docker", () => { const actual = await configToDocker( PATH_TO_CONFIG, config, - await assembleLocalDeps(PATH_TO_CONFIG, config) + await assembleLocalDeps(PATH_TO_CONFIG, config), ); expect(actual).toEqual(dedenter` @@ -178,7 +178,7 @@ describe("config to docker", () => { await configToDocker( PATH_TO_CONFIG, config, - await assembleLocalDeps(PATH_TO_CONFIG, config) + await assembleLocalDeps(PATH_TO_CONFIG, config), ); }).rejects.toThrowError(/Could not find local dependency/); @@ -194,7 +194,7 @@ describe("config to docker", () => { await configToDocker( PATH_TO_CONFIG, config, - await assembleLocalDeps(PATH_TO_CONFIG, config) + await assembleLocalDeps(PATH_TO_CONFIG, config), ); }).rejects.toThrowError(/Could not find local module/); }); @@ -210,7 +210,7 @@ describe("config to docker", () => { const actual = await configToDocker( PATH_TO_CONFIG, config, - await assembleLocalDeps(PATH_TO_CONFIG, config) + await assembleLocalDeps(PATH_TO_CONFIG, config), ); expect(actual).toEqual(dedenter` @@ -239,7 +239,7 @@ describe("config to docker", () => { version = "0.1" dependencies = ["langchain"] `, - { encoding: "utf-8" } + { encoding: "utf-8" }, ); const graphs = { agent: "./graphs/agent.py:graph" }; @@ -252,7 +252,7 @@ describe("config to docker", () => { const actual = await configToDocker( PATH_TO_CONFIG, config, - await assembleLocalDeps(PATH_TO_CONFIG, config) + await assembleLocalDeps(PATH_TO_CONFIG, config), ); await fs.rm(pyproject); @@ -279,7 +279,7 @@ describe("config to docker", () => { const actual = await configToDocker( PATH_TO_CONFIG, config, - await assembleLocalDeps(PATH_TO_CONFIG, config) + await assembleLocalDeps(PATH_TO_CONFIG, config), ); expect(actual).toEqual(dedenter` @@ -314,7 +314,7 @@ describe("config to docker", () => { const actual = await configToDocker( PATH_TO_CONFIG, config, - await assembleLocalDeps(PATH_TO_CONFIG, config) + await assembleLocalDeps(PATH_TO_CONFIG, config), ); // TODO: add support for any packager @@ -484,7 +484,7 @@ describe("config to compose", () => { dependencies: ["."], graphs: graph, }, - { watch: true } + { watch: true }, ); expect(yaml.stringify(actual, { blockQuote: "literal" })).toEqual(expected); @@ -497,7 +497,7 @@ describe("config to compose", () => { it("env", async () => { const PATH_TO_CONFIG = path.resolve( __dirname, - "./env_tests/langgraph.json" + "./env_tests/langgraph.json", ); const graph = { agent: "./agent.py:graph" }; @@ -545,7 +545,7 @@ describe("config to compose", () => { { watch: true, extendEnv: { ANTHROPIC_API_KEY: "key", OPENAI_API_KEY: "key" }, - } + }, ); expect(yaml.stringify(actual, { blockQuote: "literal" })).toEqual(expected); @@ -566,10 +566,10 @@ describe("config to compose", () => { env: ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"], dockerfile_lines: [], }, - { watch: true } - ) + { watch: true }, + ), ).rejects.toThrowError( - /Missing environment variables: OPENAI_API_KEY, ANTHROPIC_API_KEY/ + /Missing environment variables: OPENAI_API_KEY, ANTHROPIC_API_KEY/, ); }); @@ -659,7 +659,7 @@ describe("config to compose", () => { env: ".env", dockerfile_lines: [], }, - { watch: true } + { watch: true }, ); expect(yaml.stringify(actual, { blockQuote: "literal" })).toEqual(expected); @@ -672,11 +672,11 @@ describe("config to compose", () => { describe("packaging", () => { async function loadConfig( - rel: string + rel: string, ): Promise<[path: string, config: Config]> { const res = path.resolve(__dirname, rel); const config = getConfig( - JSON.parse(await fs.readFile(res, { encoding: "utf-8" })) + JSON.parse(await fs.readFile(res, { encoding: "utf-8" })), ); return [res, config]; } @@ -684,7 +684,7 @@ describe("packaging", () => { it("faux", async () => { const { apiDef: actual } = await configToCompose( ...(await loadConfig("./packaging_tests/faux/langgraph.json")), - { watch: true } + { watch: true }, ); const expected = @@ -728,7 +728,7 @@ describe("packaging", () => { it("js", async () => { const { apiDef: actual, rewrite } = await configToCompose( ...(await loadConfig("./packaging_tests/js/langgraph.json")), - { watch: true } + { watch: true }, ); const expected = @@ -787,7 +787,7 @@ it("node config and python config", () => { dockerfile_lines: [], dependencies: ["."], graphs: { agent: "./route.ts:agent" }, - }) + }), ).toEqual({ node_version: "20", dockerfile_lines: [], @@ -804,7 +804,7 @@ it("node config and python config", () => { pip_config_file: undefined, dependencies: ["."], graphs: { agent: "./agent.py:graph" }, - }) + }), ).toEqual({ python_version: "3.11", pip_config_file: undefined, @@ -819,7 +819,7 @@ it("node config and python config", () => { getConfig({ dependencies: ["."], graphs: { agent: "./agent.py:graph" }, - }) + }), ).toEqual({ python_version: "3.11", pip_config_file: undefined, @@ -842,7 +842,7 @@ it("node config and python config", () => { getConfig({ dependencies: ["."], graphs: { js: "./agent.js:graph", py: "./agent.py:graph" }, - }) + }), ).toEqual({ python_version: "3.12", node_version: "20", @@ -860,7 +860,7 @@ it("node config and python config", () => { python_version: "3.11", graphs: { agent: "./agent.py:graph", js: "./agent.js:graph" }, dependencies: ["."], - }) + }), ) .toThrow("Only Python 3.12 is supported with Node.js"); @@ -870,7 +870,7 @@ it("node config and python config", () => { getConfig({ graphs: { agent: "agent.py" }, dependencies: ["."], - }) + }), ) .toThrow(`Import string must be in format ':'`); @@ -881,7 +881,7 @@ it("node config and python config", () => { graphs: { agent: "./agent.py:graph" }, // @ts-expect-error dependencies: [], // Empty array - }) + }), ) .toThrow("You need to specify at least one dependency"); @@ -893,7 +893,7 @@ it("node config and python config", () => { python_version: "3.10", // Unsupported version graphs: { agent: "./agent.py:graph" }, dependencies: ["."], - }) + }), ) .toThrow(); @@ -904,7 +904,7 @@ it("node config and python config", () => { // @ts-expect-error node_version: "18", // Unsupported version graphs: { agent: "./agent.js:graph" }, - }) + }), ) .toThrow(); }); diff --git a/libs/langgraph-cli/tests/docker.test.mts b/libs/langgraph-cli/tests/docker.test.mts index 40988af..a4e7ec8 100644 --- a/libs/langgraph-cli/tests/docker.test.mts +++ b/libs/langgraph-cli/tests/docker.test.mts @@ -48,8 +48,8 @@ it("compose with custom db and healthcheck", () => { expect( createCompose( { ...DEFAULT_DOCKER_CAPABILITIES, healthcheckStartInterval: true }, - { port, postgresUri } - ) + { port, postgresUri }, + ), ).toEqual(dedent` services: langgraph-redis: diff --git a/package.json b/package.json index 5a6f0db..843c75e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,15 @@ { "name": "langgraphjs-api", "private": true, - "scripts": {}, - "keywords": [] + "packageManager": "pnpm@9.1.1", + "scripts": { + "clean": "turbo run clean", + "build": "turbo run build", + "format": "turbo run format", + "format:check": "turbo run format:check" + }, + "keywords": [], + "devDependencies": { + "turbo": "^2.4.0" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 294b42f..a81bc9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,11 @@ settings: importers: - .: {} + .: + devDependencies: + turbo: + specifier: ^2.4.0 + version: 2.4.0 libs/create-langgraph: dependencies: @@ -1307,6 +1311,40 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + turbo-darwin-64@2.4.0: + resolution: {integrity: sha512-kVMScnPUa3R4n7woNmkR15kOY0aUwCLJcUyH5UC59ggKqr5HIHwweKYK8N1pwBQso0LQF4I9i93hIzfJguCcwQ==} + cpu: [x64] + os: [darwin] + + turbo-darwin-arm64@2.4.0: + resolution: {integrity: sha512-8JObIpfun1guA7UlFR5jC/SOVm49lRscxMxfg5jZ5ABft79rhFC+ygN9AwAhGKv6W2DUhIh2xENkSgu4EDmUyg==} + cpu: [arm64] + os: [darwin] + + turbo-linux-64@2.4.0: + resolution: {integrity: sha512-xWDGGcRlBuGV7HXWAVuTY6vsQi4aZxGMAnuiuNDg8Ij1aHGohOM0RUsWMXjxz4vuJmjk9+/D6NQqHH3AJEXezg==} + cpu: [x64] + os: [linux] + + turbo-linux-arm64@2.4.0: + resolution: {integrity: sha512-c3En99xMguc/Pdtk/rZP53LnDdw0W6lgUc04he8r8F+UHYSNvgzHh0WGXXmCC6lGbBH72kPhhGx4bAwyvi7dug==} + cpu: [arm64] + os: [linux] + + turbo-windows-64@2.4.0: + resolution: {integrity: sha512-/gOORuOlyA8JDPzyA16CD3wvyRcuBFePa1URAnFUof9hXQmKxK0VvSDO79cYZFsJSchCKNJpckUS0gYxGsWwoA==} + cpu: [x64] + os: [win32] + + turbo-windows-arm64@2.4.0: + resolution: {integrity: sha512-/DJIdTFijEMM5LSiEpSfarDOMOlYqJV+EzmppqWtHqDsOLF4hbbIBH9sJR6OOp5dURAu5eURBYdmvBRz9Lo6TA==} + cpu: [arm64] + os: [win32] + + turbo@2.4.0: + resolution: {integrity: sha512-ah/yQp2oMif1X0u7fBJ4MLMygnkbKnW5O8SG6pJvloPCpHfFoZctkSVQiJ3VnvNTq71V2JJIdwmOeu1i34OQyg==} + hasBin: true + type-fest@0.7.1: resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} engines: {node: '>=8'} @@ -2385,6 +2423,33 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + turbo-darwin-64@2.4.0: + optional: true + + turbo-darwin-arm64@2.4.0: + optional: true + + turbo-linux-64@2.4.0: + optional: true + + turbo-linux-arm64@2.4.0: + optional: true + + turbo-windows-64@2.4.0: + optional: true + + turbo-windows-arm64@2.4.0: + optional: true + + turbo@2.4.0: + optionalDependencies: + turbo-darwin-64: 2.4.0 + turbo-darwin-arm64: 2.4.0 + turbo-linux-64: 2.4.0 + turbo-linux-arm64: 2.4.0 + turbo-windows-64: 2.4.0 + turbo-windows-arm64: 2.4.0 + type-fest@0.7.1: {} typescript@5.5.4: {} diff --git a/turbo.json b/turbo.json new file mode 100644 index 0000000..406fe97 --- /dev/null +++ b/turbo.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://turbo.build/schema.json", + "tasks": { + "build": { + "dependsOn": ["^build"], + "outputs": ["dist/**"] + }, + "format": { + "dependsOn": ["^format"] + }, + "format:check": { + "dependsOn": ["^format:check"] + }, + "test": { + "cache": false, + "dependsOn": ["^build", "build"] + }, + "clean": { + "dependsOn": ["^clean"] + }, + "precommit": {}, + "start": { + "cache": false + } + } +}