mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-20 06:35:46 +02:00
Compare commits
29
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08cb68feba | ||
|
|
0ed23858b9 | ||
|
|
eb7ed80272 | ||
|
|
176eaafbab | ||
|
|
a688d287a1 | ||
|
|
a8ea374b83 | ||
|
|
11077affd6 | ||
|
|
d236412ab3 | ||
|
|
b225b603b8 | ||
|
|
1fbc623d57 | ||
|
|
bc6bb1027e | ||
|
|
a1e35d8a3b | ||
|
|
5112f55904 | ||
|
|
c438dd2a03 | ||
|
|
2c520982bb | ||
|
|
8414ae01de | ||
|
|
1801a193bc | ||
|
|
05299c8dba | ||
|
|
283dbe5015 | ||
|
|
e224fdc84a | ||
|
|
01c9f6e722 | ||
|
|
288337b217 | ||
|
|
01c5302c13 | ||
|
|
3e64219370 | ||
|
|
9257282252 | ||
|
|
73d0c804ae | ||
|
|
4f13a66924 | ||
|
|
6859bc312d | ||
|
|
38218c55e5 |
@@ -1,29 +1,29 @@
|
||||
name: "\U0001F41B Bug Report"
|
||||
description: Report a bug in LangGraph. To report a security issue, please instead use the security option below. For questions, please use the LangChain Forum at forum.langchain.com.
|
||||
labels: [pending, bug]
|
||||
description: Report a bug in LangGraph. To report a security issue, please instead use the security option below. For questions, please use the GitHub Discussions.
|
||||
labels: [pending,bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
value: >
|
||||
Thank you for taking the time to file a bug report.
|
||||
|
||||
Use this to report BUGS in LangGraph. For usage questions, feature requests and general design questions, please use the [LangChain Forum](https://forum.langchain.com/).
|
||||
|
||||
|
||||
Use this to report BUGS in LangGraph. For usage questions, feature requests and general design questions, please use [GitHub Discussions](https://github.com/langchain-ai/langgraph/discussions).
|
||||
|
||||
Relevant links to check before filing a bug report to see if your issue has already been reported, fixed or
|
||||
if there's another way to solve your problem:
|
||||
|
||||
* [LangChain Forum](https://forum.langchain.com/),
|
||||
* [LangGraph Github Issues](https://github.com/langchain-ai/langgraph/issues),
|
||||
* [LangGraph how-to guides](https://langchain-ai.github.io/langgraph/how-tos/).
|
||||
* [LangChain documentation with the integrated search](https://docs.langchain.com/),
|
||||
* [GitHub search](https://github.com/langchain-ai/langgraph),
|
||||
|
||||
[LangGraph Github Discussions](https://github.com/langchain-ai/langgraph/discussions),
|
||||
[LangGraph Github Issues](https://github.com/langchain-ai/langgraph/issues),
|
||||
[LangGraph how-to guides](https://langchain-ai.github.io/langgraph/how-tos/).
|
||||
[LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction),
|
||||
[GitHub search](https://github.com/langchain-ai/langgraph),
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Checked other resources
|
||||
description: Before submitting this issue, please confirm that you have completed all the steps below by checking each option. These steps help ensure your issue is well-defined, relevant, and actionable.
|
||||
options:
|
||||
- label: This is a bug, not a usage question. For questions, please use the LangChain Forum (https://forum.langchain.com/).
|
||||
- label: This is a bug, not a usage question. For questions, please use GitHub Discussions.
|
||||
required: true
|
||||
- label: I added a clear and detailed title that summarizes the issue.
|
||||
required: true
|
||||
@@ -38,7 +38,7 @@ body:
|
||||
attributes:
|
||||
label: Example Code
|
||||
description: |
|
||||
Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case. Replace this code with your own!
|
||||
Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case.
|
||||
placeholder: |
|
||||
from langgraph.graph import StateGraph
|
||||
|
||||
@@ -78,7 +78,7 @@ body:
|
||||
attributes:
|
||||
label: System Info
|
||||
description: |
|
||||
Run on your machine: `python -m langchain_core.sys_info`
|
||||
python -m langchain_core.sys_info
|
||||
placeholder: |
|
||||
python -m langchain_core.sys_info
|
||||
validations:
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
blank_issues_enabled: false
|
||||
blank_issues_enabled: true
|
||||
version: 2.1
|
||||
contact_links:
|
||||
- name: Documentation
|
||||
url: https://github.com/langchain-ai/docs/issues/new?template=langgraph.yml
|
||||
about: Report an issue related to the LangGraph documentation
|
||||
- name: LangChain Forum
|
||||
url: https://forum.langchain.com/
|
||||
about: General community discussions and support
|
||||
- name: 🤔 Question or Problem
|
||||
about: Ask a question or ask about a problem in GitHub Discussions.
|
||||
url: https://github.com/langchain-ai/langgraph/discussions/categories/q-a
|
||||
- name: Feature Request
|
||||
url: https://github.com/langchain-ai/langgraph/discussions/categories/ideas
|
||||
about: Suggest a feature or an idea
|
||||
- name: Show and tell
|
||||
about: Show what you built with LangChain
|
||||
url: https://github.com/langchain-ai/langgraph/discussions/categories/show-and-tell
|
||||
- name: Slack
|
||||
url: https://www.langchain.com/join-community
|
||||
about: General community discussions
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
name: Documentation
|
||||
description: Report an issue related to the LangGraph documentation.
|
||||
title: "DOC: <Please write a comprehensive title after the 'DOC: ' prefix>"
|
||||
labels: [documentation]
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Issue with current documentation:"
|
||||
description: >
|
||||
Please make sure to leave a reference to the document/code you're
|
||||
referring to.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Idea or request for content:"
|
||||
description: >
|
||||
Please describe as clearly as possible what topics you think are missing
|
||||
from the current documentation.
|
||||
@@ -1,29 +1,25 @@
|
||||
name: 🔒 Privileged
|
||||
description: You are a LangGraph maintainer, or was asked directly by a maintainer to create an issue here. If not, check the other options.
|
||||
description: You are a LangChain maintainer, or was asked directly by a maintainer to create an issue here. If not, check the other options.
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for your interest in LangGraph! 🚀
|
||||
|
||||
If you are not a LangGraph maintainer or were not asked directly by a maintainer to create an issue, then please start the conversation on the [LangChain Forum](https://forum.langchain.com/) instead.
|
||||
|
||||
You are a LangGraph maintainer if you maintain any of the packages inside of the LangGraph repository
|
||||
or are a regular contributor to LangGraph with previous merged merged pull requests.
|
||||
Thanks for your interest in LangChain! 🚀
|
||||
|
||||
If you are not a LangChain maintainer or were not asked directly by a maintainer to create an issue, then please start the conversation in a [Question in GitHub Discussions](https://github.com/langchain-ai/langchain/discussions/categories/q-a) instead.
|
||||
|
||||
You are a LangChain maintainer if you maintain any of the packages inside of the LangChain repository
|
||||
or are a regular contributor to LangChain with previous merged merged pull requests.
|
||||
- type: checkboxes
|
||||
id: privileged
|
||||
attributes:
|
||||
label: Privileged issue
|
||||
description: Confirm that you are allowed to create an issue here.
|
||||
options:
|
||||
- label: I am a LangGraph maintainer, or was asked directly by a LangGraph maintainer to create an issue here.
|
||||
- label: I am a LangChain maintainer, or was asked directly by a LangChain maintainer to create an issue here.
|
||||
required: true
|
||||
- type: textarea
|
||||
id: content
|
||||
attributes:
|
||||
label: Issue Content
|
||||
description: Add the content of the issue here.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Community members should **NOT** work on Privileged issues unless these issues have been explicitly marked with a "help-wanted" tag.
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
Thank you for contributing to LangGraph! Follow these steps to mark your pull request as ready for review. **If any of these steps are not completed, your PR will not be considered for review.**
|
||||
|
||||
- [ ] **PR title**: Follows the format: {TYPE}({SCOPE}): {DESCRIPTION}
|
||||
- Examples:
|
||||
- feat(core): add multi-tenant support
|
||||
- fix(cli): resolve flag parsing error
|
||||
- docs(openai): update API usage examples
|
||||
- Allowed `{TYPE}` values:
|
||||
- feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert, release
|
||||
- Allowed `{SCOPE}` values (optional):
|
||||
- langgraph, docs, cli, checkpoint, checkpoint-postgres, checkpoint-sqlite, prebuilt, scheduler-kafka, sdk-py
|
||||
- Once you've written the title, please delete this checklist item; do not include it in the PR.
|
||||
|
||||
- [ ] **PR message**: ***Delete this entire checklist*** and replace with
|
||||
- **Description:** a description of the change. Include a [closing keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) if applicable.
|
||||
- **Issue:** the issue # it fixes, if applicable
|
||||
- **Dependencies:** any dependencies required for this change
|
||||
- **Twitter handle:** if your PR gets announced, and you'd like a mention, we'll gladly shout you out!
|
||||
|
||||
- [ ] **Add tests and docs**: If you're adding a new integration, you must include:
|
||||
1. A test for the integration, preferably unit tests that do not rely on network access,
|
||||
2. An example notebook showing its use. It lives in `docs/docs/integrations` directory.
|
||||
|
||||
- [ ] **Lint and test**: Run `make format`, `make lint` and `make test` from the root of the package(s) you've modified. We will not consider a PR unless these three are passing in CI. See [contribution guidelines](https://github.com/langchain-ai/langgraph/blob/main/CONTRIBUTING.md) for more.
|
||||
|
||||
Additional guidelines:
|
||||
|
||||
- Make sure optional dependencies are imported within a function.
|
||||
- Please do not add dependencies to `pyproject.toml` files (even optional ones) unless they are **required** for unit tests.
|
||||
- Most PRs should not touch more than one package.
|
||||
- Changes should be backwards compatible.
|
||||
+5
-12
@@ -1,18 +1,11 @@
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
# and
|
||||
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "pip"
|
||||
directories:
|
||||
- "libs/checkpoint"
|
||||
- "libs/checkpoint-postgres"
|
||||
- "libs/checkpoint-sqlite"
|
||||
- "libs/cli"
|
||||
- "libs/langgraph"
|
||||
- "libs/prebuilt"
|
||||
- "libs/sdk-py"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import ast
|
||||
import os
|
||||
from itertools import filterfalse
|
||||
from typing import Dict, List, Tuple
|
||||
from typing import List, Tuple
|
||||
|
||||
ROOT_PATH = os.path.abspath(os.path.join(__file__, "..", "..", ".."))
|
||||
CLIENT_PATH = os.path.join(ROOT_PATH, "libs", "sdk-py", "langgraph_sdk", "client.py")
|
||||
ASYNC_TO_SYNC_METHOD_MAP: Dict[str, str] = {
|
||||
"aclose": "close",
|
||||
"__aenter__": "__enter__",
|
||||
"__aexit__": "__exit__",
|
||||
}
|
||||
|
||||
|
||||
def get_class_methods(node: ast.ClassDef) -> List[str]:
|
||||
@@ -27,7 +22,7 @@ def find_classes(tree: ast.AST) -> List[Tuple[str, List[str]]]:
|
||||
|
||||
def compare_sync_async_methods(sync_methods: List[str], async_methods: List[str]) -> List[str]:
|
||||
sync_set = set(sync_methods)
|
||||
async_set = {ASYNC_TO_SYNC_METHOD_MAP.get(async_method, async_method) for async_method in async_methods}
|
||||
async_set = set(async_methods)
|
||||
missing_in_sync = list(async_set - sync_set)
|
||||
missing_in_async = list(sync_set - async_set)
|
||||
return missing_in_sync + missing_in_async
|
||||
|
||||
@@ -1,164 +1,108 @@
|
||||
import logging
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import time
|
||||
from urllib import error, request
|
||||
|
||||
import langgraph_cli
|
||||
import langgraph_cli.config
|
||||
import langgraph_cli.docker
|
||||
from langgraph_cli.cli import prepare_args_and_stdin
|
||||
from langgraph_cli.constants import DEFAULT_PORT
|
||||
import langgraph_cli.config
|
||||
|
||||
from langgraph_cli.exec import Runner, subp_exec
|
||||
from langgraph_cli.progress import Progress
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
from langgraph_cli.constants import DEFAULT_PORT
|
||||
|
||||
|
||||
def test(config: pathlib.Path, port: int, tag: str, verbose: bool):
|
||||
"""Spin up API with Postgres/Redis via docker compose and wait until ready."""
|
||||
logger.info("Starting test...")
|
||||
def test(
|
||||
config: pathlib.Path,
|
||||
port: int,
|
||||
tag: str,
|
||||
verbose: bool,
|
||||
):
|
||||
with Runner() as runner, Progress(message="Pulling...") as set:
|
||||
# Detect docker/compose capabilities
|
||||
# check docker available
|
||||
capabilities = langgraph_cli.docker.check_capabilities(runner)
|
||||
|
||||
# Validate config and prepare compose stdin/args using built image
|
||||
# open config
|
||||
config_json = langgraph_cli.config.validate_config_file(config)
|
||||
args, stdin = prepare_args_and_stdin(
|
||||
capabilities=capabilities,
|
||||
config_path=config,
|
||||
config=config_json,
|
||||
docker_compose=None,
|
||||
port=port,
|
||||
watch=False,
|
||||
debugger_port=None,
|
||||
debugger_base_url=f"http://127.0.0.1:{port}",
|
||||
postgres_uri=None,
|
||||
api_version=None,
|
||||
image=tag,
|
||||
base_image=None,
|
||||
)
|
||||
|
||||
# Compose up with wait (implies detach), similar to `langgraph up --wait`
|
||||
args_up = [*args, "up", "--remove-orphans", "--wait"]
|
||||
|
||||
compose_cmd = ["docker", "compose"]
|
||||
if capabilities.compose_type == "standalone":
|
||||
compose_cmd = ["docker-compose"]
|
||||
|
||||
set("Starting...")
|
||||
try:
|
||||
runner.run(
|
||||
subp_exec(
|
||||
*compose_cmd,
|
||||
*args_up,
|
||||
input=stdin,
|
||||
verbose=verbose,
|
||||
)
|
||||
set("Running...")
|
||||
args = [
|
||||
"run",
|
||||
"--rm",
|
||||
"-p",
|
||||
f"{port}:8000",
|
||||
]
|
||||
if isinstance(config_json["env"], str):
|
||||
args.extend(
|
||||
[
|
||||
"--env-file",
|
||||
str(config.parent / config_json["env"]),
|
||||
]
|
||||
)
|
||||
except Exception as e: # noqa: BLE001
|
||||
# On failure, show diagnostics then ensure clean teardown
|
||||
sys.stderr.write(f"docker compose up failed: {e}\n")
|
||||
try:
|
||||
sys.stderr.write("\n== docker compose ps ==\n")
|
||||
runner.run(
|
||||
subp_exec(*compose_cmd, *args, "ps", input=stdin, verbose=False)
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
sys.stderr.write("\n== docker compose logs (api) ==\n")
|
||||
runner.run(
|
||||
subp_exec(
|
||||
*compose_cmd,
|
||||
*args,
|
||||
"logs",
|
||||
"langgraph-api",
|
||||
input=stdin,
|
||||
verbose=False,
|
||||
)
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
try:
|
||||
runner.run(
|
||||
subp_exec(
|
||||
*compose_cmd,
|
||||
*args,
|
||||
"down",
|
||||
"-v",
|
||||
"--remove-orphans",
|
||||
input=stdin,
|
||||
verbose=False,
|
||||
)
|
||||
)
|
||||
finally:
|
||||
raise
|
||||
|
||||
set("")
|
||||
base_url = f"http://localhost:{port}"
|
||||
ok_url = f"{base_url}/ok"
|
||||
logger.info(f"Waiting for {ok_url} to respond with 200...")
|
||||
deadline = time.time() + 30
|
||||
last_err: Exception | None = None
|
||||
while time.time() < deadline:
|
||||
try:
|
||||
with request.urlopen(ok_url, timeout=2) as resp:
|
||||
if resp.status == 200:
|
||||
sys.stdout.write(
|
||||
f"""Ready!\n- API: {base_url}\n- /ok: 200 OK\n"""
|
||||
)
|
||||
sys.stdout.flush()
|
||||
break
|
||||
else:
|
||||
last_err = RuntimeError(f"Unexpected status: {resp.status}")
|
||||
logger.error(f"Unexpected status: {resp.status}")
|
||||
except error.URLError as e:
|
||||
logger.error(f"URLError: {e}")
|
||||
last_err = e
|
||||
except Exception as e: # noqa: BLE001
|
||||
logger.error(f"Exception: {e}")
|
||||
last_err = e
|
||||
time.sleep(0.5)
|
||||
else:
|
||||
logger.error("Timeout waiting for /ok to return 200")
|
||||
# Bring stack down before raising
|
||||
args_down = [*args, "down", "-v", "--remove-orphans"]
|
||||
try:
|
||||
runner.run(
|
||||
subp_exec(
|
||||
*compose_cmd,
|
||||
*args_down,
|
||||
input=stdin,
|
||||
verbose=verbose,
|
||||
)
|
||||
)
|
||||
finally:
|
||||
raise SystemExit(
|
||||
f"/ok did not return 202 within timeout. Last error: {last_err}"
|
||||
for k, v in config_json["env"].items():
|
||||
args.extend(
|
||||
[
|
||||
"-e",
|
||||
f"{k}={v}",
|
||||
]
|
||||
)
|
||||
if capabilities.healthcheck_start_interval:
|
||||
args.extend(
|
||||
[
|
||||
"--health-interval",
|
||||
"5s",
|
||||
"--health-retries",
|
||||
"1",
|
||||
"--health-start-period",
|
||||
"10s",
|
||||
"--health-start-interval",
|
||||
"1s",
|
||||
]
|
||||
)
|
||||
else:
|
||||
args.extend(
|
||||
[
|
||||
"--health-interval",
|
||||
"5s",
|
||||
"--health-retries",
|
||||
"2",
|
||||
]
|
||||
)
|
||||
|
||||
_task = None
|
||||
|
||||
def on_stdout(line: str):
|
||||
nonlocal _task
|
||||
if "GET /ok" in line or "Uvicorn running on" in line:
|
||||
set("")
|
||||
sys.stdout.write(
|
||||
f"""Ready!
|
||||
- API: http://localhost:{port}
|
||||
"""
|
||||
)
|
||||
sys.stdout.flush()
|
||||
_task.cancel()
|
||||
return True
|
||||
return False
|
||||
|
||||
async def subp_exec_task(*args, **kwargs):
|
||||
nonlocal _task
|
||||
_task = asyncio.create_task(subp_exec(*args, **kwargs))
|
||||
await _task
|
||||
|
||||
# Clean up: bring compose stack down to free ports for next test
|
||||
logger.info("Test succeeded. Bringing down compose stack...")
|
||||
try:
|
||||
args_down = [*args, "down", "-v", "--remove-orphans"]
|
||||
runner.run(
|
||||
subp_exec(
|
||||
*compose_cmd,
|
||||
*args_down,
|
||||
input=stdin,
|
||||
subp_exec_task(
|
||||
"docker",
|
||||
*args,
|
||||
tag,
|
||||
verbose=verbose,
|
||||
on_stdout=on_stdout,
|
||||
)
|
||||
)
|
||||
logger.info("Compose stack down. Finishing...")
|
||||
except Exception:
|
||||
logger.exception("Failed to bring down compose stack")
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
logger.info("Test finished")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
@@ -166,12 +110,6 @@ if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-t", "--tag", type=str)
|
||||
parser.add_argument("-c", "--config", type=str, default="./langgraph.json")
|
||||
parser.add_argument("-p", "--port", type=int, default=DEFAULT_PORT)
|
||||
parser.add_argument("-p", "--port", default=DEFAULT_PORT)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
test(pathlib.Path(args.config), args.port, args.tag, verbose=True)
|
||||
except BaseException:
|
||||
logger.exception("Test failed")
|
||||
raise
|
||||
|
||||
logger.info("Test execution finished")
|
||||
test(pathlib.Path(args.config), args.port, args.tag, verbose=True)
|
||||
|
||||
@@ -3,9 +3,6 @@ name: CLI integration test
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -13,26 +10,13 @@ jobs:
|
||||
matrix:
|
||||
python-version:
|
||||
- "3.10"
|
||||
- "3.14"
|
||||
example:
|
||||
- name: A
|
||||
workdir: libs/cli/examples
|
||||
tag: langgraph-test-a
|
||||
- name: B
|
||||
workdir: libs/cli/examples/graphs
|
||||
tag: langgraph-test-b
|
||||
- name: C
|
||||
workdir: libs/cli/examples/graphs_reqs_a
|
||||
tag: langgraph-test-c
|
||||
- name: D
|
||||
workdir: libs/cli/examples/graphs_reqs_b
|
||||
tag: langgraph-test-d
|
||||
- "3.11"
|
||||
name: "CLI integration test"
|
||||
defaults:
|
||||
run:
|
||||
working-directory: libs/cli
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: Ana06/get-changed-files@v2.3.0
|
||||
@@ -40,79 +24,48 @@ jobs:
|
||||
filter: "libs/cli/**"
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
if: steps.changed-files.outputs.all
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
enable-cache: true
|
||||
cache-suffix: "cli-integration-test"
|
||||
ignore-nothing-to-cache: true
|
||||
- name: Setup env
|
||||
if: steps.changed-files.outputs.all
|
||||
working-directory: libs/cli/examples
|
||||
run: cat .env.example > .env
|
||||
- name: Install cli globally
|
||||
if: steps.changed-files.outputs.all
|
||||
run: pip install -e .
|
||||
- name: Build and test service ${{ matrix.example.name }}
|
||||
- name: Build and test service A
|
||||
if: steps.changed-files.outputs.all
|
||||
working-directory: ${{ matrix.example.workdir }}
|
||||
env:
|
||||
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
|
||||
working-directory: libs/cli/examples
|
||||
run: |
|
||||
# Build the image for this example
|
||||
langgraph build -t ${{ matrix.example.tag }}
|
||||
# Prepare environment file from local or parent example directory
|
||||
if [ -f .env.example ]; then cp .env.example .env; elif [ -f ../.env.example ]; then cp ../.env.example .env && cp ../.env.example ../.env; fi
|
||||
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; if [ -f ../.env ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> ../.env; fi; fi
|
||||
# Run the integration test using the built tag
|
||||
# Compute repo root to reference the shared script robustly
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
timeout 60 python "$REPO_ROOT/.github/scripts/run_langgraph_cli_test.py" -t ${{ matrix.example.tag }}
|
||||
# The build-arg isn't used; just testing that we accept other args
|
||||
langgraph build -t langgraph-test-a --base-image "langchain/langgraph-trial"
|
||||
cp .env.example .envg
|
||||
timeout 60 python ../../../.github/scripts/run_langgraph_cli_test.py -c langgraph.json -t langgraph-test-a
|
||||
- name: Build and test service B
|
||||
if: steps.changed-files.outputs.all
|
||||
working-directory: libs/cli/examples/graphs
|
||||
run: |
|
||||
langgraph build -t langgraph-test-b --base-image "langchain/langgraph-trial"
|
||||
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-b
|
||||
- name: Build and test service C
|
||||
if: steps.changed-files.outputs.all
|
||||
working-directory: libs/cli/examples/graphs_reqs_a
|
||||
run: |
|
||||
langgraph build -t langgraph-test-c --base-image "langchain/langgraph-trial"
|
||||
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-c
|
||||
- name: Build and test service D
|
||||
if: steps.changed-files.outputs.all
|
||||
working-directory: libs/cli/examples/graphs_reqs_b
|
||||
run: |
|
||||
langgraph build -t langgraph-test-d --base-image "langchain/langgraph-trial"
|
||||
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-d
|
||||
|
||||
- name: Build JS service
|
||||
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }}
|
||||
if: steps.changed-files.outputs.all
|
||||
working-directory: libs/cli/js-examples
|
||||
run: |
|
||||
langgraph build -t langgraph-test-e
|
||||
|
||||
- name: Build JS monorepo service
|
||||
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }}
|
||||
working-directory: libs/cli/js-monorepo-example
|
||||
run: |
|
||||
langgraph build -t langgraph-test-f -c apps/agent/langgraph.json --build-command "yarn run turbo build" --install-command "yarn install"
|
||||
|
||||
- name: Build Python monorepo service
|
||||
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }}
|
||||
working-directory: libs/cli/python-monorepo-example
|
||||
run: |
|
||||
langgraph build -t langgraph-test-g -c apps/agent/langgraph.json
|
||||
cp apps/agent/.env.example apps/agent/.env
|
||||
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> apps/agent/.env; fi
|
||||
timeout 60 python ../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-g -c apps/agent/langgraph.json
|
||||
|
||||
- name: Build and test prerelease reqs service
|
||||
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }}
|
||||
working-directory: libs/cli/examples/graph_prerelease_reqs
|
||||
run: |
|
||||
langgraph build -t langgraph-test-h
|
||||
cp ../.env.example .env
|
||||
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; fi
|
||||
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-h
|
||||
echo "Finished starting up langgraph-test-h"
|
||||
LANGGRAPH_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langgraph'); print(v);")
|
||||
if [ "$LANGGRAPH_VERSION" != "1.0.2" ]; then
|
||||
echo "LANGGRAPH_VERSION != 1.0.2; $LANGGRAPH_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
LANGCHAIN_OPENAI_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langchain-openai'); print(v);")
|
||||
if [ "$LANGCHAIN_OPENAI_VERSION" != "1.0.1" ]; then
|
||||
echo "LANGCHAIN_OPENAI_VERSION != 1.0.1; $LANGCHAIN_OPENAI_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
LANGCHAIN_ANTHROPIC_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langchain-anthropic'); print(v);")
|
||||
if [ "$LANGCHAIN_ANTHROPIC_VERSION" != "1.0.0a5" ]; then
|
||||
echo "LANGCHAIN_ANTHROPIC_VERSION != 1.0.0a5; $LANGCHAIN_ANTHROPIC_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Build and test prerelease reqs fail service
|
||||
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }}
|
||||
working-directory: libs/cli/examples/graph_prerelease_reqs_fail
|
||||
run: |
|
||||
langgraph build -t langgraph-test-i || [ $? -eq 1 ]
|
||||
|
||||
@@ -8,9 +8,6 @@ on:
|
||||
type: string
|
||||
description: "From which folder this pipeline executes"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# This env var allows us to get inline annotations when ruff has complaints.
|
||||
RUFF_OUTPUT_FORMAT: github
|
||||
@@ -31,7 +28,7 @@ jobs:
|
||||
- "3.12"
|
||||
name: "lint #${{ matrix.python-version }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: Ana06/get-changed-files@v2.3.0
|
||||
@@ -39,7 +36,7 @@ jobs:
|
||||
filter: "${{ inputs.working-directory }}/**"
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
if: steps.changed-files.outputs.all
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
enable-cache: true
|
||||
@@ -48,7 +45,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
if: steps.changed-files.outputs.all
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: uv sync --frozen --group lint
|
||||
run: uv sync --frozen --group dev
|
||||
|
||||
- name: Get .mypy_cache to speed up mypy
|
||||
if: steps.changed-files.outputs.all
|
||||
@@ -74,7 +71,7 @@ jobs:
|
||||
- name: Install test dependencies
|
||||
if: steps.changed-files.outputs.all
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: uv sync --group lint
|
||||
run: uv sync --group dev
|
||||
|
||||
- name: Get .mypy_cache_test to speed up mypy
|
||||
if: steps.changed-files.outputs.all
|
||||
|
||||
@@ -8,26 +8,23 @@ on:
|
||||
type: string
|
||||
description: "From which folder this pipeline executes"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version:
|
||||
- "3.9"
|
||||
- "3.10"
|
||||
- "3.11"
|
||||
- "3.12"
|
||||
- "3.13"
|
||||
- "3.14"
|
||||
|
||||
name: "test #${{ matrix.python-version }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
enable-cache: true
|
||||
@@ -42,7 +39,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: uv sync --frozen --group test --no-dev
|
||||
run: uv sync --frozen --group dev
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
|
||||
@@ -3,29 +3,26 @@ name: test
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version:
|
||||
- "3.9"
|
||||
- "3.10"
|
||||
- "3.11"
|
||||
- "3.12"
|
||||
- "3.13"
|
||||
- "3.14"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: libs/langgraph
|
||||
name: "test #${{ matrix.python-version }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
enable-cache: true
|
||||
@@ -39,7 +36,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: uv sync --frozen --group test --no-dev
|
||||
run: uv sync --frozen --group dev
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
|
||||
@@ -11,11 +11,9 @@ on:
|
||||
env:
|
||||
PYTHON_VERSION: "3.10"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
@@ -23,10 +21,10 @@ jobs:
|
||||
version: ${{ steps.check-version.outputs.version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python $${ env.PYTHON_VERSION }}
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
enable-cache: true
|
||||
@@ -48,7 +46,7 @@ jobs:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-dist
|
||||
path: ${{ inputs.working-directory }}/dist/
|
||||
@@ -74,9 +72,9 @@ jobs:
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: test-dist
|
||||
path: ${{ inputs.working-directory }}/dist/
|
||||
|
||||
@@ -7,9 +7,6 @@ on:
|
||||
paths:
|
||||
- "libs/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
benchmark:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -17,16 +14,16 @@ jobs:
|
||||
run:
|
||||
working-directory: libs/langgraph
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- run: SHA=$(git rev-parse HEAD) && echo "SHA=$SHA" >> $GITHUB_ENV
|
||||
- name: Set up Python 3.11
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: "3.11"
|
||||
enable-cache: true
|
||||
cache-suffix: "bench"
|
||||
- name: Install dependencies
|
||||
run: uv sync --group test
|
||||
run: uv sync --group dev
|
||||
- name: Run benchmarks
|
||||
run: OUTPUT=out/benchmark-baseline.json make -s benchmark
|
||||
- name: Save outputs
|
||||
|
||||
@@ -5,9 +5,6 @@ on:
|
||||
paths:
|
||||
- "libs/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
benchmark:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -15,20 +12,20 @@ jobs:
|
||||
run:
|
||||
working-directory: libs/langgraph
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- id: files
|
||||
name: Get changed files
|
||||
uses: Ana06/get-changed-files@v2.3.0
|
||||
with:
|
||||
format: json
|
||||
- name: Set up Python 3.11
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: "3.11"
|
||||
enable-cache: true
|
||||
cache-suffix: "bench"
|
||||
- name: Install dependencies
|
||||
run: uv sync --group test
|
||||
run: uv sync --group dev
|
||||
- name: Download baseline
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
@@ -57,7 +54,7 @@ jobs:
|
||||
echo EOF
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
- name: Annotation
|
||||
uses: actions/github-script@v8
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const file = JSON.parse(`${{ steps.files.outputs.added_modified_renamed }}`)[0]
|
||||
|
||||
+65
-19
@@ -3,13 +3,9 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
branches: [main]
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# If another push to the same PR or branch happens while this workflow is still running,
|
||||
# cancel the earlier run in favor of the next run.
|
||||
#
|
||||
@@ -25,9 +21,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
python: ${{ steps.filter.outputs.python }}
|
||||
deps: ${{ steps.filter.outputs.deps }}
|
||||
sdk-js: ${{ steps.filter.outputs.sdk-js }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: filter
|
||||
with:
|
||||
@@ -40,9 +36,8 @@ jobs:
|
||||
- 'libs/checkpoint-sqlite/**'
|
||||
- 'libs/checkpoint-postgres/**'
|
||||
- 'libs/prebuilt/**'
|
||||
deps:
|
||||
- '**/pyproject.toml'
|
||||
- '**/uv.lock'
|
||||
sdk-js:
|
||||
- 'libs/sdk-js/**'
|
||||
|
||||
lint:
|
||||
needs: changes
|
||||
@@ -60,7 +55,7 @@ jobs:
|
||||
|
||||
"libs/prebuilt",
|
||||
]
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.deps == 'true'
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
uses: ./.github/workflows/_lint.yml
|
||||
with:
|
||||
working-directory: ${{ matrix.working-directory }}
|
||||
@@ -78,9 +73,8 @@ jobs:
|
||||
"libs/checkpoint-sqlite",
|
||||
"libs/checkpoint-postgres",
|
||||
"libs/prebuilt",
|
||||
"libs/sdk-py",
|
||||
]
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.deps == 'true'
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
uses: ./.github/workflows/_test.yml
|
||||
with:
|
||||
working-directory: ${{ matrix.working-directory }}
|
||||
@@ -89,7 +83,7 @@ jobs:
|
||||
# NOTE: we're testing langgraph separately because it requires a different matrix
|
||||
test-langgraph:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.deps == 'true'
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
name: "cd libs/langgraph"
|
||||
uses: ./.github/workflows/_test_langgraph.yml
|
||||
secrets: inherit
|
||||
@@ -100,9 +94,9 @@ jobs:
|
||||
name: "Check SDK methods matching"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- name: Run check_sdk_methods script
|
||||
@@ -118,9 +112,9 @@ jobs:
|
||||
python-version:
|
||||
- "3.11"
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: "3.11"
|
||||
enable-cache: true
|
||||
@@ -146,21 +140,73 @@ jobs:
|
||||
|
||||
integration-test:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.deps == 'true'
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
name: CLI integration test
|
||||
uses: ./.github/workflows/_integration_test.yml
|
||||
secrets: inherit
|
||||
|
||||
lint-js:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.sdk-js == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
working-directory:
|
||||
- "libs/sdk-js"
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ matrix.working-directory }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Node.js (LTS)
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: "yarn"
|
||||
cache-dependency-path: ${{ matrix.working-directory }}/yarn.lock
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
- name: Run lint
|
||||
run: yarn lint
|
||||
- name: Build
|
||||
run: yarn build
|
||||
|
||||
test-js:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.sdk-js == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
working-directory:
|
||||
- "libs/sdk-js"
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ matrix.working-directory }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Node.js (LTS)
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: "yarn"
|
||||
cache-dependency-path: ${{ matrix.working-directory }}/yarn.lock
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
- name: Run tests
|
||||
run: yarn test
|
||||
|
||||
ci_success:
|
||||
name: "CI Success"
|
||||
needs:
|
||||
[
|
||||
lint,
|
||||
lint-js,
|
||||
test,
|
||||
test-langgraph,
|
||||
check-sdk-methods,
|
||||
check-schema,
|
||||
integration-test,
|
||||
test-js,
|
||||
]
|
||||
if: |
|
||||
always()
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
LangChain
|
||||
LangGraph
|
||||
LangSmith
|
||||
thead
|
||||
stdio
|
||||
nd
|
||||
jupyter
|
||||
lets
|
||||
lite
|
||||
uis
|
||||
deque
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
@@ -34,16 +34,10 @@
|
||||
id: extract_ignore_words
|
||||
|
||||
- name: Codespell
|
||||
uses: codespell-project/actions-codespell@v2.1
|
||||
uses: codespell-project/actions-codespell@v2
|
||||
with:
|
||||
skip: '*.ambr,*.lock,*.ipynb,*.yaml,*.zlib,*.css.map,*.js.map'
|
||||
skip: '*.ambr,*.lock,*.ipynb,*.yaml,*.zlib,*.md'
|
||||
ignore_words_list: ${{ steps.extract_ignore_words.outputs.ignore_words_list }}
|
||||
# We do this to avoid spellchecking cell outputs
|
||||
- name: Codespell Notebooks
|
||||
run: make codespell
|
||||
|
||||
- name: Codespell LangGraph Library
|
||||
run: |
|
||||
# Change to root directory to check the main LangGraph library
|
||||
cd ..
|
||||
codespell --skip="*.ambr,*.lock,*.ipynb,*.yaml,*.zlib,*.css.map,*.js.map,*.pyc,__pycache__/*" --ignore-words-list="${{ steps.extract_ignore_words.outputs.ignore_words_list }}" libs/langgraph/langgraph/
|
||||
run: make codespell
|
||||
@@ -1,9 +1,12 @@
|
||||
name: Deploy Docs Redirects
|
||||
name: Deploy Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -20,18 +23,39 @@ defaults:
|
||||
working-directory: docs
|
||||
|
||||
jobs:
|
||||
get-changed-files:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
changed-files: ${{ steps.changed-files.outputs.added_modified }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: Ana06/get-changed-files@v2.3.0
|
||||
with:
|
||||
filter: "docs/docs/**"
|
||||
|
||||
# TODO: Uncomment this to run on PRs
|
||||
# run-changed-notebooks:
|
||||
# needs: get-changed-files
|
||||
# uses: ./.github/workflows/run_notebooks.yml
|
||||
# secrets: inherit
|
||||
# with:
|
||||
# changed-files: ${{ needs.get-changed-files.outputs.changed-files }}
|
||||
|
||||
deploy:
|
||||
# needs: run-changed-notebooks
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10 # Job will be cancelled if it runs for more than 10 minutes
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.MKDOCS_GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: "3.12"
|
||||
enable-cache: true
|
||||
@@ -47,22 +71,85 @@ jobs:
|
||||
uv run pip install "git+https://${GITHUB_TOKEN}@github.com/langchain-ai/mkdocs-material-insiders.git"
|
||||
fi
|
||||
|
||||
- name: Run unit tests
|
||||
# Run unit tests on the docs build pipeline
|
||||
run: make tests
|
||||
- name: Lint Docs
|
||||
# This step lints the docs using the existing linting set up.
|
||||
# It should be very fast and should not require any external services.
|
||||
run: make lint-docs
|
||||
- name: Build llms-text
|
||||
run: make llms-text
|
||||
|
||||
- name: Build site (redirects only)
|
||||
run: make build-docs
|
||||
- name: Build site
|
||||
run: |
|
||||
# If this is main branch, then we want to download stats. we do this
|
||||
# with the env variable DOWNLOAD_STATS=true
|
||||
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
||||
DOWNLOAD_STATS=true make build-docs
|
||||
else
|
||||
make build-docs
|
||||
fi
|
||||
env:
|
||||
MKDOCS_GIT_COMMITTERS_APIKEY: ${{ secrets.MKDOCS_GIT_COMMITTERS_APIKEY }}
|
||||
OPENAI_API_KEY: sf-proj-1234567890 # fake placeholder, shouldn't actually be used
|
||||
ANTHROPIC_API_KEY: sk-ant-api03-1234567890 # fake placeholder, shouldn't actually be used
|
||||
- name: Check links in notebooks
|
||||
env:
|
||||
LANGCHAIN_API_KEY: test
|
||||
if: github.event_name == 'schedule'
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" == "schedule" ]; then
|
||||
echo "Running link check on all HTML files matching notebooks in docs directory..."
|
||||
uv run pytest -v \
|
||||
--check-links-ignore "https://(api|web|docs)\.smith\.langchain\.com/.*" \
|
||||
--check-links-ignore "https://academy\.langchain\.com/.*" \
|
||||
--check-links-ignore "https://x.com/.*" \
|
||||
--check-links-ignore "https://twitter.com/.*" \
|
||||
--check-links-ignore "https://github\.com/.*" \
|
||||
--check-links-ignore "http://localhost:8123/.*" \
|
||||
--check-links-ignore "http://localhost:2024.*" \
|
||||
--check-links-ignore "http://127.0.0.1:.*" \
|
||||
--check-links-ignore "/.*\.(ipynb|html)$" \
|
||||
--check-links-ignore "https://python\.langchain\.com/.*" \
|
||||
--check-links-ignore "https://openai\.com/.*" \
|
||||
--check-links-ignore "https://www\.uber\.com/.*" \
|
||||
--check-links-ignore "https://pepy\.tech/.*" \
|
||||
--check-links-ignore "docs/docs/static/wordmark_*" \
|
||||
--check-links $(find site -name "index.html" | grep -v 'storm/index.html')
|
||||
|
||||
else
|
||||
echo "Fetching changes from origin/main..."
|
||||
git fetch origin main
|
||||
echo "Checking for changed notebook files..."
|
||||
CHANGED_FILES=$(git diff --name-only --diff-filter=d origin/main | grep 'docs/docs/.*\.ipynb$' | grep -v 'storm.ipynb' | sed -E 's|^docs/docs/|site/|; s/\.ipynb$/\/index.html/' || true)
|
||||
echo "Changed files: ${CHANGED_FILES}"
|
||||
if [ -n "${CHANGED_FILES}" ]; then
|
||||
echo "Running link check on HTML files matching changed notebook files..."
|
||||
uv run pytest -v \
|
||||
--check-links-ignore "https://(api|web|docs)\.smith\.langchain\.com/.*" \
|
||||
--check-links-ignore "https://academy\.langchain\.com/.*" \
|
||||
--check-links-ignore "http://localhost:8123/.*" \
|
||||
--check-links-ignore "http://localhost:2024.*" \
|
||||
--check-links-ignore "http://127.0.0.1:.*" \
|
||||
--check-links-ignore "https://x.com/.*" \
|
||||
--check-links-ignore "https://twitter.com/.*" \
|
||||
--check-links-ignore "https://github\.com/.*" \
|
||||
--check-links-ignore "/.*\.(ipynb|html)$" \
|
||||
--check-links-ignore "docs/docs/static/wordmark_*" \
|
||||
--check-links ${CHANGED_FILES} \
|
||||
|| ([ $? = 5 ] && exit 0 || exit $?)
|
||||
else
|
||||
echo "No notebook files changed."
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Configure GitHub Pages
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: actions/configure-pages@v5
|
||||
|
||||
- name: Upload Pages Artifact
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: actions/upload-pages-artifact@v4
|
||||
# if: github.ref == 'refs/heads/main'
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: ./docs/site/
|
||||
|
||||
|
||||
@@ -11,15 +11,12 @@ on:
|
||||
- cron: "0 5 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
markdown-link-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -36,7 +33,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
name: PR Title Lint
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, synchronize]
|
||||
|
||||
jobs:
|
||||
lint-pr-title:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Validate PR Title
|
||||
uses: amannn/action-semantic-pull-request@v6
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
types: |
|
||||
feat
|
||||
fix
|
||||
docs
|
||||
style
|
||||
refactor
|
||||
perf
|
||||
test
|
||||
build
|
||||
ci
|
||||
chore
|
||||
revert
|
||||
release
|
||||
scopes: |
|
||||
checkpoint
|
||||
checkpoint-postgres
|
||||
checkpoint-sqlite
|
||||
cli
|
||||
langgraph
|
||||
prebuilt
|
||||
scheduler-kafka
|
||||
sdk-py
|
||||
docs
|
||||
ci
|
||||
deps
|
||||
requireScope: false
|
||||
ignoreLabels: |
|
||||
ignore-lint-pr-title
|
||||
@@ -8,14 +8,12 @@ on:
|
||||
type: string
|
||||
default: "libs/langgraph"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
PYTHON_VERSION: "3.11"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
@@ -25,10 +23,10 @@ jobs:
|
||||
tag: ${{ steps.check-version.outputs.tag }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
enable-cache: true
|
||||
@@ -50,7 +48,7 @@ jobs:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: dist
|
||||
path: ${{ inputs.working-directory }}/dist/
|
||||
@@ -61,13 +59,7 @@ jobs:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: |
|
||||
PKG_NAME=$(grep -m 1 "^name = " pyproject.toml | cut -d '"' -f 2)
|
||||
if grep -q 'dynamic.*=.*\[.*"version".*\]' pyproject.toml; then
|
||||
# handle dynamic versioning
|
||||
DIR_NAME=$(echo "$PKG_NAME" | tr '-' '_')
|
||||
VERSION=$(grep -m 1 '^__version__' "${DIR_NAME}/__init__.py" | cut -d '"' -f 2)
|
||||
else
|
||||
VERSION=$(grep -m 1 "^version = " pyproject.toml | cut -d '"' -f 2)
|
||||
fi
|
||||
VERSION=$(grep -m 1 "^version = " pyproject.toml | cut -d '"' -f 2)
|
||||
SHORT_PKG_NAME="$(echo "$PKG_NAME" | sed -e 's/langgraph//g' -e 's/-//g')"
|
||||
if [ -z $SHORT_PKG_NAME ]; then
|
||||
TAG="$VERSION"
|
||||
@@ -86,7 +78,7 @@ jobs:
|
||||
outputs:
|
||||
release-body: ${{ steps.generate-release-body.outputs.release-body }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: langchain-ai/langgraph
|
||||
path: langgraph
|
||||
@@ -142,9 +134,7 @@ jobs:
|
||||
needs:
|
||||
- build
|
||||
- release-notes
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
permissions: write-all
|
||||
uses: ./.github/workflows/_test_release.yml
|
||||
with:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
@@ -157,7 +147,7 @@ jobs:
|
||||
- test-pypi-publish
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# We explicitly *don't* set up caching here. This ensures our tests are
|
||||
# maximally sensitive to catching breakage.
|
||||
@@ -173,7 +163,7 @@ jobs:
|
||||
# used in the real world.
|
||||
|
||||
- name: Set up Python
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
enable-cache: true
|
||||
@@ -221,7 +211,7 @@ jobs:
|
||||
uv run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))"
|
||||
|
||||
- name: Import test dependencies
|
||||
run: uv sync --group test
|
||||
run: uv sync --group dev
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
# Overwrite the local version of the package with the test PyPI version.
|
||||
@@ -260,16 +250,16 @@ jobs:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
enable-cache: true
|
||||
cache-suffix: "release"
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: dist
|
||||
path: ${{ inputs.working-directory }}/dist/
|
||||
@@ -301,16 +291,16 @@ jobs:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
enable-cache: true
|
||||
cache-suffix: "release"
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: dist
|
||||
path: ${{ inputs.working-directory }}/dist/
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
name: JS Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
# Disallow publishing from branches that aren't `main`.
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
working-directory:
|
||||
- "libs/sdk-js"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ matrix.working-directory }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# JS Build
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: "yarn"
|
||||
cache-dependency-path: ${{ matrix.working-directory }}/yarn.lock
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
- name: Build
|
||||
run: yarn build
|
||||
- name: Publish package to NPM
|
||||
run: |
|
||||
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc
|
||||
npm publish
|
||||
@@ -11,9 +11,6 @@ on:
|
||||
schedule:
|
||||
- cron: "0 13 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: docs
|
||||
@@ -28,9 +25,9 @@ jobs:
|
||||
- "latest"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python + Poetry
|
||||
uses: astral-sh/setup-uv@v7
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: "3.11"
|
||||
enable-cache: true
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
name: UV Lock Upgrade
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# run at midnight every Sunday
|
||||
- cron: '0 0 * * 0'
|
||||
# allow manual triggering
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
upgrade-dependencies:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@v7
|
||||
with:
|
||||
# use minimum supported Python version
|
||||
python-version: "3.10"
|
||||
enable-cache: true
|
||||
cache-suffix: "uv-lock-upgrade"
|
||||
|
||||
- name: Run uv lock --upgrade in all Python packages
|
||||
run: make lock-upgrade
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: "chore(deps): upgrade dependencies with `uv lock --upgrade`"
|
||||
title: "chore(deps): upgrade dependencies with `uv lock --upgrade`"
|
||||
body: |
|
||||
This PR updates the dependencies in all Python packages using `uv lock --upgrade`.
|
||||
|
||||
This is an automated PR created by the UV Lock Upgrade workflow.
|
||||
branch: deps/uv-lock-upgrade
|
||||
delete-branch: true
|
||||
labels: |
|
||||
dependencies
|
||||
@@ -28,7 +28,7 @@ Below is a high-level overview:
|
||||
- **langgraph** – core framework for building stateful, multi-actor agents.
|
||||
- **prebuilt** – high-level APIs for creating and running agents and tools.
|
||||
- **sdk-js** – JS/TS SDK for interacting with the LangGraph REST API.
|
||||
- **sdk-py** – Python SDK for the LangGraph Server API.
|
||||
- **sdk-py** – Python SDK for the LangGraph Platform API.
|
||||
|
||||
### Dependency map
|
||||
|
||||
|
||||
+13
-12
@@ -9,7 +9,7 @@ Here are some things to keep in mind for all types of contributions:
|
||||
- Follow the ["fork and pull request"](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project) workflow.
|
||||
- Fill out the checked-in pull request template when opening pull requests. Note related issues and tag relevant maintainers.
|
||||
- Ensure your PR passes formatting, linting, and testing checks before requesting a review.
|
||||
- If you would like comments or feedback, please tag a maintainer.
|
||||
- If you would like comments or feedback, please open an issue or discussion and tag a maintainer.
|
||||
- Backwards compatibility is key. Your changes must not be breaking, except in case of critical bug and security fixes.
|
||||
- Look for duplicate PRs or issues that have already been opened before opening a new one.
|
||||
- Keep scope as isolated as possible. As a general rule, your changes should not affect more than one package at a time.
|
||||
@@ -20,7 +20,7 @@ For bug fixes, please open up an issue before proposing a fix to ensure the prop
|
||||
|
||||
### New features
|
||||
|
||||
For new features, please start a new [discussion](https://forum.langchain.com/), where the maintainers will help with scoping out the necessary changes.
|
||||
For new features, please start a new [discussion](https://github.com/langchain-ai/langgraph/discussions), where the maintainers will help with scoping out the necessary changes.
|
||||
|
||||
## Contribute Documentation
|
||||
|
||||
@@ -60,7 +60,7 @@ In LangGraph, these are often higher level guides that show off end-to-end use c
|
||||
Some examples include:
|
||||
|
||||
- [Build a Customer Support Bot](https://langchain-ai.github.io/langgraph/tutorials/customer-support/customer-support/)
|
||||
- [Build a SQL Agent](https://langchain-ai.github.io/langgraph/tutorials/sql/sql-agent/)
|
||||
- [Build a SQL Agent](https://langchain-ai.github.io/langgraph/tutorials/sql-agent/)
|
||||
|
||||
Here are some high-level tips on writing a good tutorial:
|
||||
|
||||
@@ -111,6 +111,7 @@ in a more abstract way than how-to guides or tutorials, and should be geared tow
|
||||
gaining a deeper understanding of the framework. Try to avoid excessively large code examples. The goal here is to
|
||||
impart perspective to the user rather than to finish a practical project. These guides should cover **why** things work the way they do.
|
||||
|
||||
|
||||
To quote the Diataxis website:
|
||||
|
||||
> The perspective of explanation is higher and wider than that of the other types. It does not take the user’s eye-level view, as in a how-to guide, or a close-up view of the machinery, like reference material. Its scope in each case is a topic - “an area of knowledge”, that somehow has to be bounded in a reasonable, meaningful way.
|
||||
@@ -186,9 +187,9 @@ Be concise, including in code samples.
|
||||
|
||||
## Setup
|
||||
|
||||
LangGraph documentation consists of two components:
|
||||
LangChain documentation consists of two components:
|
||||
|
||||
1. Main Documentation: Hosted at [https://langchain-ai.github.io/langgraph/](https://langchain-ai.github.io/langgraph/),
|
||||
1. Main Documentation: Hosted at [https://langchain-ai.github.io](https://langchain-ai.github.io/langgraph/),
|
||||
this comprehensive resource serves as the primary user-facing documentation.
|
||||
It covers a wide array of topics, including tutorials, use cases, integrations,
|
||||
and more, offering extensive guidance on building with LangGraph.
|
||||
@@ -249,17 +250,17 @@ make serve-docs
|
||||
|
||||
#### Linting
|
||||
|
||||
To spell check the docs, run the following from the `docs` directory:
|
||||
The documentation is linted from the **monorepo root**. To lint it, run the following from there:
|
||||
|
||||
```bash
|
||||
codespell --skip="*.ambr,*.lock,*.ipynb,*.yaml,*.zlib,*.css.map,*.js.map" --ignore-words-list="infor,thead,stdio,nd,jupyter,lets,lite,uis,deque" .
|
||||
make spellcheck
|
||||
```
|
||||
|
||||
### ️In-code Documentation
|
||||
|
||||
The in-code documentation is autogenerated from docstrings.
|
||||
|
||||
For the API reference to be useful, the codebase must be well-documented. This means that all functions, classes, and methods should have a docstring that explains what they do, what the arguments are, and what the return value is. This is a good practice in general, but it is especially important for LangGraph because the API reference is the primary resource for developers to understand how to use the codebase.
|
||||
For the API reference to be useful, the codebase must be well-documented. This means that all functions, classes, and methods should have a docstring that explains what they do, what the arguments are, and what the return value is. This is a good practice in general, but it is especially important for LangChain because the API reference is the primary resource for developers to understand how to use the codebase.
|
||||
|
||||
We generally follow the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings) for docstrings.
|
||||
|
||||
@@ -277,9 +278,9 @@ def my_function(arg1: int, arg2: str) -> float:
|
||||
Examples:
|
||||
This is a section for examples of how to use the function.
|
||||
|
||||
```python
|
||||
my_function(1, "hello")
|
||||
\```
|
||||
.. code-block:: python
|
||||
|
||||
my_function(1, "hello")
|
||||
|
||||
Args:
|
||||
arg1: This is a description of arg1. We do not need to specify the type since
|
||||
@@ -290,4 +291,4 @@ def my_function(arg1: int, arg2: str) -> float:
|
||||
This is a description of the return value.
|
||||
"""
|
||||
return 3.14
|
||||
```
|
||||
```
|
||||
@@ -47,16 +47,6 @@ lock:
|
||||
fi; \
|
||||
done
|
||||
|
||||
# Lock all projects and upgrade dependencies
|
||||
.PHONY: lock-upgrade
|
||||
lock-upgrade:
|
||||
@for dir in $(LIBS_DIRS); do \
|
||||
if [ -f $$dir/Makefile ]; then \
|
||||
echo "Running lock-upgrade in $$dir"; \
|
||||
(cd $$dir && uv lock --upgrade); \
|
||||
fi; \
|
||||
done
|
||||
|
||||
# Test all projects
|
||||
.PHONY: test
|
||||
test:
|
||||
|
||||
@@ -63,18 +63,17 @@ LangGraph provides low-level supporting infrastructure for *any* long-running, s
|
||||
While LangGraph can be used standalone, it also integrates seamlessly with any LangChain product, giving developers a full suite of tools for building agents. To improve your LLM application development, pair LangGraph with:
|
||||
|
||||
- [LangSmith](http://www.langchain.com/langsmith) — Helpful for agent evals and observability. Debug poor-performing LLM app runs, evaluate agent trajectories, gain visibility in production, and improve performance over time.
|
||||
- [LangSmith Deployment](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/) — Deploy and scale agents effortlessly with a purpose-built deployment platform for long running, stateful workflows. Discover, reuse, configure, and share agents across teams — and iterate quickly with visual prototyping in [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/).
|
||||
- [LangChain](https://docs.langchain.com/oss/python/langchain/overview) – Provides integrations and composable components to streamline LLM application development.
|
||||
- [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/#langgraph-platform) — Deploy and scale agents effortlessly with a purpose-built deployment platform for long running, stateful workflows. Discover, reuse, configure, and share agents across teams — and iterate quickly with visual prototyping in [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/).
|
||||
- [LangChain](https://python.langchain.com/docs/introduction/) – Provides integrations and composable components to streamline LLM application development.
|
||||
|
||||
> [!NOTE]
|
||||
> Looking for the JS version of LangGraph? See the [JS repo](https://github.com/langchain-ai/langgraphjs) and the [JS docs](https://langchain-ai.github.io/langgraphjs/).
|
||||
|
||||
## Additional resources
|
||||
|
||||
- [Guides](https://langchain-ai.github.io/langgraph/guides/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.).
|
||||
- [Guides](https://langchain-ai.github.io/langgraph/how-tos/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.).
|
||||
- [Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Detailed reference on core classes, methods, how to use the graph and checkpointing APIs, and higher-level prebuilt components.
|
||||
- [Examples](https://langchain-ai.github.io/langgraph/examples/): Guided examples on getting started with LangGraph.
|
||||
- [LangChain Forum](https://forum.langchain.com/): Connect with the community and share all of your technical questions, ideas, and feedback.
|
||||
- [Examples](https://langchain-ai.github.io/langgraph/tutorials/overview/): Guided examples on getting started with LangGraph.
|
||||
- [LangChain Academy](https://academy.langchain.com/courses/intro-to-langgraph): Learn the basics of LangGraph in our free, structured course.
|
||||
- [Templates](https://langchain-ai.github.io/langgraph/concepts/template_applications/): Pre-built reference apps for common agentic workflows (e.g. ReAct agent, memory, retrieval etc.) that can be cloned and adapted.
|
||||
- [Case studies](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship AI applications at scale.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
site/
|
||||
docs/cloud/reference/sdk/js_ts_sdk_ref.md
|
||||
|
||||
.vercel
|
||||
|
||||
+9
-6
@@ -1,4 +1,10 @@
|
||||
.PHONY: lint-docs format-docs build-docs serve-docs serve-clean-docs clean-docs codespell llms-text build-prebuilt tests
|
||||
.PHONY: lint-docs format-docs build-docs serve-docs serve-clean-docs clean-docs codespell build-typedoc llms-text build-prebuilt tests
|
||||
|
||||
build-typedoc:
|
||||
cd ../libs/sdk-js && yarn install --include-dev && yarn typedoc
|
||||
cd ../libs/sdk-js && yarn --silent concat-md --decrease-title-levels --ignore=js_ts_sdk_ref.md --start-title-level-at 2 docs > ../../docs/docs/cloud/reference/sdk/js_ts_sdk_ref.md 2>/dev/null
|
||||
# Add links to the monorepo
|
||||
sed -e '1,10s|@langchain/langgraph-sdk|[@langchain/langgraph-sdk](https://github.com/langchain-ai/langgraph/tree/main/libs/sdk-js)|g' docs/cloud/reference/sdk/js_ts_sdk_ref.md > temp_file && mv temp_file docs/cloud/reference/sdk/js_ts_sdk_ref.md
|
||||
|
||||
build-prebuilt:
|
||||
# Use to create an update to date prebuilt page.
|
||||
@@ -15,10 +21,7 @@ build-prebuilt:
|
||||
fi
|
||||
uv run python -m _scripts.third_party_page.create_third_party_page stats.yml docs/agents/prebuilt.md
|
||||
|
||||
build-docs: build-prebuilt
|
||||
TARGET_LANGUAGE=python uv run python -m mkdocs build --clean -f mkdocs.yml --strict
|
||||
|
||||
build-docs-js: build-prebuilt
|
||||
build-docs: build-typedoc build-prebuilt
|
||||
TARGET_LANGUAGE=js uv run python -m mkdocs build --clean -f mkdocs.yml --strict
|
||||
|
||||
llms-text:
|
||||
@@ -42,7 +45,7 @@ vercel-build-docs: install-vercel-deps
|
||||
serve-clean-docs: clean-docs
|
||||
uv run python -m mkdocs serve -c -f mkdocs.yml --strict -w ../libs/langgraph
|
||||
|
||||
serve-docs:
|
||||
serve-docs: build-typedoc
|
||||
uv run python -m mkdocs serve -f mkdocs.yml -w ../libs/langgraph -w ../libs/checkpoint -w ../libs/sdk-py --dirty
|
||||
|
||||
clean-docs:
|
||||
|
||||
+14
-117
@@ -1,126 +1,24 @@
|
||||
# LangGraph Documentation
|
||||
# Setup
|
||||
|
||||
For more information on contributing to our documentation, see the [Contributing Guide](../CONTRIBUTING.md).
|
||||
|
||||
## Structure
|
||||
|
||||
The primary documentation is located in the `docs/` directory. This directory contains both the source files for the main documentation as well as the API reference doc build process.
|
||||
|
||||
### Main Documentation
|
||||
|
||||
Main documentation files are located in `docs/docs/` and are written in Markdown format. The site uses [**MkDocs**](https://www.mkdocs.org/) with the [Material theme](https://squidfunk.github.io/mkdocs-material/) and includes:
|
||||
|
||||
- **Concepts**: Core LangGraph concepts and explanations
|
||||
- **Tutorials**: Step-by-step learning guides
|
||||
- **How-tos**: Task-focused guides for specific use cases
|
||||
- **Examples**: Real-world applications and use cases
|
||||
- **Jupyter Notebooks**: Interactive tutorials that are automatically converted to markdown
|
||||
|
||||
### API Reference
|
||||
|
||||
API reference documentation is defined in `docs/docs/reference/`. Each `.md` file outlines the "template" that each page is built from. Reference content is automatically generated from docstrings in the codebase using the **mkdocstrings** plugin. Once generated, the content is plugged into the corresponding markdown file where it is referenced by using manual directives to specify which classes and/or functions are documented:
|
||||
|
||||
```markdown
|
||||
::: langgraph.graph.state.StateGraph
|
||||
options:
|
||||
show_if_no_docstring: true
|
||||
show_root_heading: true
|
||||
show_root_full_path: false
|
||||
members:
|
||||
- add_node
|
||||
- add_edge
|
||||
- add_conditional_edges
|
||||
- add_sequence
|
||||
- compile
|
||||
```
|
||||
|
||||
## Build Process
|
||||
|
||||
Docs are built following these steps:
|
||||
|
||||
1. **Content Processing:**
|
||||
- `_scripts/notebook_hooks.py` - Main processing pipeline that:
|
||||
- Converts how-tos/tutorial Jupyter notebooks to markdown using `notebook_convert.py`
|
||||
- Adds automatic API reference links to code blocks using `generate_api_reference_links.py`
|
||||
- Handles conditional rendering for Python/JS versions
|
||||
- Processes highlight comments and custom syntax
|
||||
|
||||
2. **API Reference Generation:**
|
||||
- **mkdocstrings** plugin extracts docstrings from Python source code
|
||||
- Manual `::: module.Class` directives in reference pages (`/docs/docs/*`) specify what to document
|
||||
- Cross-references are automatically generated between docs and API
|
||||
|
||||
3. **Site Generation:**
|
||||
- **MkDocs** processes all markdown files and generates static HTML
|
||||
- Custom hooks handle redirects and inject additional functionality
|
||||
|
||||
4. **Deployment:**
|
||||
- Site is deployed with Vercel
|
||||
- `make build-docs` generates production build (also usable for local testing)
|
||||
- Automatic redirects handle URL changes between versions
|
||||
|
||||
### Local Development
|
||||
|
||||
For local development, use the Makefile targets:
|
||||
To setup requirements for building docs you can run:
|
||||
|
||||
```bash
|
||||
uv sync --group test
|
||||
```
|
||||
|
||||
## Serving documentation locally
|
||||
|
||||
To run the documentation server locally you can run:
|
||||
|
||||
```bash
|
||||
# Serve docs locally with hot reloading
|
||||
make serve-docs
|
||||
|
||||
# Clean build for production testing
|
||||
make build-docs
|
||||
|
||||
# Serve with clean build
|
||||
make serve-clean-docs
|
||||
```
|
||||
|
||||
The `serve-docs` command:
|
||||
|
||||
- Watches source files for changes
|
||||
- Includes dirty builds for faster iteration
|
||||
- Serves on [http://127.0.0.1:8000/langgraph/](http://127.0.0.1:8000/langgraph/)
|
||||
|
||||
## Standards
|
||||
|
||||
**Docstring Format:**
|
||||
The API reference uses **Google-style docstrings** with Markdown markup. The `mkdocstrings` plugin processes these to generate documentation.
|
||||
|
||||
**Required format:**
|
||||
|
||||
```python
|
||||
def example_function(param1: str, param2: int = 5) -> bool:
|
||||
"""Brief description of the function.
|
||||
|
||||
Longer description can go here. Use Markdown syntax for
|
||||
rich formatting like **bold** and *italic*.
|
||||
|
||||
Args:
|
||||
param1: Description of the first parameter.
|
||||
param2: Description of the second parameter with default value.
|
||||
|
||||
Returns:
|
||||
Description of the return value.
|
||||
|
||||
Raises:
|
||||
ValueError: When param1 is empty.
|
||||
TypeError: When param2 is not an integer.
|
||||
|
||||
!!! warning
|
||||
This function is experimental and may change.
|
||||
|
||||
!!! version-added "Added in version 0.2.0"
|
||||
"""
|
||||
```
|
||||
|
||||
**Special Markers:**
|
||||
|
||||
- **MkDocs admonitions**: `!!! warning`, `!!! note`, `!!! version-added`
|
||||
- **Code blocks**: Standard markdown ``` syntax
|
||||
- **Cross-references**: Automatic linking via `generate_api_reference_links.py`
|
||||
This will start the documentation server on [http://127.0.0.1:8000/langgraph/](http://127.0.0.1:8000/langgraph/).
|
||||
|
||||
## Execute notebooks
|
||||
|
||||
If you would like to automatically execute all of the notebooks, to mimic the "Run notebooks" GitHub action, you can run:
|
||||
If you would like to automatically execute all of the notebooks, to mimic the "Run notebooks" GHA, you can run:
|
||||
|
||||
```bash
|
||||
python _scripts/prepare_notebooks_for_ci.py
|
||||
@@ -135,9 +33,8 @@ python _scripts/prepare_notebooks_for_ci.py --comment-install-cells
|
||||
```
|
||||
|
||||
`prepare_notebooks_for_ci.py` script will add VCR cassette context manager for each cell in the notebook, so that:
|
||||
|
||||
- when the notebook is run for the first time, cells with network requests will be recorded to a VCR cassette file
|
||||
- when the notebook is run subsequently, the cells with network requests will be replayed from the cassettes
|
||||
* when the notebook is run for the first time, cells with network requests will be recorded to a VCR cassette file
|
||||
* when the notebook is run subsequently, the cells with network requests will be replayed from the cassettes
|
||||
|
||||
## Adding new notebooks
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
"""Generate API reference links for imports in Python code blocks within markdown files."""
|
||||
|
||||
import ast
|
||||
import importlib
|
||||
import logging
|
||||
@@ -72,18 +70,8 @@ MANUAL_API_REFERENCES_LANGGRAPH = [
|
||||
([], "langgraph.checkpoint.postgres.aio", "AsyncPostgresSaver", "checkpoints"),
|
||||
([], "langgraph.checkpoint.postgres", "PostgresSaver", "checkpoints"),
|
||||
# other prebuilts
|
||||
(
|
||||
["langgraph_supervisor"],
|
||||
"langgraph_supervisor.supervisor",
|
||||
"create_supervisor",
|
||||
"supervisor",
|
||||
),
|
||||
(
|
||||
["langgraph_supervisor"],
|
||||
"langgraph_supervisor.handoff",
|
||||
"create_handoff_tool",
|
||||
"supervisor",
|
||||
),
|
||||
(["langgraph_supervisor"], "langgraph_supervisor.supervisor", "create_supervisor", "supervisor"),
|
||||
(["langgraph_supervisor"], "langgraph_supervisor.handoff", "create_handoff_tool", "supervisor"),
|
||||
([], "langgraph_supervisor.handoff", "create_forward_message_tool", "supervisor"),
|
||||
(["langgraph_swarm"], "langgraph_swarm.swarm", "create_swarm", "swarm"),
|
||||
(["langgraph_swarm"], "langgraph_swarm.swarm", "add_active_agent_router", "swarm"),
|
||||
|
||||
@@ -14,7 +14,10 @@ from mkdocs.structure.pages import Page
|
||||
from pydantic import BaseModel, Field
|
||||
from yaml import SafeLoader
|
||||
|
||||
from _scripts.notebook_hooks import _on_page_markdown_with_config
|
||||
from _scripts.notebook_hooks import (
|
||||
_on_page_markdown_with_config,
|
||||
_apply_conditional_rendering,
|
||||
)
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
# Get source directory (parent of HERE / docs)
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
"""Logic to identify and transform cross-reference links in markdown files.
|
||||
|
||||
This module allows supporting custom markdown syntax for "autolinks". These are links
|
||||
that will be transformed based on the current scope context, such as "global", "python",
|
||||
or "js" into an appropriate markdown link format.
|
||||
|
||||
For example,
|
||||
|
||||
```markdown
|
||||
@[StateGraph]
|
||||
```
|
||||
|
||||
May be transformed into:
|
||||
|
||||
```markdown
|
||||
[StateGraph](some_path/api-reference/state-graph.md)
|
||||
```
|
||||
|
||||
The transformation value depends on the scope in which the link is used.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
from _scripts.link_map import SCOPE_LINK_MAPS
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _transform_link(
|
||||
link_name: str,
|
||||
scope: str,
|
||||
file_path: str,
|
||||
line_number: int,
|
||||
custom_title: Optional[str] = None,
|
||||
) -> Optional[str]:
|
||||
"""Transform a cross-reference link based on the current scope.
|
||||
|
||||
Args:
|
||||
link_name: The name of the link to transform (e.g., "StateGraph").
|
||||
scope: The current scope context ("global", "python", "js", etc.).
|
||||
file_path: The file path for error reporting.
|
||||
line_number: The line number for error reporting.
|
||||
custom_title: Optional custom title for the link. If `None`, uses link_name.
|
||||
|
||||
Returns:
|
||||
A formatted markdown link if the link is found in the scope mapping,
|
||||
None otherwise.
|
||||
|
||||
Example:
|
||||
>>> _transform_link("StateGraph", "python", "file.md", 5)
|
||||
"[StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph)"
|
||||
|
||||
>>> _transform_link("StateGraph", "python", "file.md", 5, "Custom Title")
|
||||
"[Custom Title](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph)"
|
||||
|
||||
>>> _transform_link("unknown-link", "python", "file.md", 5)
|
||||
None
|
||||
"""
|
||||
if scope == "global":
|
||||
# Special scope that is composed of both Python and JS links
|
||||
# For now, we will substitute in the python scope!
|
||||
# But we need to add support for handling both scopes.
|
||||
scope = "python"
|
||||
logger.error(
|
||||
"Encountered unhandled 'global' scope. Defaulting to 'python'."
|
||||
"In file: %s, line %d, link_name: %s",
|
||||
file_path,
|
||||
line_number,
|
||||
link_name,
|
||||
)
|
||||
link_map = SCOPE_LINK_MAPS.get(scope, {})
|
||||
url = link_map.get(link_name)
|
||||
|
||||
if url:
|
||||
title = custom_title if custom_title is not None else link_name
|
||||
return f"[{title}]({url})"
|
||||
else:
|
||||
# Log error with file location information
|
||||
logger.info(
|
||||
# Using %s
|
||||
"Link '%s' not found in scope '%s'. "
|
||||
"In file: %s, line %d. Available links in scope: %s",
|
||||
link_name,
|
||||
scope,
|
||||
file_path,
|
||||
line_number,
|
||||
list(link_map.keys() if link_map else []),
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
CONDITIONAL_FENCE_PATTERN = re.compile(
|
||||
r"""
|
||||
^ # Start of line
|
||||
(?P<indent>[ \t]*) # Optional indentation (spaces or tabs)
|
||||
::: # Literal fence marker
|
||||
(?P<language>\w+)? # Optional language identifier (named group: language)
|
||||
\s* # Optional trailing whitespace
|
||||
$ # End of line
|
||||
""",
|
||||
re.VERBOSE,
|
||||
)
|
||||
CROSS_REFERENCE_PATTERN = re.compile(
|
||||
r"""
|
||||
(?: # Non-capturing group for two possible formats:
|
||||
@\[ # @ symbol followed by opening bracket for title
|
||||
(?P<title>[^\]]+) # Custom title - one or more non-bracket characters
|
||||
\] # Closing bracket for title
|
||||
\[ # Opening bracket for link name
|
||||
(?P<link_name_with_title>[^\]]+) # Link name - one or more non-bracket characters
|
||||
\] # Closing bracket for link name
|
||||
| # OR
|
||||
@\[ # @ symbol followed by opening bracket
|
||||
(?P<link_name>[^\]]+) # Link name - one or more non-bracket characters
|
||||
\] # Closing bracket
|
||||
)
|
||||
""",
|
||||
re.VERBOSE,
|
||||
)
|
||||
|
||||
|
||||
def _replace_autolinks(
|
||||
markdown: str, file_path: str, *, default_scope: str = "python"
|
||||
) -> str:
|
||||
"""Preprocess markdown lines to handle @[links] with conditional fence scopes.
|
||||
|
||||
This function processes markdown content to transform @[link_name] references
|
||||
based on the current conditional fence scope. Conditional fences use the
|
||||
syntax :::language to define scope boundaries.
|
||||
|
||||
Args:
|
||||
markdown: The markdown content to process.
|
||||
file_path: The file path for error reporting.
|
||||
default_scope: The default scope to use if no scope is matched.
|
||||
|
||||
Returns:
|
||||
Processed markdown content with @[references] transformed to proper
|
||||
markdown links or left unchanged if not found.
|
||||
|
||||
Example:
|
||||
Input:
|
||||
"@[StateGraph]\\n:::python\\n@[Command]\\n:::\\n"
|
||||
Output:
|
||||
"[StateGraph](url)\\n:::python\\n[Command](url)\\n:::\\n"
|
||||
"""
|
||||
# Track the current scope context
|
||||
current_scope = default_scope
|
||||
lines = markdown.splitlines(keepends=True)
|
||||
processed_lines = []
|
||||
|
||||
for line_number, line in enumerate(lines, 1):
|
||||
line_stripped = line.strip()
|
||||
|
||||
# Check if this line defines a new conditional fence scope
|
||||
fence_match = CONDITIONAL_FENCE_PATTERN.match(line_stripped)
|
||||
if fence_match:
|
||||
language = fence_match.group("language")
|
||||
# Set scope to the specified language, or reset to global if no language
|
||||
current_scope = language.lower() if language else default_scope
|
||||
processed_lines.append(line)
|
||||
continue
|
||||
|
||||
# Transform all @[link_name] references in this line based on current scope
|
||||
def replace_cross_reference(match: re.Match[str]) -> str:
|
||||
"""Replace a single @[link_name] with the scoped equivalent."""
|
||||
# Check if this is the @[title][ref] format or @[ref] format
|
||||
title = match.group("title")
|
||||
if title is not None:
|
||||
# This is @[title][ref] format
|
||||
link_name = match.group("link_name_with_title")
|
||||
custom_title = title
|
||||
else:
|
||||
# This is @[ref] format
|
||||
link_name = match.group("link_name")
|
||||
custom_title = None
|
||||
|
||||
transformed = _transform_link(
|
||||
link_name, current_scope, file_path, line_number, custom_title
|
||||
)
|
||||
return transformed if transformed is not None else match.group(0)
|
||||
|
||||
transformed_line = CROSS_REFERENCE_PATTERN.sub(replace_cross_reference, line)
|
||||
processed_lines.append(transformed_line)
|
||||
|
||||
return "".join(processed_lines)
|
||||
Binary file not shown.
@@ -2108,9 +2108,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"hono@npm:^4.5.4":
|
||||
version: 4.10.3
|
||||
resolution: "hono@npm:4.10.3"
|
||||
checksum: 10c0/bdcc4c7066c74ba7cfa63ed6550768a0f43a420286c8f8f74b7012ea4901b8b06778fa8e98264b46f1a86920f056b7ede1f07814da4934912f9945def4977c29
|
||||
version: 4.8.9
|
||||
resolution: "hono@npm:4.8.9"
|
||||
checksum: 10c0/385539d1787fdc747bc869ef0e5ccc9f39cbe40289b94f23eecfc82c6ca440f059704647cd6381a5066d2cf7baa43ab25184c78d44af4c5c98a5c5b07670059e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
+3
-125
@@ -1,127 +1,5 @@
|
||||
"""Link mapping for cross-reference resolution across different scopes.
|
||||
|
||||
This module provides link mappings for different language/framework scopes
|
||||
to resolve @[link_name] references to actual URLs.
|
||||
"""
|
||||
|
||||
# Python-specific link mappings
|
||||
PYTHON_LINK_MAP = {
|
||||
"StateGraph": "reference/graphs/#langgraph.graph.StateGraph",
|
||||
"add_conditional_edges": "reference/graphs/#langgraph.graph.state.StateGraph.add_conditional_edges",
|
||||
"add_edge": "reference/graphs/#langgraph.graph.state.StateGraph.add_edge",
|
||||
"add_node": "reference/graphs/#langgraph.graph.state.StateGraph.add_node",
|
||||
"add_messages": "reference/graphs/#langgraph.graph.message.add_messages",
|
||||
"ToolNode": "reference/agents/#langgraph.prebuilt.tool_node.ToolNode",
|
||||
"CompiledStateGraph.astream": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.astream",
|
||||
"Pregel.astream": "reference/pregel/#langgraph.pregel.Pregel.astream",
|
||||
"AsyncPostgresSaver": "reference/checkpoints/#langgraph.checkpoint.postgres.aio.AsyncPostgresSaver",
|
||||
"AsyncSqliteSaver": "reference/checkpoints/#langgraph.checkpoint.sqlite.aio.AsyncSqliteSaver",
|
||||
"BaseCheckpointSaver": "reference/checkpoints/#langgraph.checkpoint.base.BaseCheckpointSaver",
|
||||
"BaseStore": "reference/store/#langgraph.store.base.BaseStore",
|
||||
"BaseStore.put": "reference/store/#langgraph.store.base.BaseStore.put",
|
||||
"BinaryOperatorAggregate": "reference/pregel/#langgraph.pregel.Pregel--advanced-channels-context-and-binaryoperatoraggregate",
|
||||
"CipherProtocol": "reference/checkpoints/#langgraph.checkpoint.serde.base.CipherProtocol",
|
||||
"client.runs.stream": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.RunsClient.stream",
|
||||
"client.runs.wait": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.RunsClient.wait",
|
||||
"client.threads.get_history": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.ThreadsClient.get_history",
|
||||
"client.threads.update_state": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.ThreadsClient.update_state",
|
||||
"Command": "reference/types/#langgraph.types.Command",
|
||||
"CompiledStateGraph": "reference/graphs/#langgraph.graph.state.CompiledStateGraph",
|
||||
"create_react_agent": "reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent",
|
||||
"create_supervisor": "reference/supervisor/#langgraph_supervisor.supervisor.create_supervisor",
|
||||
"EncryptedSerializer": "reference/checkpoints/#langgraph.checkpoint.serde.encrypted.EncryptedSerializer",
|
||||
"entrypoint.final": "reference/func/#langgraph.func.entrypoint.final",
|
||||
"entrypoint": "reference/func/#langgraph.func.entrypoint",
|
||||
"from_pycryptodome_aes": "reference/checkpoints/#langgraph.checkpoint.serde.encrypted.EncryptedSerializer.from_pycryptodome_aes",
|
||||
"get_state_history": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.get_state_history",
|
||||
"get_stream_writer": "reference/config/#langgraph.config.get_stream_writer",
|
||||
"HumanInterrupt": "reference/prebuilt/#langgraph.prebuilt.interrupt.HumanInterrupt",
|
||||
"InjectedState": "reference/agents/#langgraph.prebuilt.tool_node.InjectedState",
|
||||
"InMemorySaver": "reference/checkpoints/#langgraph.checkpoint.memory.InMemorySaver",
|
||||
"interrupt": "reference/types/#langgraph.types.Interrupt",
|
||||
"CompiledStateGraph.invoke": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.invoke",
|
||||
"JsonPlusSerializer": "reference/checkpoints/#langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer",
|
||||
"langgraph.json": "cloud/reference/cli/#configuration-file",
|
||||
"LastValue": "reference/channels/#langgraph.channels.LastValue",
|
||||
"PostgresSaver": "reference/checkpoints/#langgraph.checkpoint.postgres.PostgresSaver",
|
||||
"Pregel": "reference/pregel/",
|
||||
"Pregel.stream": "reference/pregel/#langgraph.pregel.Pregel.stream",
|
||||
"pre_model_hook": "reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent",
|
||||
"protocol": "reference/checkpoints/#langgraph.checkpoint.serde.base.SerializerProtocol",
|
||||
"Send": "reference/types/#langgraph.types.Send",
|
||||
"SerializerProtocol": "reference/checkpoints/#langgraph.checkpoint.serde.base.SerializerProtocol",
|
||||
"SqliteSaver": "reference/checkpoints/#langgraph.checkpoint.sqlite.SqliteSaver",
|
||||
"START": "reference/constants/#langgraph.constants.START",
|
||||
"CompiledStateGraph.stream": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.stream",
|
||||
"task": "reference/func/#langgraph.func.task",
|
||||
"Topic": "reference/channels/#langgraph.channels.Topic",
|
||||
"update_state": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.update_state",
|
||||
}
|
||||
|
||||
# JavaScript-specific link mappings
|
||||
JS_LINK_MAP = {
|
||||
"Auth": "reference/classes/sdk_auth.Auth.html",
|
||||
"StateGraph": "reference/classes/langgraph.StateGraph.html",
|
||||
"add_conditional_edges": "/reference/classes/langgraph.StateGraph.html#addConditionalEdges",
|
||||
"add_edge": "reference/classes/langgraph.StateGraph.html#addEdge",
|
||||
"add_node": "reference/classes/langgraph.StateGraph.html#addNode",
|
||||
"add_messages": "reference/modules/langgraph.html#addMessages",
|
||||
"ToolNode": "reference/classes/langgraph_prebuilt.ToolNode.html",
|
||||
"BaseCheckpointSaver": "reference/classes/checkpoint.BaseCheckpointSaver.html",
|
||||
"BaseStore": "reference/classes/checkpoint.BaseStore.html",
|
||||
"BaseStore.put": "reference/classes/checkpoint.BaseStore.html#put",
|
||||
"BinaryOperatorAggregate": "reference/classes/langgraph.BinaryOperatorAggregate.html",
|
||||
"client.runs.stream": "reference/classes/sdk_client.RunsClient.html#stream",
|
||||
"client.runs.wait": "reference/classes/sdk_client.RunsClient.html#wait",
|
||||
"client.threads.get_history": "reference/classes/sdk_client.ThreadsClient.html#getHistory",
|
||||
"client.threads.update_state": "reference/classes/sdk_client.ThreadsClient.html#updateState",
|
||||
"Command": "reference/classes/langgraph.Command.html",
|
||||
"CompiledStateGraph": "reference/classes/langgraph.CompiledStateGraph.html",
|
||||
"create_react_agent": "reference/functions/langgraph_prebuilt.createReactAgent.html",
|
||||
"create_supervisor": "reference/functions/langgraph_supervisor.createSupervisor.html",
|
||||
"entrypoint.final": "reference/functions/langgraph.entrypoint.html#final",
|
||||
"entrypoint": "reference/functions/langgraph.entrypoint.html",
|
||||
"getContextVariable": "https://v03.api.js.langchain.com/functions/_langchain_core.context.getContextVariable.html",
|
||||
"get_state_history": "reference/classes/langgraph.CompiledStateGraph.html#getStateHistory",
|
||||
"HumanInterrupt": "reference/interfaces/langgraph_prebuilt.HumanInterrupt.html",
|
||||
"interrupt": "reference/functions/langgraph.interrupt-2.html",
|
||||
"CompiledStateGraph.invoke": "reference/classes/langgraph.CompiledStateGraph.html#invoke",
|
||||
"langgraph.json": "cloud/reference/cli/#configuration-file",
|
||||
"MemorySaver": "reference/classes/checkpoint.MemorySaver.html",
|
||||
"messagesStateReducer": "reference/functions/langgraph.messagesStateReducer.html",
|
||||
"PostgresSaver": "reference/classes/checkpoint_postgres.PostgresSaver.html",
|
||||
"Pregel": "reference/classes/langgraph.Pregel.html",
|
||||
"Pregel.stream": "reference/classes/langgraph.Pregel.html#stream",
|
||||
"pre_model_hook": "reference/functions/langgraph_prebuilt.createReactAgent.html",
|
||||
"protocol": "reference/interfaces/checkpoint.SerializerProtocol.html",
|
||||
"Send": "reference/classes/langgraph.Send.html",
|
||||
"SerializerProtocol": "reference/interfaces/checkpoint.SerializerProtocol.html",
|
||||
"SqliteSaver": "reference/classes/checkpoint_sqlite.SqliteSaver.html",
|
||||
"START": "reference/variables/langgraph.START.html",
|
||||
"CompiledStateGraph.stream": "reference/classes/langgraph.CompiledStateGraph.html#stream",
|
||||
"task": "reference/functions/langgraph.task.html",
|
||||
## TODO (hntrl): export Topic from langgraphjs
|
||||
# "Topic": "reference/classes/langgraph_channels.Topic.html",
|
||||
"update_state": "reference/classes/langgraph.CompiledStateGraph.html#updateState",
|
||||
}
|
||||
|
||||
# TODO: Allow updating these to localhost for local development
|
||||
PY_REFERENCE_HOST = "https://langchain-ai.github.io/langgraph/"
|
||||
JS_REFERENCE_HOST = "https://langchain-ai.github.io/langgraphjs/"
|
||||
|
||||
for key, value in PYTHON_LINK_MAP.items():
|
||||
# Ensure the link is absolute
|
||||
if not value.startswith("http"):
|
||||
PYTHON_LINK_MAP[key] = f"{PY_REFERENCE_HOST}{value}"
|
||||
|
||||
for key, value in JS_LINK_MAP.items():
|
||||
# Ensure the link is absolute
|
||||
if not value.startswith("http"):
|
||||
JS_LINK_MAP[key] = f"{JS_REFERENCE_HOST}{value}"
|
||||
|
||||
# Global scope is assembled from the Python and JS mappings
|
||||
# Combined mapping by scope
|
||||
SCOPE_LINK_MAPS = {
|
||||
"python": PYTHON_LINK_MAP,
|
||||
"js": JS_LINK_MAP,
|
||||
"langgraph.types.interrupt": "https://langchain-ai.github.io/langgraphjs/reference/functions/langgraph.interrupt-2.html",
|
||||
"create_react_agent": "https://langchain-ai.github.io/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html",
|
||||
"langgraph.types.Command": "https://langchain-ai.github.io/langgraphjs/reference/classes/langgraph.Command.html",
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
"""Convert Jupyter notebooks to markdown with custom processing."""
|
||||
|
||||
import ast
|
||||
import os
|
||||
import re
|
||||
|
||||
+142
-609
@@ -3,7 +3,6 @@
|
||||
Lifecycle events: https://www.mkdocs.org/dev-guide/plugins/#events
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import posixpath
|
||||
@@ -16,7 +15,7 @@ from mkdocs.structure.files import Files, File
|
||||
from mkdocs.structure.pages import Page
|
||||
|
||||
from _scripts.generate_api_reference_links import update_markdown_with_imports
|
||||
from _scripts.handle_auto_links import _replace_autolinks
|
||||
from _scripts.link_map import JS_LINK_MAP
|
||||
from _scripts.notebook_convert import convert_notebook
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -27,430 +26,103 @@ DISABLED = os.getenv("DISABLE_NOTEBOOK_CONVERT") in ("1", "true", "True")
|
||||
|
||||
REDIRECT_MAP = {
|
||||
# lib redirects
|
||||
"how-tos/stream-values.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"how-tos/stream-updates.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"how-tos/streaming-content.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"how-tos/stream-multiple.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"how-tos/streaming-tokens-without-langchain.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"how-tos/streaming-from-final-node.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"how-tos/streaming-events-from-within-tools-without-langchain.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"how-tos/stream-values.ipynb": "how-tos/streaming.md#stream-graph-state",
|
||||
"how-tos/stream-updates.ipynb": "how-tos/streaming.md#stream-graph-state",
|
||||
"how-tos/streaming-content.ipynb": "how-tos/streaming.md",
|
||||
"how-tos/stream-multiple.ipynb": "how-tos/streaming.md#stream-multiple-nodes",
|
||||
"how-tos/streaming-tokens-without-langchain.ipynb": "how-tos/streaming.md#use-with-any-llm",
|
||||
"how-tos/streaming-from-final-node.ipynb": "how-tos/streaming-specific-nodes.ipynb",
|
||||
"how-tos/streaming-events-from-within-tools-without-langchain.ipynb": "how-tos/streaming-events-from-within-tools.ipynb#example-without-langchain",
|
||||
# graph-api
|
||||
"how-tos/state-reducers.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#define-and-update-state",
|
||||
"how-tos/sequence.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#create-a-sequence-of-steps",
|
||||
"how-tos/branching.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#create-branches",
|
||||
"how-tos/recursion-limit.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#create-and-control-loops",
|
||||
"how-tos/visualization.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#visualize-your-graph",
|
||||
"how-tos/input_output_schema.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#define-input-and-output-schemas",
|
||||
"how-tos/pass_private_state.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#pass-private-state-between-nodes",
|
||||
"how-tos/state-model.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#use-pydantic-models-for-graph-state",
|
||||
"how-tos/map-reduce.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#map-reduce-and-the-send-api",
|
||||
"how-tos/command.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#combine-control-flow-and-state-updates-with-command",
|
||||
"how-tos/configuration.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#add-runtime-configuration",
|
||||
"how-tos/node-retries.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#add-retry-policies",
|
||||
"how-tos/return-when-recursion-limit-hits.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#impose-a-recursion-limit",
|
||||
"how-tos/async.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#async",
|
||||
"how-tos/state-reducers.ipynb": "how-tos/graph-api#define-and-update-state",
|
||||
"how-tos/sequence.ipynb": "how-tos/graph-api#create-a-sequence-of-steps",
|
||||
"how-tos/branching.ipynb": "how-tos/graph-api#create-branches",
|
||||
"how-tos/recursion-limit.ipynb": "how-tos/graph-api#create-and-control-loops",
|
||||
"how-tos/visualization.ipynb": "how-tos/graph-api#visualize-your-graph",
|
||||
"how-tos/input_output_schema.ipynb": "how-tos/graph-api#define-input-and-output-schemas",
|
||||
"how-tos/pass_private_state.ipynb": "how-tos/graph-api#pass-private-state-between-nodes",
|
||||
"how-tos/state-model.ipynb": "how-tos/graph-api#use-pydantic-models-for-graph-state",
|
||||
"how-tos/map-reduce.ipynb": "how-tos/graph-api/#map-reduce-and-the-send-api",
|
||||
"how-tos/command.ipynb": "how-tos/graph-api/#combine-control-flow-and-state-updates-with-command",
|
||||
"how-tos/configuration.ipynb": "how-tos/graph-api/#add-runtime-configuration",
|
||||
"how-tos/node-retries.ipynb": "how-tos/graph-api/#add-retry-policies",
|
||||
"how-tos/return-when-recursion-limit-hits.ipynb": "how-tos/graph-api/#impose-a-recursion-limit",
|
||||
"how-tos/async.ipynb": "how-tos/graph-api/#async",
|
||||
# memory how-tos
|
||||
"how-tos/memory/manage-conversation-history.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
|
||||
"how-tos/memory/delete-messages.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#delete-messages",
|
||||
"how-tos/memory/add-summary-conversation-history.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#summarize-messages",
|
||||
"how-tos/memory.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
|
||||
"agents/memory.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
|
||||
"how-tos/memory/manage-conversation-history.ipynb": "how-tos/memory/add-memory.md",
|
||||
"how-tos/memory/delete-messages.ipynb": "how-tos/memory/add-memory.md#delete-messages",
|
||||
"how-tos/memory/add-summary-conversation-history.ipynb": "how-tos/memory/add-memory.md#summarize-messages",
|
||||
"how-tos/memory.ipynb": "how-tos/memory/add-memory.md",
|
||||
"agents/memory.ipynb": "how-tos/memory/add-memory.md",
|
||||
# subgraph how-tos
|
||||
"how-tos/subgraph-transform-state.ipynb": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs#different-state-schemas",
|
||||
"how-tos/subgraphs-manage-state.ipynb": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs#add-persistence",
|
||||
"how-tos/subgraph-transform-state.ipynb": "how-tos/subgraph.ipynb#different-state-schemas",
|
||||
"how-tos/subgraphs-manage-state.ipynb": "how-tos/subgraph.ipynb#add-persistence",
|
||||
# persistence how-tos
|
||||
"how-tos/persistence_postgres.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-in-production",
|
||||
"how-tos/persistence_mongodb.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-in-production",
|
||||
"how-tos/persistence_redis.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-in-production",
|
||||
"how-tos/subgraph-persistence.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-with-subgraphs",
|
||||
"how-tos/cross-thread-persistence.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#add-long-term-memory",
|
||||
"cloud/how-tos/copy_threads": "https://docs.langchain.com/langsmith/use-threads",
|
||||
"cloud/how-tos/check-thread-status": "https://docs.langchain.com/langsmith/use-threads",
|
||||
"cloud/concepts/threads.md": "https://docs.langchain.com/oss/python/langgraph/persistence#threads",
|
||||
"how-tos/persistence.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
|
||||
"how-tos/persistence_postgres.ipynb": "how-tos/memory/add-memory.md#use-in-production",
|
||||
"how-tos/persistence_mongodb.ipynb": "how-tos/memory/add-memory.md#use-in-production",
|
||||
"how-tos/persistence_redis.ipynb": "how-tos/memory/add-memory.md#use-in-production",
|
||||
"how-tos/subgraph-persistence.ipynb": "how-tos/memory/add-memory.md#use-with-subgraphs",
|
||||
"how-tos/cross-thread-persistence.ipynb": "how-tos/memory/add-memory.md#add-long-term-memory",
|
||||
"cloud/how-tos/copy_threads": "cloud/how-tos/use_threads",
|
||||
"cloud/how-tos/check-thread-status": "cloud/how-tos/use_threads",
|
||||
"cloud/concepts/threads.md": "concepts/persistence.md#threads",
|
||||
"how-tos/persistence.ipynb": "how-tos/memory/add-memory.md",
|
||||
# tool calling how-tos
|
||||
"how-tos/tool-calling-errors.ipynb": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"how-tos/pass-config-to-tools.ipynb": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"how-tos/pass-run-time-values-to-tools.ipynb": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"how-tos/update-state-from-tools.ipynb": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"agents/tools.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"how-tos/tool-calling-errors.ipynb": "how-tos/tool-calling.ipynb#handle-errors",
|
||||
"how-tos/pass-config-to-tools.ipynb": "how-tos/tool-calling.ipynb#access-config",
|
||||
"how-tos/pass-run-time-values-to-tools.ipynb": "how-tos/tool-calling.ipynb#read-state",
|
||||
"how-tos/update-state-from-tools.ipynb": "how-tos/tool-calling.ipynb#update-state",
|
||||
# multi-agent how-tos
|
||||
"how-tos/agent-handoffs.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api",
|
||||
"how-tos/multi-agent-network.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api",
|
||||
"how-tos/multi-agent-multi-turn-convo.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api",
|
||||
"how-tos/agent-handoffs.ipynb": "how-tos/multi_agent.ipynb#handoffs",
|
||||
"how-tos/multi-agent-network.ipynb": "how-tos/multi_agent.ipynb#use-in-a-multi-agent-system",
|
||||
"how-tos/multi-agent-multi-turn-convo.ipynb": "how-tos/multi_agent.ipynb#multi-turn-conversation",
|
||||
# cloud redirects
|
||||
"cloud/index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"cloud/how-tos/index.md": "https://docs.langchain.com/langsmith/home",
|
||||
"cloud/concepts/api.md": "https://docs.langchain.com/langsmith/agent-server",
|
||||
"cloud/concepts/cloud.md": "https://docs.langchain.com/langsmith/cloud",
|
||||
"cloud/faq/studio.md": "https://docs.langchain.com/langsmith/studio",
|
||||
"cloud/how-tos/human_in_the_loop_edit_state.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop",
|
||||
"cloud/how-tos/human_in_the_loop_user_input.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop",
|
||||
"concepts/platform_architecture.md": "https://docs.langchain.com/langsmith/cloud#architecture",
|
||||
"cloud/index.md": "index.md",
|
||||
"cloud/how-tos/index.md": "concepts/langgraph_platform",
|
||||
"cloud/concepts/api.md": "concepts/langgraph_server.md",
|
||||
"cloud/concepts/cloud.md": "concepts/langgraph_cloud.md",
|
||||
"cloud/faq/studio.md": "concepts/langgraph_studio.md#studio-faqs",
|
||||
"cloud/how-tos/human_in_the_loop_edit_state.md": "cloud/how-tos/add-human-in-the-loop.md",
|
||||
"cloud/how-tos/human_in_the_loop_user_input.md": "cloud/how-tos/add-human-in-the-loop.md",
|
||||
"concepts/platform_architecture.md": "concepts/langgraph_cloud#architecture",
|
||||
# cloud streaming redirects
|
||||
"cloud/how-tos/stream_values.md": "https://docs.langchain.com/langsmith/streaming",
|
||||
"cloud/how-tos/stream_updates.md": "https://docs.langchain.com/langsmith/streaming",
|
||||
"cloud/how-tos/stream_messages.md": "https://docs.langchain.com/langsmith/streaming",
|
||||
"cloud/how-tos/stream_events.md": "https://docs.langchain.com/langsmith/streaming",
|
||||
"cloud/how-tos/stream_debug.md": "https://docs.langchain.com/langsmith/streaming",
|
||||
"cloud/how-tos/stream_multiple.md": "https://docs.langchain.com/langsmith/streaming",
|
||||
"cloud/concepts/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"agents/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"cloud/how-tos/stream_values.md": "cloud/how-tos/streaming.md#stream-graph-state",
|
||||
"cloud/how-tos/stream_updates.md": "cloud/how-tos/streaming.md#stream-graph-state",
|
||||
"cloud/how-tos/stream_messages.md": "cloud/how-tos/streaming.md#messages",
|
||||
"cloud/how-tos/stream_events.md": "cloud/how-tos/streaming.md#stream-events",
|
||||
"cloud/how-tos/stream_debug.md": "cloud/how-tos/streaming.md#debug",
|
||||
"cloud/how-tos/stream_multiple.md": "cloud/how-tos/streaming.md#stream-multiple-modes",
|
||||
"cloud/concepts/streaming.md": "concepts/streaming.md",
|
||||
"agents/streaming.md": "how-tos/streaming.md",
|
||||
# prebuilt redirects
|
||||
"how-tos/create-react-agent.ipynb": "https://docs.langchain.com/oss/python/langchain/agents#basic-configuration",
|
||||
"how-tos/create-react-agent-memory.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
|
||||
"how-tos/create-react-agent-system-prompt.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
|
||||
"how-tos/create-react-agent-structured-output.ipynb": "https://docs.langchain.com/oss/python/langchain/agents#structured-output",
|
||||
"how-tos/create-react-agent.ipynb": "agents/agents.md#basic-configuration",
|
||||
"how-tos/create-react-agent-memory.ipynb": "agents/memory.md",
|
||||
"how-tos/create-react-agent-system-prompt.ipynb": "agents/context.md#prompts",
|
||||
"how-tos/create-react-agent-structured-output.ipynb": "agents/agents.md#structured-output",
|
||||
# Time-travel
|
||||
"how-tos/human_in_the_loop/edit-graph-state.ipynb": "how-tos/human_in_the_loop/time-travel.md",
|
||||
# breakpoints
|
||||
"how-tos/human_in_the_loop/dynamic_breakpoints.ipynb": "how-tos/human_in_the_loop/breakpoints.md",
|
||||
# misc
|
||||
"prebuilt.md": "https://docs.langchain.com/oss/python/langchain/agents",
|
||||
"reference/prebuilt.md": "https://reference.langchain.com/python/langgraph/agents/",
|
||||
"concepts/high_level.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"concepts/index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"concepts/v0-human-in-the-loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
|
||||
"how-tos/index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"tutorials/introduction.ipynb": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"agents/deployment.md": "https://docs.langchain.com/oss/python/langgraph/local-server",
|
||||
"prebuilt.md": "agents/prebuilt.md",
|
||||
"reference/prebuilt.md": "reference/agents.md",
|
||||
"concepts/high_level.md": "index.md",
|
||||
"concepts/index.md": "index.md",
|
||||
"concepts/v0-human-in-the-loop.md": "concepts/human-in-the-loop.md",
|
||||
"how-tos/index.md": "index.md",
|
||||
"tutorials/introduction.ipynb": "concepts/why-langgraph.md",
|
||||
# deployment redirects
|
||||
"how-tos/deploy-self-hosted.md": "https://docs.langchain.com/langsmith/platform-setup",
|
||||
"concepts/self_hosted.md": "https://docs.langchain.com/langsmith/platform-setup",
|
||||
"tutorials/deployment.md": "https://docs.langchain.com/langsmith/deployments",
|
||||
"how-tos/deploy-self-hosted.md": "cloud/deployment/self_hosted_data_plane.md",
|
||||
"concepts/self_hosted.md": "concepts/langgraph_self_hosted_data_plane.md",
|
||||
"tutorials/deployment.md": "concepts/deployment_options.md",
|
||||
# assistant redirects
|
||||
"cloud/how-tos/assistant_versioning.md": "https://docs.langchain.com/langsmith/configuration-cloud",
|
||||
"cloud/concepts/runs.md": "https://docs.langchain.com/langsmith/assistants#execution",
|
||||
"cloud/how-tos/assistant_versioning.md": "cloud/how-tos/configuration_cloud.md",
|
||||
"cloud/concepts/runs.md": "concepts/assistants.md#execution",
|
||||
# hitl redirects
|
||||
"how-tos/wait-user-input-functional.ipynb": "https://docs.langchain.com/oss/python/langgraph/functional-api",
|
||||
"how-tos/review-tool-calls-functional.ipynb": "https://docs.langchain.com/oss/python/langgraph/functional-api",
|
||||
"how-tos/create-react-agent-hitl.ipynb": "https://docs.langchain.com/oss/python/langgraph/interrupts",
|
||||
"agents/human-in-the-loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
|
||||
"how-tos/human_in_the_loop/dynamic_breakpoints.ipynb": "https://docs.langchain.com/oss/python/langgraph/interrupts",
|
||||
"concepts/breakpoints.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
|
||||
"how-tos/human_in_the_loop/breakpoints.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
|
||||
"cloud/how-tos/human_in_the_loop_breakpoint.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop",
|
||||
"how-tos/human_in_the_loop/edit-graph-state.ipynb": "https://docs.langchain.com/oss/python/langgraph/use-time-travel",
|
||||
|
||||
# LGP mintlify migration redirects
|
||||
"examples/index.md": "https://docs.langchain.com/oss/python/learn",
|
||||
"guides/index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"concepts/index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"tutorials/index.md": "https://docs.langchain.com/oss/python/learn",
|
||||
"llms-txt-overview.md": "https://docs.langchain.com/llms.txt",
|
||||
"tutorials/rag/langgraph_adaptive_rag.md": "https://docs.langchain.com/oss/python/langgraph/agentic-rag",
|
||||
"tutorials/multi_agent/multi-agent-collaboration.ipynb": "https://docs.langchain.com/oss/python/langchain/multi-agent",
|
||||
"how-tos/create-react-agent-manage-message-history.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
|
||||
"how-tos/many-tools.ipynb": "https://docs.langchain.com/oss/python/langchain/tools",
|
||||
"tutorials/customer-support/customer-support.ipynb": "https://docs.langchain.com/oss/python/langgraph/agentic-rag",
|
||||
"how-tos/react-agent-structured-output.ipynb": "https://docs.langchain.com/oss/python/langchain/agents#structured-output",
|
||||
"tutorials/code_assistant/langgraph_code_assistant.ipynb": "https://docs.langchain.com/oss/python/langgraph/agentic-rag",
|
||||
"tutorials/multi_agent/hierarchical_agent_teams.ipynb": "https://docs.langchain.com/oss/python/langchain/supervisor",
|
||||
"tutorials/auth/getting_started.md": "https://docs.langchain.com/langsmith/auth",
|
||||
"tutorials/auth/resource_auth.md": "https://docs.langchain.com/langsmith/resource-auth",
|
||||
"tutorials/auth/add_auth_server.md": "https://docs.langchain.com/langsmith/add-auth-server",
|
||||
"how-tos/use-remote-graph.md": "https://docs.langchain.com/langsmith/use-remote-graph",
|
||||
"how-tos/autogen-integration.md": "https://docs.langchain.com/langsmith/autogen-integration",
|
||||
"how-tos/human_in_the_loop/wait-user-input.ipynb": "https://docs.langchain.com/oss/python/langgraph/interrupts",
|
||||
"cloud/how-tos/use_stream_react.md": "https://docs.langchain.com/langsmith/use-stream-react",
|
||||
"cloud/how-tos/generative_ui_react.md": "https://docs.langchain.com/langsmith/generative-ui-react",
|
||||
"concepts/langgraph_platform.md": "https://docs.langchain.com/langsmith/deployments",
|
||||
"concepts/langgraph_components.md": "https://docs.langchain.com/langsmith/components",
|
||||
"concepts/langgraph_server.md": "https://docs.langchain.com/langsmith/agent-server",
|
||||
"concepts/langgraph_data_plane.md": "https://docs.langchain.com/langsmith/data-plane",
|
||||
"concepts/langgraph_control_plane.md": "https://docs.langchain.com/langsmith/control-plane",
|
||||
"concepts/langgraph_cli.md": "https://docs.langchain.com/langsmith/cli",
|
||||
"concepts/langgraph_studio.md": "https://docs.langchain.com/langsmith/studio",
|
||||
"cloud/how-tos/studio/quick_start.md": "https://docs.langchain.com/langsmith/quick-start-studio",
|
||||
"cloud/how-tos/invoke_studio.md": "https://docs.langchain.com/langsmith/use-studio#run-application",
|
||||
"cloud/how-tos/studio/manage_assistants.md": "https://docs.langchain.com/langsmith/use-studio#manage-assistants",
|
||||
"cloud/how-tos/threads_studio.md": "https://docs.langchain.com/langsmith/use-studio#manage-threads",
|
||||
"cloud/how-tos/iterate_graph_studio.md": "https://docs.langchain.com/langsmith/observability-studio#iterate-on-prompts",
|
||||
"cloud/how-tos/studio/run_evals.md": "https://docs.langchain.com/langsmith/observability-studio#run-experiments-over-a-dataset",
|
||||
"cloud/how-tos/clone_traces_studio.md": "https://docs.langchain.com/langsmith/observability-studio#debug-langsmith-traces",
|
||||
"cloud/how-tos/datasets_studio.md": "https://docs.langchain.com/langsmith/observability-studio#add-node-to-dataset",
|
||||
"concepts/sdk.md": "https://docs.langchain.com/langsmith/sdk",
|
||||
"concepts/plans.md": "https://langchain.com/pricing",
|
||||
"concepts/application_structure.md": "https://docs.langchain.com/langsmith/application-structure",
|
||||
"concepts/scalability_and_resilience.md": "https://docs.langchain.com/langsmith/scalability-and-resilience",
|
||||
"concepts/auth.md": "https://docs.langchain.com/langsmith/authentication-methods",
|
||||
"how-tos/auth/custom_auth.md": "https://docs.langchain.com/langsmith/custom-auth",
|
||||
"how-tos/auth/openapi_security.md": "https://docs.langchain.com/langsmith/openapi-security",
|
||||
"concepts/assistants.md": "https://docs.langchain.com/langsmith/assistants",
|
||||
"cloud/how-tos/configuration_cloud.md": "https://docs.langchain.com/langsmith/cloud",
|
||||
"cloud/how-tos/use_threads.md": "https://docs.langchain.com/langsmith/use-threads",
|
||||
"cloud/how-tos/background_run.md": "https://docs.langchain.com/langsmith/background-run",
|
||||
"cloud/how-tos/same-thread.md": "https://docs.langchain.com/langsmith/same-thread",
|
||||
"cloud/how-tos/stateless_runs.md": "https://docs.langchain.com/langsmith/stateless-runs",
|
||||
"cloud/how-tos/configurable_headers.md": "https://docs.langchain.com/langsmith/configurable-headers",
|
||||
"concepts/double_texting.md": "https://docs.langchain.com/langsmith/double-texting",
|
||||
"cloud/how-tos/interrupt_concurrent.md": "https://docs.langchain.com/langsmith/interrupt-concurrent",
|
||||
"cloud/how-tos/rollback_concurrent.md": "https://docs.langchain.com/langsmith/rollback-concurrent",
|
||||
"cloud/how-tos/reject_concurrent.md": "https://docs.langchain.com/langsmith/reject-concurrent",
|
||||
"cloud/how-tos/enqueue_concurrent.md": "https://docs.langchain.com/langsmith/enqueue-concurrent",
|
||||
"cloud/concepts/webhooks.md": "https://docs.langchain.com/langsmith/use-webhooks",
|
||||
"cloud/how-tos/webhooks.md": "https://docs.langchain.com/langsmith/use-webhooks",
|
||||
"cloud/concepts/cron_jobs.md": "https://docs.langchain.com/langsmith/cron-jobs",
|
||||
"cloud/how-tos/cron_jobs.md": "https://docs.langchain.com/langsmith/cron-jobs",
|
||||
"how-tos/http/custom_lifespan.md": "https://docs.langchain.com/langsmith/custom-lifespan",
|
||||
"how-tos/http/custom_middleware.md": "https://docs.langchain.com/langsmith/custom-middleware",
|
||||
"how-tos/http/custom_routes.md": "https://docs.langchain.com/langsmith/custom-routes",
|
||||
"cloud/concepts/data_storage_and_privacy.md": "https://docs.langchain.com/langsmith/data-storage-and-privacy",
|
||||
"cloud/deployment/semantic_search.md": "https://docs.langchain.com/langsmith/semantic-search",
|
||||
"how-tos/ttl/configure_ttl.md": "https://docs.langchain.com/langsmith/configure-ttl",
|
||||
"concepts/deployment_options.md": "https://docs.langchain.com/langsmith/platform-setup",
|
||||
"cloud/quick_start.md": "https://docs.langchain.com/langsmith/deployment-quickstart",
|
||||
"cloud/deployment/setup.md": "https://docs.langchain.com/langsmith/setup-app-requirements-txt",
|
||||
"cloud/deployment/setup_pyproject.md": "https://docs.langchain.com/langsmith/setup-pyproject",
|
||||
"cloud/deployment/setup_javascript.md": "https://docs.langchain.com/langsmith/setup-javascript",
|
||||
"cloud/deployment/custom_docker.md": "https://docs.langchain.com/langsmith/custom-docker",
|
||||
"cloud/deployment/graph_rebuild.md": "https://docs.langchain.com/langsmith/graph-rebuild",
|
||||
"concepts/langgraph_cloud.md": "https://docs.langchain.com/langsmith/cloud",
|
||||
"concepts/langgraph_self_hosted_data_plane.md": "https://docs.langchain.com/langsmith/hybrid",
|
||||
"concepts/langgraph_self_hosted_control_plane.md": "https://docs.langchain.com/langsmith/self-hosted",
|
||||
"concepts/langgraph_standalone_container.md": "https://docs.langchain.com/langsmith/self-hosted#standalone-server",
|
||||
"cloud/deployment/cloud.md": "https://docs.langchain.com/langsmith/cloud",
|
||||
"cloud/deployment/self_hosted_data_plane.md": "https://docs.langchain.com/langsmith/deploy-hybrid",
|
||||
"cloud/deployment/self_hosted_control_plane.md": "https://docs.langchain.com/langsmith/deploy-self-hosted-full-platform",
|
||||
"cloud/deployment/standalone_container.md": "https://docs.langchain.com/langsmith/deploy-standalone-server",
|
||||
"concepts/server-mcp.md": "https://docs.langchain.com/langsmith/server-mcp",
|
||||
"cloud/how-tos/human_in_the_loop_time_travel.md": "https://docs.langchain.com/langsmith/human-in-the-loop-time-travel",
|
||||
"cloud/how-tos/add-human-in-the-loop.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop",
|
||||
"cloud/deployment/egress.md": "https://docs.langchain.com/langsmith/env-var",
|
||||
"cloud/how-tos/streaming.md": "https://docs.langchain.com/langsmith/streaming",
|
||||
"cloud/reference/api/api_ref.md": "https://docs.langchain.com/langsmith/server-api-ref",
|
||||
"cloud/reference/langgraph_server_changelog.md": "https://docs.langchain.com/langsmith/agent-server-changelog",
|
||||
"cloud/reference/api/api_ref_control_plane.md": "https://docs.langchain.com/langsmith/api-ref-control-plane",
|
||||
"cloud/reference/cli.md": "https://docs.langchain.com/langsmith/cli",
|
||||
"cloud/reference/env_var.md": "https://docs.langchain.com/langsmith/env-var",
|
||||
"troubleshooting/studio.md": "https://docs.langchain.com/langsmith/troubleshooting-studio",
|
||||
|
||||
# LangGraph mintlify migration redirects
|
||||
"index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"agents/agents.md": "https://docs.langchain.com/oss/python/langchain/agents",
|
||||
"concepts/why-langgraph.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"tutorials/get-started/1-build-basic-chatbot.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
|
||||
"tutorials/get-started/2-add-tools.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
|
||||
"tutorials/get-started/3-add-memory.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
|
||||
"tutorials/get-started/4-human-in-the-loop.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
|
||||
"tutorials/get-started/5-customize-state.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
|
||||
"tutorials/get-started/6-time-travel.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
|
||||
"tutorials/langsmith/local-server.md": "https://docs.langchain.com/oss/python/langgraph/local-server",
|
||||
"tutorials/workflows.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"tutorials/plan-and-execute/plan-and-execute.ipynb": "https://docs.langchain.com/oss/python/langchain/middleware/built-in#to-do-list",
|
||||
"tutorials/langgraph-platform/local-server/local-server.md": "https://docs.langchain.com/langsmith/local-server",
|
||||
"concepts/agentic_concepts.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"guides/index.md": "https://docs.langchain.com/oss/python/langchain/overview",
|
||||
"agents/overview.md": "https://docs.langchain.com/oss/python/langchain/agents",
|
||||
"agents/run_agents.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
|
||||
"concepts/low_level.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
|
||||
"how-tos/graph-api.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
|
||||
"how-tos/react-agent-from-scratch.ipynb": "https://docs.langchain.com/oss/python/langchain/quickstart",
|
||||
"concepts/functional_api.md": "https://docs.langchain.com/oss/python/langgraph/functional-api",
|
||||
"how-tos/use-functional-api.md": "https://docs.langchain.com/oss/python/langgraph/functional-api",
|
||||
"concepts/pregel.md": "https://docs.langchain.com/oss/python/langgraph/pregel",
|
||||
"concepts/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"how-tos/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"concepts/persistence.md": "https://docs.langchain.com/oss/python/langgraph/persistence",
|
||||
"concepts/durable_execution.md": "https://docs.langchain.com/oss/python/langgraph/durable-execution",
|
||||
"concepts/memory.md": "https://docs.langchain.com/oss/python/langgraph/memory",
|
||||
"how-tos/memory/add-memory.md": "https://docs.langchain.com/oss/python/langgraph/add-memory",
|
||||
"agents/context.md": "https://docs.langchain.com/oss/python/langgraph/add-memory",
|
||||
"agents/models.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"concepts/tools.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"how-tos/tool-calling.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"concepts/human_in_the_loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
|
||||
"how-tos/human_in_the_loop/add-human-in-the-loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
|
||||
"concepts/time-travel.md": "https://docs.langchain.com/oss/python/langgraph/persistence",
|
||||
"how-tos/human_in_the_loop/time-travel.md": "https://docs.langchain.com/oss/python/langgraph/use-time-travel",
|
||||
"concepts/subgraphs.md": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs",
|
||||
"how-tos/subgraph.md": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs",
|
||||
"concepts/multi_agent.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
|
||||
"agents/multi-agent.md": "https://docs.langchain.com/oss/python/langchain/multi-agent",
|
||||
"how-tos/multi_agent.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
|
||||
"concepts/mcp.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"agents/mcp.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"concepts/tracing.md": "https://docs.langchain.com/oss/python/langgraph/observability",
|
||||
"how-tos/enable-tracing.md": "https://docs.langchain.com/oss/python/langgraph/observability",
|
||||
"agents/evals.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"examples/index.md": "https://docs.langchain.com/oss/python/langgraph/case-studies",
|
||||
"concepts/template_applications.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"tutorials/rag/langgraph_agentic_rag.md": "https://docs.langchain.com/oss/python/langgraph/agentic-rag",
|
||||
"tutorials/multi_agent/agent_supervisor.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"tutorials/sql/sql-agent.md": "https://docs.langchain.com/oss/python/langgraph/sql-agent",
|
||||
"agents/ui.md": "https://docs.langchain.com/oss/python/langgraph/ui",
|
||||
"how-tos/run-id-langsmith.md": "https://docs.langchain.com/oss/python/langgraph/observability",
|
||||
"troubleshooting/errors/index.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
|
||||
"troubleshooting/errors/INVALID_CHAT_HISTORY.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_CHAT_HISTORY",
|
||||
"troubleshooting/errors/INVALID_LICENSE.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
|
||||
"adopters.md": "https://docs.langchain.com/oss/python/langgraph/case-studies",
|
||||
"concepts/faq.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"agents/prebuilt.md": "https://docs.langchain.com/oss/python/langchain/agents",
|
||||
"reference/index.md": "https://reference.langchain.com/python/langgraph/",
|
||||
"reference/graphs.md": "https://reference.langchain.com/python/langgraph/graphs/",
|
||||
"reference/func.md": "https://reference.langchain.com/python/langgraph/func/",
|
||||
"reference/pregel.md": "https://reference.langchain.com/python/langgraph/pregel/",
|
||||
"reference/checkpoints.md": "https://reference.langchain.com/python/langgraph/checkpoints/",
|
||||
"reference/store.md": "https://reference.langchain.com/python/langgraph/store/",
|
||||
"reference/cache.md": "https://reference.langchain.com/python/langgraph/cache/",
|
||||
"reference/types.md": "https://reference.langchain.com/python/langgraph/types/",
|
||||
"reference/runtime.md": "https://reference.langchain.com/python/langgraph/runtime/",
|
||||
"reference/config.md": "https://reference.langchain.com/python/langgraph/config/",
|
||||
"reference/errors.md": "https://reference.langchain.com/python/langgraph/errors/",
|
||||
"reference/constants.md": "https://reference.langchain.com/python/langgraph/constants/",
|
||||
"reference/channels.md": "https://reference.langchain.com/python/langgraph/channels/",
|
||||
"reference/agents.md": "https://reference.langchain.com/python/langgraph/agents/",
|
||||
"reference/supervisor.md": "https://reference.langchain.com/python/langgraph/supervisor/",
|
||||
"reference/swarm.md": "https://reference.langchain.com/python/langgraph/swarm/",
|
||||
"reference/mcp.md": "https://reference.langchain.com/python/langgraph/mcp/",
|
||||
"cloud/reference/sdk/python_sdk_ref.md": "https://reference.langchain.com/python/langsmith/deployment/sdk/",
|
||||
"reference/remote_graph.md": "https://reference.langchain.com/python/langsmith/deployment/remote_graph/",
|
||||
|
||||
# additional exclude-search entries from mkdocs.yml
|
||||
"additional-resources/index.md": "https://docs.langchain.com/oss/python/langchain/overview",
|
||||
"cloud/concepts/cron_jobs.md": "https://docs.langchain.com/langsmith/cron-jobs",
|
||||
"cloud/concepts/data_storage_and_privacy.md": "https://docs.langchain.com/langsmith/data-storage-and-privacy",
|
||||
"cloud/concepts/webhooks.md": "https://docs.langchain.com/langsmith/use-webhooks",
|
||||
"cloud/deployment/cloud.md": "https://docs.langchain.com/langsmith/cloud",
|
||||
"cloud/deployment/custom_docker.md": "https://docs.langchain.com/langsmith/custom-docker",
|
||||
"cloud/deployment/egress.md": "https://docs.langchain.com/langsmith/env-var",
|
||||
"cloud/deployment/graph_rebuild.md": "https://docs.langchain.com/langsmith/graph-rebuild",
|
||||
"cloud/deployment/self_hosted_control_plane.md": "https://docs.langchain.com/langsmith/platform-setup",
|
||||
"cloud/deployment/self_hosted_data_plane.md": "https://docs.langchain.com/langsmith/platform-setup",
|
||||
"cloud/deployment/semantic_search.md": "https://docs.langchain.com/langsmith/semantic-search",
|
||||
"cloud/deployment/setup_javascript.md": "https://docs.langchain.com/langsmith/setup-javascript",
|
||||
"cloud/deployment/setup_pyproject.md": "https://docs.langchain.com/langsmith/setup-pyproject",
|
||||
"cloud/deployment/setup.md": "https://docs.langchain.com/langsmith/setup-app-requirements-txt",
|
||||
"cloud/deployment/standalone_container.md": "https://docs.langchain.com/langsmith/docker",
|
||||
"cloud/how-tos/add-human-in-the-loop.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop",
|
||||
"cloud/how-tos/background_run.md": "https://docs.langchain.com/langsmith/background-run",
|
||||
"cloud/how-tos/clone_traces_studio.md": "https://docs.langchain.com/langsmith/observability",
|
||||
"cloud/how-tos/configurable_headers.md": "https://docs.langchain.com/langsmith/configurable-headers",
|
||||
"cloud/how-tos/configuration_cloud.md": "https://docs.langchain.com/langsmith/configuration-cloud",
|
||||
"cloud/how-tos/cron_jobs.md": "https://docs.langchain.com/langsmith/cron-jobs",
|
||||
"cloud/how-tos/datasets_studio.md": "https://docs.langchain.com/langsmith/use-studio",
|
||||
"cloud/how-tos/enqueue_concurrent.md": "https://docs.langchain.com/langsmith/enqueue-concurrent",
|
||||
"cloud/how-tos/generative_ui_react.md": "https://docs.langchain.com/langsmith/generative-ui-react",
|
||||
"cloud/how-tos/human_in_the_loop_time_travel.md": "https://docs.langchain.com/langsmith/human-in-the-loop-time-travel",
|
||||
"cloud/how-tos/interrupt_concurrent.md": "https://docs.langchain.com/langsmith/interrupt-concurrent",
|
||||
"cloud/how-tos/invoke_studio.md": "https://docs.langchain.com/langsmith/use-studio",
|
||||
"cloud/how-tos/iterate_graph_studio.md": "https://docs.langchain.com/langsmith/use-studio",
|
||||
"cloud/how-tos/reject_concurrent.md": "https://docs.langchain.com/langsmith/reject-concurrent",
|
||||
"cloud/how-tos/rollback_concurrent.md": "https://docs.langchain.com/langsmith/rollback-concurrent",
|
||||
"cloud/how-tos/same-thread.md": "https://docs.langchain.com/langsmith/same-thread",
|
||||
"cloud/how-tos/stateless_runs.md": "https://docs.langchain.com/langsmith/stateless-runs",
|
||||
"cloud/how-tos/streaming.md": "https://docs.langchain.com/langsmith/streaming",
|
||||
"cloud/how-tos/studio/manage_assistants.md": "https://docs.langchain.com/langsmith/use-studio",
|
||||
"cloud/how-tos/studio/quick_start.md": "https://docs.langchain.com/langsmith/quick-start-studio",
|
||||
"cloud/how-tos/studio/run_evals.md": "https://docs.langchain.com/langsmith/observability",
|
||||
"cloud/how-tos/threads_studio.md": "https://docs.langchain.com/langsmith/use-threads",
|
||||
"cloud/how-tos/use_stream_react.md": "https://docs.langchain.com/langsmith/use-stream-react",
|
||||
"cloud/how-tos/use_threads.md": "https://docs.langchain.com/langsmith/use-threads",
|
||||
"cloud/how-tos/webhooks.md": "https://docs.langchain.com/langsmith/use-webhooks",
|
||||
"cloud/quick_start.md": "https://docs.langchain.com/langsmith/deployment-quickstart",
|
||||
"cloud/reference/api/api_ref_control_plane.md": "https://docs.langchain.com/langsmith/api-ref-control-plane",
|
||||
"cloud/reference/api/api_ref.md": "https://docs.langchain.com/langsmith/server-api-ref",
|
||||
"cloud/reference/cli.md": "https://docs.langchain.com/langsmith/cli",
|
||||
"cloud/reference/env_var.md": "https://docs.langchain.com/langsmith/env-var",
|
||||
"cloud/reference/langgraph_server_changelog.md": "https://docs.langchain.com/langsmith/agent-server-changelog",
|
||||
"cloud/reference/sdk/js_ts_sdk_ref.md": "https://reference.langchain.com/javascript/modules/langsmith.html",
|
||||
"concepts/application_structure.md": "https://docs.langchain.com/langsmith/application-structure",
|
||||
"concepts/assistants.md": "https://docs.langchain.com/langsmith/assistants",
|
||||
"concepts/auth.md": "https://docs.langchain.com/langsmith/auth",
|
||||
"concepts/deployment_options.md": "https://docs.langchain.com/langsmith/deployments",
|
||||
"concepts/double_texting.md": "https://docs.langchain.com/langsmith/double-texting",
|
||||
"concepts/faq.md": "https://docs.langchain.com/langsmith/faq",
|
||||
"concepts/langgraph_cli.md": "https://docs.langchain.com/langsmith/cli",
|
||||
"concepts/langgraph_cloud.md": "https://docs.langchain.com/langsmith/cloud",
|
||||
"concepts/langgraph_components.md": "https://docs.langchain.com/langsmith/components",
|
||||
"concepts/langgraph_control_plane.md": "https://docs.langchain.com/langsmith/control-plane",
|
||||
"concepts/langgraph_data_plane.md": "https://docs.langchain.com/langsmith/data-plane",
|
||||
"concepts/langgraph_platform.md": "https://docs.langchain.com/langsmith/home",
|
||||
"concepts/langgraph_self_hosted_control_plane.md": "https://docs.langchain.com/langsmith/platform-setup",
|
||||
"concepts/langgraph_self_hosted_data_plane.md": "https://docs.langchain.com/langsmith/platform-setup",
|
||||
"concepts/langgraph_server.md": "https://docs.langchain.com/langsmith/agent-server",
|
||||
"concepts/langgraph_standalone_container.md": "https://docs.langchain.com/langsmith/docker",
|
||||
"concepts/langgraph_studio.md": "https://docs.langchain.com/langsmith/studio",
|
||||
"concepts/plans.md": "https://docs.langchain.com/langsmith/home",
|
||||
"concepts/scalability_and_resilience.md": "https://docs.langchain.com/langsmith/scalability-and-resilience",
|
||||
"concepts/sdk.md": "https://docs.langchain.com/langsmith/sdk",
|
||||
"concepts/server-mcp.md": "https://docs.langchain.com/langsmith/server-mcp",
|
||||
"concepts/template_applications.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"concepts/why-langgraph.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"examples/index.md": "https://docs.langchain.com/oss/python/langgraph/case-studies",
|
||||
"guides/index.md": "https://docs.langchain.com/oss/python/langchain/overview",
|
||||
"how-tos/auth/custom_auth.md": "https://docs.langchain.com/langsmith/custom-auth",
|
||||
"how-tos/auth/openapi_security.md": "https://docs.langchain.com/langsmith/openapi-security",
|
||||
"how-tos/autogen-integration.md": "https://docs.langchain.com/langsmith/autogen-integration",
|
||||
"how-tos/http/custom_lifespan.md": "https://docs.langchain.com/langsmith/custom-lifespan",
|
||||
"how-tos/http/custom_middleware.md": "https://docs.langchain.com/langsmith/custom-middleware",
|
||||
"how-tos/http/custom_routes.md": "https://docs.langchain.com/langsmith/custom-routes",
|
||||
"how-tos/ttl/configure_ttl.md": "https://docs.langchain.com/langsmith/configure-ttl",
|
||||
"how-tos/use-remote-graph.md": "https://docs.langchain.com/langsmith/use-remote-graph",
|
||||
"index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"snippets/chat_model_tabs.md": "https://docs.langchain.com/oss/python/langchain/overview",
|
||||
"troubleshooting/errors/GRAPH_RECURSION_LIMIT.md": "https://docs.langchain.com/oss/python/langgraph/GRAPH_RECURSION_LIMIT",
|
||||
"troubleshooting/errors/index.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
|
||||
"troubleshooting/errors/INVALID_CHAT_HISTORY.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_CHAT_HISTORY",
|
||||
"troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_CONCURRENT_GRAPH_UPDATE",
|
||||
"troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_GRAPH_NODE_RETURN_VALUE",
|
||||
"troubleshooting/errors/INVALID_LICENSE.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
|
||||
"troubleshooting/errors/MULTIPLE_SUBGRAPHS.md": "https://docs.langchain.com/oss/python/langgraph/MULTIPLE_SUBGRAPHS",
|
||||
"troubleshooting/studio.md": "https://docs.langchain.com/langsmith/troubleshooting-studio",
|
||||
"tutorials/auth/add_auth_server.md": "https://docs.langchain.com/langsmith/add-auth-server",
|
||||
"tutorials/auth/getting_started.md": "https://docs.langchain.com/langsmith/auth",
|
||||
"tutorials/auth/resource_auth.md": "https://docs.langchain.com/langsmith/resource-auth",
|
||||
"agents/agents.md": "https://docs.langchain.com/oss/python/langchain/agents",
|
||||
"concepts/why-langgraph.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"tutorials/langsmith/local-server.md": "https://docs.langchain.com/oss/python/langgraph/local-server",
|
||||
"tutorials/workflows.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"concepts/agentic_concepts.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"guides/index.md": "https://docs.langchain.com/oss/python/langchain/overview",
|
||||
"agents/overview.md": "https://docs.langchain.com/oss/python/langchain/agents",
|
||||
"concepts/agentic_concepts.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"agents/run_agents.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
|
||||
"concepts/low_level.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
|
||||
"how-tos/graph-api.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
|
||||
"concepts/functional_api.md": "https://docs.langchain.com/oss/python/langgraph/functional-api",
|
||||
"how-tos/use-functional-api.md": "https://docs.langchain.com/oss/python/langgraph/functional-api",
|
||||
"concepts/pregel.md": "https://docs.langchain.com/oss/python/langgraph/pregel",
|
||||
"concepts/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"how-tos/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
|
||||
"concepts/persistence.md": "https://docs.langchain.com/oss/python/langgraph/persistence",
|
||||
"concepts/durable_execution.md": "https://docs.langchain.com/oss/python/langgraph/durable-execution",
|
||||
"concepts/memory.md": "https://docs.langchain.com/oss/python/langgraph/memory",
|
||||
"how-tos/memory/add-memory.md": "https://docs.langchain.com/oss/python/langgraph/add-memory",
|
||||
"agents/context.md": "https://docs.langchain.com/oss/python/langgraph/add-memory",
|
||||
"agents/models.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"concepts/tools.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"how-tos/tool-calling.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"concepts/human_in_the_loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
|
||||
"how-tos/human_in_the_loop/add-human-in-the-loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
|
||||
"concepts/time-travel.md": "https://docs.langchain.com/oss/python/langgraph/persistence",
|
||||
"how-tos/human_in_the_loop/time-travel.md": "https://docs.langchain.com/oss/python/langgraph/use-time-travel",
|
||||
"concepts/subgraphs.md": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs",
|
||||
"how-tos/subgraph.md": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs",
|
||||
"concepts/multi_agent.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
|
||||
"agents/multi-agent.md": "https://docs.langchain.com/oss/python/langchain/multi-agent",
|
||||
"how-tos/multi_agent.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
|
||||
"concepts/mcp.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"agents/mcp.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"concepts/tracing.md": "https://docs.langchain.com/oss/python/langgraph/observability",
|
||||
"how-tos/enable-tracing.md": "https://docs.langchain.com/oss/python/langgraph/observability",
|
||||
"agents/evals.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"examples/index.md": "https://docs.langchain.com/oss/python/langgraph/case-studies",
|
||||
"concepts/template_applications.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"tutorials/rag/langgraph_agentic_rag.md": "https://docs.langchain.com/oss/python/langgraph/agentic-rag",
|
||||
"tutorials/multi_agent/agent_supervisor.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
|
||||
"tutorials/sql/sql-agent.md": "https://docs.langchain.com/oss/python/langgraph/sql-agent",
|
||||
"agents/ui.md": "https://docs.langchain.com/oss/python/langgraph/ui",
|
||||
"how-tos/run-id-langsmith.md": "https://docs.langchain.com/oss/python/langgraph/observability",
|
||||
"troubleshooting/errors/index.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
|
||||
"troubleshooting/errors/GRAPH_RECURSION_LIMIT.md": "https://docs.langchain.com/oss/python/langgraph/GRAPH_RECURSION_LIMIT",
|
||||
"troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_CONCURRENT_GRAPH_UPDATE",
|
||||
"troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_GRAPH_NODE_RETURN_VALUE",
|
||||
"troubleshooting/errors/MULTIPLE_SUBGRAPHS.md": "https://docs.langchain.com/oss/python/langgraph/MULTIPLE_SUBGRAPHS",
|
||||
"troubleshooting/errors/INVALID_CHAT_HISTORY.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_CHAT_HISTORY",
|
||||
"troubleshooting/errors/INVALID_LICENSE.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
|
||||
"adopters.md": "https://docs.langchain.com/oss/python/langgraph/case-studies",
|
||||
"concepts/faq.md": "https://docs.langchain.com/oss/python/langgraph/overview",
|
||||
"agents/prebuilt.md": "https://docs.langchain.com/oss/python/langchain/agents",
|
||||
"how-tos/wait-user-input-functional.ipynb": "how-tos/use-functional-api.md",
|
||||
"how-tos/review-tool-calls-functional.ipynb": "how-tos/use-functional-api.md",
|
||||
"how-tos/create-react-agent-hitl.ipynb": "how-tos/human_in_the_loop/add-human-in-the-loop.md",
|
||||
"agents/human-in-the-loop.md": "how-tos/human_in_the_loop/add-human-in-the-loop.md",
|
||||
}
|
||||
|
||||
|
||||
@@ -500,7 +172,31 @@ def _add_path_to_code_blocks(markdown: str, page: Page) -> str:
|
||||
return code_block_pattern.sub(replace_code_block_header, markdown)
|
||||
|
||||
|
||||
# Compiled regex patterns for better performance and readability
|
||||
def _resolve_cross_references(md_text: str, link_map: dict[str, str]) -> str:
|
||||
"""Replace [title][identifier] with [title](url) using language-specific link_map.
|
||||
|
||||
Args:
|
||||
md_text: The markdown text to process.
|
||||
link_map: mapping of identifier to URL.
|
||||
|
||||
Returns:
|
||||
The processed markdown text with cross-references resolved.
|
||||
"""
|
||||
# Pattern to match [title][identifier]
|
||||
pattern = re.compile(r"\[([^\]]+)\]\[([^\]]+)\]")
|
||||
|
||||
def replace_reference(match: re.Match) -> str:
|
||||
"""Replace the matched reference with the corresponding URL."""
|
||||
title, identifier = match.group(1), match.group(2)
|
||||
url = link_map.get(identifier)
|
||||
|
||||
if url:
|
||||
return f"[{title}]({url})"
|
||||
else:
|
||||
# Leave it unchanged if not found
|
||||
return match.group(0)
|
||||
|
||||
return pattern.sub(replace_reference, md_text)
|
||||
|
||||
|
||||
def _apply_conditional_rendering(md_text: str, target_language: str) -> str:
|
||||
@@ -510,7 +206,7 @@ def _apply_conditional_rendering(md_text: str, target_language: str) -> str:
|
||||
pattern = re.compile(
|
||||
r"(?P<indent>[ \t]*):::(?P<language>\w+)\s*\n"
|
||||
r"(?P<content>((?:.*\n)*?))" # Capture the content inside the block
|
||||
r"(?P=indent)[ \t]*:::" # Match closing with the same indentation + any additional whitespace
|
||||
r"(?P=indent):::" # Match closing with the same indentation
|
||||
)
|
||||
|
||||
def replace_conditional_blocks(match: re.Match) -> str:
|
||||
@@ -595,7 +291,7 @@ def _highlight_code_blocks(markdown: str) -> str:
|
||||
opening_fence += f" {attributes}"
|
||||
|
||||
if highlighted_lines:
|
||||
opening_fence += f' hl_lines="{" ".join(highlighted_lines)}"'
|
||||
opening_fence += f" hl_lines=\"{' '.join(highlighted_lines)}\""
|
||||
|
||||
return (
|
||||
# The indent and opening fence
|
||||
@@ -610,19 +306,10 @@ def _highlight_code_blocks(markdown: str) -> str:
|
||||
return markdown
|
||||
|
||||
|
||||
def _save_page_output(markdown: str, output_path: str):
|
||||
"""Save markdown content to a file, creating parent directories if needed.
|
||||
TARGET_LANGUAGE = os.environ.get("TARGET_LANGUAGE", "python")
|
||||
|
||||
Args:
|
||||
markdown: The markdown content to save
|
||||
output_path: The file path to save to
|
||||
"""
|
||||
# Create parent directories recursively if they don't exist
|
||||
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
||||
|
||||
# Write the markdown content to the file
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
f.write(markdown)
|
||||
if TARGET_LANGUAGE not in {"python", "js"}:
|
||||
raise ValueError(f"TARGET_LANGUAGE must be 'python' or 'js', got {TARGET_LANGUAGE}")
|
||||
|
||||
|
||||
def _on_page_markdown_with_config(
|
||||
@@ -640,14 +327,6 @@ def _on_page_markdown_with_config(
|
||||
# logger.info("Processing Jupyter notebook: %s", page.file.src_path)
|
||||
markdown = convert_notebook(page.file.abs_src_path)
|
||||
|
||||
target_language = kwargs.get(
|
||||
"target_language",
|
||||
os.environ.get("TARGET_LANGUAGE", "python")
|
||||
)
|
||||
|
||||
# Apply cross-reference preprocessing to all markdown content
|
||||
markdown = _replace_autolinks(markdown, page.file.src_path, default_scope=target_language)
|
||||
|
||||
# Append API reference links to code blocks
|
||||
if add_api_references:
|
||||
markdown = update_markdown_with_imports(markdown, page.file.abs_src_path)
|
||||
@@ -655,7 +334,17 @@ def _on_page_markdown_with_config(
|
||||
markdown = _highlight_code_blocks(markdown)
|
||||
|
||||
# Apply conditional rendering for code blocks
|
||||
markdown = _apply_conditional_rendering(markdown, target_language)
|
||||
markdown = _apply_conditional_rendering(markdown, TARGET_LANGUAGE)
|
||||
if TARGET_LANGUAGE == "js":
|
||||
markdown = _resolve_cross_references(markdown, JS_LINK_MAP)
|
||||
elif TARGET_LANGUAGE == "python":
|
||||
# Via a dedicated plugin
|
||||
pass
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unsupported target language: {TARGET_LANGUAGE}. "
|
||||
"Supported languages are 'python' and 'js'."
|
||||
)
|
||||
|
||||
# Add file path as an attribute to code blocks that are executable.
|
||||
# This file path is used to associate fixtures with the executable code
|
||||
@@ -670,20 +359,12 @@ def _on_page_markdown_with_config(
|
||||
|
||||
|
||||
def on_page_markdown(markdown: str, page: Page, **kwargs: Dict[str, Any]):
|
||||
finalized_markdown = _on_page_markdown_with_config(
|
||||
return _on_page_markdown_with_config(
|
||||
markdown,
|
||||
page,
|
||||
add_api_references=True,
|
||||
**kwargs,
|
||||
)
|
||||
page.meta["original_markdown"] = finalized_markdown
|
||||
|
||||
output_path = os.environ.get("MD_OUTPUT_PATH")
|
||||
if output_path:
|
||||
file_path = os.path.join(output_path, page.file.src_path)
|
||||
_save_page_output(finalized_markdown, file_path)
|
||||
|
||||
return finalized_markdown
|
||||
|
||||
|
||||
# redirects
|
||||
@@ -754,182 +435,34 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
||||
return html # fallback if no <body> found
|
||||
|
||||
|
||||
def _inject_markdown_into_html(html: str, page: Page) -> str:
|
||||
"""Inject the original markdown content into the HTML page as JSON."""
|
||||
original_markdown = page.meta.get("original_markdown", "")
|
||||
if not original_markdown:
|
||||
return html
|
||||
markdown_data = {
|
||||
"markdown": original_markdown,
|
||||
"title": page.title or "Page Content",
|
||||
"url": page.url or "",
|
||||
}
|
||||
|
||||
# Properly escape the JSON for HTML
|
||||
json_content = json.dumps(markdown_data, ensure_ascii=False)
|
||||
|
||||
json_content = (
|
||||
json_content.replace("</", "\\u003c/")
|
||||
.replace("<script", "\\u003cscript")
|
||||
.replace("</script", "\\u003c/script")
|
||||
)
|
||||
|
||||
script_content = (
|
||||
f'<script id="page-markdown-content" '
|
||||
f'type="application/json">{json_content}</script>'
|
||||
)
|
||||
|
||||
# Insert before </head> if it exists, otherwise before </body>
|
||||
if "</head>" not in html:
|
||||
raise ValueError(
|
||||
"HTML does not contain </head> tag. Cannot inject markdown content."
|
||||
)
|
||||
return html.replace("</head>", f"{script_content}</head>")
|
||||
|
||||
|
||||
def on_post_page(html: str, page: Page, config: MkDocsConfig) -> str:
|
||||
def on_post_page(output: str, page: Page, config: MkDocsConfig) -> str:
|
||||
"""Inject Google Tag Manager noscript tag immediately after <body>.
|
||||
|
||||
Args:
|
||||
html: The HTML output of the page.
|
||||
output: The HTML output of the page.
|
||||
page: The page instance.
|
||||
config: The MkDocs configuration object.
|
||||
|
||||
Returns:
|
||||
modified HTML output with GTM code injected.
|
||||
"""
|
||||
html = _inject_markdown_into_html(html, page)
|
||||
return _inject_gtm(html)
|
||||
return _inject_gtm(output)
|
||||
|
||||
|
||||
# Create HTML files for redirects after site dir has been built
|
||||
def on_post_build(config):
|
||||
use_directory_urls = config.get("use_directory_urls")
|
||||
site_dir = config["site_dir"]
|
||||
|
||||
# Track which paths have explicit redirects
|
||||
redirected_paths = set()
|
||||
|
||||
# Collect all existing HTML files in the site
|
||||
all_html_files = set()
|
||||
for root, dirs, files in os.walk(site_dir):
|
||||
for file in files:
|
||||
if file.endswith(".html"):
|
||||
# Get relative path from site_dir
|
||||
html_path = os.path.relpath(os.path.join(root, file), site_dir)
|
||||
# Normalize path separators to forward slashes
|
||||
html_path = html_path.replace(os.sep, "/")
|
||||
all_html_files.add(html_path)
|
||||
|
||||
# Process explicit redirects from REDIRECT_MAP
|
||||
for page_old, page_new in REDIRECT_MAP.items():
|
||||
# Convert .ipynb to .md for path calculation
|
||||
page_old = page_old.replace(".ipynb", ".md")
|
||||
|
||||
# Calculate the HTML path for the old page (whether it exists or not)
|
||||
if use_directory_urls:
|
||||
# With directory URLs: /path/to/page/ becomes /path/to/page/index.html
|
||||
if page_old.endswith(".md"):
|
||||
old_html_path = page_old[:-3] + "/index.html"
|
||||
else:
|
||||
old_html_path = page_old + "/index.html"
|
||||
else:
|
||||
# Without directory URLs: /path/to/page.md becomes /path/to/page.html
|
||||
if page_old.endswith(".md"):
|
||||
old_html_path = page_old[:-3] + ".html"
|
||||
else:
|
||||
old_html_path = page_old + ".html"
|
||||
|
||||
# Track this path as redirected
|
||||
redirected_paths.add(old_html_path)
|
||||
|
||||
if isinstance(page_new, str) and page_new.startswith("http"):
|
||||
# Handle external redirects
|
||||
_write_html(site_dir, old_html_path, page_new)
|
||||
else:
|
||||
# Handle internal redirects
|
||||
page_new = page_new.replace(".ipynb", ".md")
|
||||
page_new_before_hash, hash, suffix = page_new.partition("#")
|
||||
|
||||
# Try to get the new path using File class, but fallback to manual calculation
|
||||
try:
|
||||
new_html_path = File(page_new_before_hash, "", "", True).url
|
||||
new_html_path = (
|
||||
posixpath.relpath(new_html_path, start=posixpath.dirname(old_html_path))
|
||||
+ hash
|
||||
+ suffix
|
||||
)
|
||||
except:
|
||||
# Fallback: calculate relative path manually
|
||||
if use_directory_urls:
|
||||
if page_new_before_hash.endswith(".md"):
|
||||
new_html_path = page_new_before_hash[:-3] + "/"
|
||||
else:
|
||||
new_html_path = page_new_before_hash + "/"
|
||||
else:
|
||||
if page_new_before_hash.endswith(".md"):
|
||||
new_html_path = page_new_before_hash[:-3] + ".html"
|
||||
else:
|
||||
new_html_path = page_new_before_hash + ".html"
|
||||
new_html_path += hash + suffix
|
||||
|
||||
_write_html(site_dir, old_html_path, new_html_path)
|
||||
|
||||
# Create catch-all redirects for any HTML files not explicitly redirected
|
||||
catchall_url = "https://docs.langchain.com/oss/python/langgraph/overview"
|
||||
for html_file in all_html_files:
|
||||
# Skip if this file is already explicitly redirected
|
||||
if html_file in redirected_paths:
|
||||
continue
|
||||
|
||||
# Skip the root index.html (we handle that separately)
|
||||
if html_file == "index.html":
|
||||
continue
|
||||
|
||||
# Skip reference documentation (keep those accessible)
|
||||
if html_file.startswith("reference/"):
|
||||
continue
|
||||
|
||||
# Create redirect for this unmapped file
|
||||
_write_html(site_dir, html_file, catchall_url)
|
||||
|
||||
# Create root index.html redirect
|
||||
root_redirect_html = """<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Redirecting to LangGraph Documentation</title>
|
||||
<link rel="canonical" href="https://docs.langchain.com/oss/python/langgraph/overview">
|
||||
<meta name="robots" content="noindex">
|
||||
<script>var anchor=window.location.hash.substr(1);location.href="https://docs.langchain.com/oss/python/langgraph/overview"+(anchor?"#"+anchor:"")</script>
|
||||
<meta http-equiv="refresh" content="0; url=https://docs.langchain.com/oss/python/langgraph/overview">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Documentation has moved</h1>
|
||||
<p>The LangGraph documentation has moved to <a href="https://docs.langchain.com/oss/python/langgraph/overview">docs.langchain.com</a>.</p>
|
||||
<p>Redirecting you now...</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
root_index_path = os.path.join(site_dir, "index.html")
|
||||
with open(root_index_path, "w", encoding="utf-8") as f:
|
||||
f.write(root_redirect_html)
|
||||
|
||||
# Create server-side catch-all redirect file for Netlify/Cloudflare Pages
|
||||
# This handles any pages not explicitly mapped in REDIRECT_MAP
|
||||
# Note: This won't work on GitHub Pages, but kept for potential future use
|
||||
redirects_content = """# Netlify/Cloudflare Pages redirect rules
|
||||
# Specific redirects are handled by individual HTML redirect pages
|
||||
# This is the catch-all for any unmapped pages
|
||||
|
||||
# Exclude reference docs from catch-all
|
||||
/reference/* 200
|
||||
|
||||
# Catch-all: redirect any page not explicitly mapped
|
||||
/* https://docs.langchain.com/oss/python/langgraph/overview 301
|
||||
"""
|
||||
|
||||
redirects_path = os.path.join(site_dir, "_redirects")
|
||||
with open(redirects_path, "w", encoding="utf-8") as f:
|
||||
f.write(redirects_content)
|
||||
page_new = page_new.replace(".ipynb", ".md")
|
||||
page_new_before_hash, hash, suffix = page_new.partition("#")
|
||||
old_html_path = File(page_old, "", "", use_directory_urls).dest_path.replace(
|
||||
os.sep, "/"
|
||||
)
|
||||
new_html_path = File(page_new_before_hash, "", "", True).url
|
||||
new_html_path = (
|
||||
posixpath.relpath(new_html_path, start=posixpath.dirname(old_html_path))
|
||||
+ hash
|
||||
+ suffix
|
||||
)
|
||||
_write_html(config["site_dir"], old_html_path, new_html_path)
|
||||
|
||||
@@ -20,19 +20,16 @@ class Package(TypedDict):
|
||||
description: str
|
||||
"""A brief description of what the package does."""
|
||||
|
||||
|
||||
class ResolvedPackage(Package):
|
||||
weekly_downloads: int | None
|
||||
"""The weekly download count of the package."""
|
||||
language: str
|
||||
"""The language of the package. (either 'python' or 'js')"""
|
||||
|
||||
|
||||
HERE = pathlib.Path(__file__).parent
|
||||
PACKAGES_FILE = HERE / "packages.yml"
|
||||
PACKAGES = yaml.safe_load(PACKAGES_FILE.read_text())["packages"]
|
||||
|
||||
|
||||
def _get_pypi_downloads(package: Package) -> int:
|
||||
"""Retrieve the weekly download count for a package from PyPIStats."""
|
||||
|
||||
@@ -75,8 +72,7 @@ def _get_pypi_downloads(package: Package) -> int:
|
||||
return sum(entry["downloads"] for entry in sorted_data[:7])
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def _get_npm_downloads(package: Package) -> int:
|
||||
"""Retrieve the weekly download count for a package on the npm registry."""
|
||||
|
||||
@@ -86,18 +82,14 @@ def _get_npm_downloads(package: Package) -> int:
|
||||
npm_response = requests.get(npm_url)
|
||||
npm_response.raise_for_status()
|
||||
except requests.exceptions.HTTPError:
|
||||
raise AssertionError(
|
||||
f"Package {package['name']} does not exist on npm registry"
|
||||
)
|
||||
raise AssertionError(f"Package {package['name']} does not exist on npm registry")
|
||||
|
||||
npm_data = npm_response.json()
|
||||
|
||||
# Retrieve the first publish date using the 'created' timestamp from the 'time' field.
|
||||
created_str = npm_data.get("time", {}).get("created")
|
||||
if created_str is None:
|
||||
raise AssertionError(
|
||||
f"Package {package['name']} has no creation time in registry data"
|
||||
)
|
||||
raise AssertionError(f"Package {package['name']} has no creation time in registry data")
|
||||
# Remove the trailing 'Z' if present and parse the ISO format timestamp
|
||||
first_publish_date = datetime.fromisoformat(created_str.rstrip("Z"))
|
||||
|
||||
@@ -111,10 +103,7 @@ def _get_npm_downloads(package: Package) -> int:
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def _get_weekly_downloads(
|
||||
packages: dict[str, list[Package]], fake: bool
|
||||
) -> list[ResolvedPackage]:
|
||||
def _get_weekly_downloads(packages: dict[str, list[Package]], fake: bool) -> list[ResolvedPackage]:
|
||||
"""Retrieve the weekly download count for a dictionary of python or js packages."""
|
||||
resolved_packages: list[ResolvedPackage] = []
|
||||
|
||||
@@ -142,7 +131,7 @@ def _get_weekly_downloads(
|
||||
num_downloads = _get_npm_downloads(package)
|
||||
else:
|
||||
num_downloads = None
|
||||
|
||||
|
||||
resolved_packages.append(
|
||||
{
|
||||
"name": package["name"],
|
||||
@@ -156,13 +145,12 @@ def _get_weekly_downloads(
|
||||
|
||||
return resolved_packages
|
||||
|
||||
|
||||
def main(output_file: str, fake: bool) -> None:
|
||||
"""Main function to generate package download information.
|
||||
|
||||
Args:
|
||||
output_file: Path to the output YAML file.
|
||||
fake: If `True`, use fake download counts for testing purposes.
|
||||
fake: If True, use fake download counts for testing purposes.
|
||||
"""
|
||||
resolved_packages: list[ResolvedPackage] = _get_weekly_downloads(PACKAGES, fake)
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
[`add_conditional_edges`][langgraph.graph.StateGraph.add_conditional_edges]
|
||||
[add_conditional_edges][langgraph.graph.StateGraph.add_conditional_edges]
|
||||
[`add_edge`][langgraph.graph.StateGraph.add_edge]
|
||||
[add_edge][langgraph.graph.StateGraph.add_edge]
|
||||
[`add_messages`][langgraph.graph.message.add_messages]
|
||||
[add_node][langgraph.graph.StateGraph.add_node]
|
||||
[API reference][langgraph.prebuilt.tool_node.ToolNode]
|
||||
[API reference][toolnode]
|
||||
[`astream()`][langgraph.graph.state.CompiledStateGraph.astream]
|
||||
[`.astream()`][langgraph.pregel.Pregel.astream]
|
||||
[AsyncPostgresSaver][langgraph.checkpoint.postgres.aio.AsyncPostgresSaver]
|
||||
[AsyncSqliteSaver][langgraph.checkpoint.sqlite.aio.AsyncSqliteSaver]
|
||||
[BaseCheckpointSaver][<insert-ref>]
|
||||
[BaseCheckpointSaver][langgraph.checkpoint.base.BaseCheckpointSaver]
|
||||
[BaseStore][langgraph.store.base.BaseStore]
|
||||
[BaseStore.put][<insert-ref>]
|
||||
[BaseStore.put][langgraph.store.base.BaseStore.put]
|
||||
[BinaryOperatorAggregate][<insert-ref>]
|
||||
[BinaryOperatorAggregate][langgraph.channels.BinaryOperatorAggregate]
|
||||
[`CipherProtocol`][langgraph.checkpoint.serde.base.CipherProtocol]
|
||||
[`client.runs.stream`][langgraph_sdk.client.RunsClient.stream]
|
||||
[`client.runs.wait`][langgraph_sdk.client.RunsClient.wait]
|
||||
[`client.threads.get_history`][langgraph_sdk.client.ThreadsClient.get_history]
|
||||
[`client.threads.update_state`][langgraph_sdk.client.ThreadsClient.update_state]
|
||||
[`Command`][<insert-ref>]
|
||||
[`Command`][langgraph.types.Command]
|
||||
[Command][langgraph.types.Command]
|
||||
[CompiledStateGraph][langgraph.graph.state.CompiledStateGraph]
|
||||
[`createReactAgent`][<insert-ref>]
|
||||
[`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]
|
||||
[create_react_agent][langgraph.prebuilt.chat_agent_executor.create_react_agent]
|
||||
[`create_supervisor`][langgraph_supervisor.supervisor.create_supervisor]
|
||||
[`EncryptedSerializer`][langgraph.checkpoint.serde.encrypted.EncryptedSerializer]
|
||||
[`entrypoint.final`][langgraph.func.entrypoint.final]
|
||||
[`entrypoint`][<insert-ref>]
|
||||
[entrypoint][<insert-ref>]
|
||||
[`@entrypoint`][langgraph.func.entrypoint]
|
||||
[`entrypoint`][langgraph.func.entrypoint]
|
||||
[entrypoint()][langgraph.func.entrypoint]
|
||||
[entrypoint][langgraph.func.entrypoint]
|
||||
[finalResult['values']['messages']
|
||||
[`from_pycryptodome_aes`][langgraph.checkpoint.serde.encrypted.EncryptedSerializer.from_pycryptodome_aes]
|
||||
[`getContextVariable`][<insert-ref>]
|
||||
[`getStateHistory()`][<insert-ref>]
|
||||
[`get_state_history()`][langgraph.graph.state.CompiledStateGraph.get_state_history]
|
||||
[get_stream_writer][langgraph.config.get_stream_writer]
|
||||
[`HumanInterrupt`][langgraph.prebuilt.interrupt.HumanInterrupt]
|
||||
[`HumanInterrupt` schema][langgraph.prebuilt.interrupt.HumanInterrupt]
|
||||
[HumanMessage(content=state[\"messages\"][-2]
|
||||
[`InjectedState`][langgraph.prebuilt.InjectedState]
|
||||
[InjectedState][langgraph.prebuilt.InjectedState]
|
||||
[InMemorySaver][langgraph.checkpoint.memory.InMemorySaver]
|
||||
[`interrupt` function][<insert-ref>]
|
||||
[`interrupt` function][langgraph.types.interrupt]
|
||||
[`interrupt()`][langgraph.types.interrupt]
|
||||
[`interrupt`][langgraph.types.interrupt]
|
||||
[interrupt][langgraph.types.interrupt]
|
||||
[`invoke`][<insert-ref>]
|
||||
[`invoke`][langgraph.graph.state.CompiledStateGraph.invoke]
|
||||
[`JsonPlusSerializer`][langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer]
|
||||
[JsonPlusSerializer][langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer]
|
||||
[langgraph.json CLI reference][configuration-file]
|
||||
[LastValue][<insert-ref>]
|
||||
[LastValue][langgraph.channels.LastValue]
|
||||
[MemorySaver][<insert-ref>]
|
||||
[`messagesStateReducer`][<insert-ref>]
|
||||
[PostgresSaver][<insert-ref>]
|
||||
[PostgresSaver][langgraph.checkpoint.postgres.PostgresSaver]
|
||||
[Pregel][<insert-ref>]
|
||||
[Pregel][langgraph.pregel.Pregel]
|
||||
[`Pregel`][langgraph.pregel.Pregel.stream]
|
||||
[`pre_model_hook`][langgraph.prebuilt.chat_agent_executor.create_react_agent]
|
||||
[protocol][langgraph.checkpoint.serde.base.SerializerProtocol]
|
||||
[`Send()`][langgraph.types.Send]
|
||||
[`Send`][langgraph.types.Send]
|
||||
[SerializerProtocol][<insert-ref>]
|
||||
[SerializerProtocol][langgraph.checkpoint.serde.base.SerializerProtocol]
|
||||
[SqliteSaver][<insert-ref>]
|
||||
[SqliteSaver][langgraph.checkpoint.sqlite.SqliteSaver]
|
||||
[`START`][langgraph.constants.START]
|
||||
[StateGraph (Graph API)][<insert-ref>]
|
||||
[StateGraph (Graph API)][langgraph.graph.StateGraph]
|
||||
[StateGraph (Graph API)][langgraph.graph.state.StateGraph]
|
||||
[StateGraph][<insert-ref>]
|
||||
[StateGraph][langgraph.graph.StateGraph]
|
||||
[`.stream()`][<insert-ref>]
|
||||
[`stream()`][<insert-ref>]
|
||||
[`stream`][<insert-ref>]
|
||||
[`stream()`][langgraph.graph.state.CompiledStateGraph.stream]
|
||||
[`stream`][langgraph.graph.state.CompiledStateGraph.stream]
|
||||
[`.stream()`][langgraph.pregel.Pregel.stream]
|
||||
[tasks][<insert-ref>]
|
||||
[tasks][langgraph.func.task]
|
||||
[`ToolNode`][<insert-ref>]
|
||||
[`ToolNode`][langgraph.prebuilt.tool_node.ToolNode]
|
||||
[ToolNode][langgraph.prebuilt.tool_node.ToolNode]
|
||||
[Topic][<insert-ref>]
|
||||
[Topic][langgraph.channels.Topic]
|
||||
[`updateState`][<insert-ref>]
|
||||
[`update_state`][langgraph.graph.state.CompiledStateGraph.update_state]
|
||||
['values']['messages']
|
||||
@@ -1,11 +0,0 @@
|
||||
# Additional resources
|
||||
|
||||
This section contains additional resources for LangGraph.
|
||||
|
||||
- [Community agents](../agents/prebuilt.md): A collection of prebuilt libraries that you can use in your LangGraph applications.
|
||||
- [LangGraph Academy](https://academy.langchain.com/courses/intro-to-langgraph): A collection of courses that teach you how to use LangGraph.
|
||||
- [Case studies](../adopters.md): A collection of case studies that show how LangGraph is used in production.
|
||||
- [FAQ](../concepts/faq.md): A collection of frequently asked questions about LangGraph.
|
||||
- [llms.txt](../llms-txt-overview.md): A list of documentation files in the `llms.txt` format that allow LLMs and agents to access our documentation.
|
||||
- [LangChain Forum](https://forum.langchain.com/): A place to ask questions and get help from other LangGraph users.
|
||||
- [Troubleshooting](../troubleshooting/errors/index.md): A collection of troubleshooting guides for common issues.
|
||||
+6
-23
@@ -8,41 +8,24 @@ This list of companies using LangGraph and their success stories is compiled fro
|
||||
| [AirTop](https://www.airtop.ai/) | Software & Technology (GenAI Native) | Browser automation for AI agents | [Case study, 2024](https://blog.langchain.dev/customers-airtop/) |
|
||||
| [AppFolio](https://www.appfolio.com/) | Real Estate | Copilot for domain-specific task | [Case study, 2024](https://blog.langchain.dev/customers-appfolio/) |
|
||||
| [Athena Intelligence](https://www.athenaintel.com/) | Software & Technology (GenAI Native) | Research & summarization | [Case study, 2024](https://blog.langchain.dev/customers-athena-intelligence/) |
|
||||
| [BlackRock](https://www.blackrock.com/) | Financial Services | Copilot for domain-specific task | [Interrupt talk, 2025](https://youtu.be/oyqeCHFM5U4?feature=shared) |
|
||||
| [Captide](https://www.captide.co/) | Software & Technology (GenAI Native) | Data extraction | [Case study, 2025](https://blog.langchain.dev/how-captide-is-redefining-equity-research-with-agentic-workflows-built-on-langgraph-and-langsmith/) |
|
||||
| [Cisco CX](https://www.cisco.com/site/us/en/services/modern-data-center/index.html?CCID=cc005911&DTID=eivtotr001480&OID=srwsas032775) | Software & Technology | Customer support | [Interrupt Talk, 2025](https://youtu.be/gPhyPRtIMn0?feature=shared) |
|
||||
| [Cisco Outshift](https://outshift.cisco.com/) | Software & Technology | DevOps | [Video story, 2025](https://www.youtube.com/watch?v=htcb-vGR_x0); [Case study, 2025](https://blog.langchain.com/cisco-outshift/); [Blog post, 2025](https://outshift.cisco.com/blog/build-react-agent-application-for-devops-tasks-using-rest-apis) |
|
||||
| [Cisco TAC](https://www.cisco.com/c/en/us/support/index.html) | Software & Technology | Customer support | [Video story, 2025](https://youtu.be/EAj0HBDGqaE?feature=shared) |
|
||||
| [City of Hope](https://www.cityofhope.org/) | Non-profit | Copilot for domain-specific task | [Video story, 2025](https://youtu.be/9ABwtK2gIZU?feature=shared) |
|
||||
| [Cisco Outshift](https://outshift.cisco.com/) | Software & Technology | DevOps | [Blog post, 2025](https://outshift.cisco.com/blog/build-react-agent-application-for-devops-tasks-using-rest-apis) |
|
||||
| [C.H. Robinson](https://www.chrobinson.com/en-us/) | Logistics | Automation | [Case study, 2025](https://blog.langchain.dev/customers-chrobinson/) |
|
||||
| [Definely](https://www.definely.com/) | Legal | Copilot for domain-specific task | [Case study, 2025](https://blog.langchain.com/customers-definely/) |
|
||||
| [Docent Pro](https://docentpro.com/) | Travel | GenAI embedded product experiences | [Case study, 2025](https://blog.langchain.com/customers-docentpro/) |
|
||||
| [Elastic](https://www.elastic.co/) | Software & Technology | Copilot for domain-specific task | [Blog post, 2025](https://www.elastic.co/blog/elastic-security-generative-ai-features) |
|
||||
| [Exa](https://exa.ai/) | Software & Technology (GenAI Native) | Search | [Case study, 2025](https://blog.langchain.com/exa/) |
|
||||
| [GitLab](https://about.gitlab.com/) | Software & Technology | Code generation | [Duo workflow docs](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/duo_workflow/) |
|
||||
| [Harmonic](https://harmonic.ai/) | Software & Technology | Search | [Case study, 2025](https://blog.langchain.com/customers-harmonic/) |
|
||||
| [Inconvo](https://inconvo.ai/?ref=blog.langchain.dev) | Software & Technology | Code generation | [Case study, 2025](https://blog.langchain.dev/customers-inconvo/) |
|
||||
| [Infor](https://infor.com/) | Software & Technology | GenAI embedded product experiences; customer support; copilot | [Case study, 2025](https://blog.langchain.dev/customers-infor/) |
|
||||
| [J.P. Morgan](https://www.jpmorganchase.com/) | Financial Services | Copilot for domain-specific task | [Interrupt talk, 2025](https://youtu.be/yMalr0jiOAc?feature=shared) |
|
||||
| [Klarna](https://www.klarna.com/) | Fintech | Copilot for domain-specific task | [Case study, 2025](https://blog.langchain.dev/customers-klarna/) |
|
||||
| [Komodo Health](https://www.komodohealth.com/) | Healthcare | Copilot for domain-specific task | [Blog post](https://www.komodohealth.com/perspectives/new-gen-ai-assistant-empowers-the-enterprise/) |
|
||||
| [LinkedIn](https://www.linkedin.com/) | Social Media | Code generation; Search & discovery | [Interrupt talk, 2025](https://youtu.be/NmblVxyBhi8?feature=shared); [Blog post, 2025](https://www.linkedin.com/blog/engineering/ai/practical-text-to-sql-for-data-analytics); [Blog post, 2024](https://www.linkedin.com/blog/engineering/generative-ai/behind-the-platform-the-journey-to-create-the-linkedin-genai-application-tech-stack) |
|
||||
| [LinkedIn](https://www.linkedin.com/) | Social Media | Code generation; Search & discovery | [Blog post, 2025](https://www.linkedin.com/blog/engineering/ai/practical-text-to-sql-for-data-analytics); [Blog post, 2024](https://www.linkedin.com/blog/engineering/generative-ai/behind-the-platform-the-journey-to-create-the-linkedin-genai-application-tech-stack) |
|
||||
| [Minimal](https://gominimal.ai/) | E-commerce | Customer support | [Case study, 2025](https://blog.langchain.dev/how-minimal-built-a-multi-agent-customer-support-system-with-langgraph-langsmith/) |
|
||||
| [Modern Treasury](https://www.moderntreasury.com/) | Fintech | GenAI embedded product experiences | [Video story, 2025](https://youtu.be/AwAiffXqaCU?feature=shared) |
|
||||
| [Monday](https://monday.com/) | Software & Technology | GenAI embedded product experiences | [Interrupt talk, 2025](https://blog.langchain.dev/how-minimal-built-a-multi-agent-customer-support-system-with-langgraph-langsmith/) |
|
||||
| [Morningstar](https://www.morningstar.com/) | Financial Services | Research & summarization | [Video story, 2025](https://youtu.be/6LidoFXCJPs?feature=shared) |
|
||||
| [OpenRecovery](https://www.openrecovery.com/) | Healthcare | Copilot for domain-specific task | [Case study, 2024](https://blog.langchain.dev/customers-openrecovery/) |
|
||||
| [Pigment](https://www.pigment.com/) | Fintech | GenAI embedded product experiences | [Video story, 2025](https://youtu.be/5JVSO2KYOmE?feature=shared) |
|
||||
| [Prosper](https://www.prosper.com/) | Fintech | Customer support | [Video story, 2025](https://youtu.be/9RFNOYtkwsc?feature=shared) |
|
||||
| [Qodo](https://www.qodo.ai/) | Software & Technology (GenAI Native) | Code generation | [Blog post, 2025](https://www.qodo.ai/blog/why-we-chose-langgraph-to-build-our-coding-agent/) |
|
||||
| [Rakuten](https://www.rakuten.com/) | E-commerce / Fintech | Copilot for domain-specific task | [Video story, 2025](https://youtu.be/gD1LIjCkuA8?feature=shared); [Blog post, 2025](https://rakuten.today/blog/from-ai-hype-to-real-world-tools-rakuten-teams-up-with-langchain.html) |
|
||||
| [Rakuten](https://www.rakuten.com/) | E-commerce / Fintech | Copilot for domain-specific task | [Blog post, 2025](https://rakuten.today/blog/from-ai-hype-to-real-world-tools-rakuten-teams-up-with-langchain.html) |
|
||||
| [Replit](https://replit.com/) | Software & Technology | Code generation | [Blog post, 2024](https://blog.langchain.dev/customers-replit/); [Breakout agent story, 2024](https://www.langchain.com/breakoutagents/replit); [Fireside chat video, 2024](https://www.youtube.com/watch?v=ViykMqljjxU) |
|
||||
| [Rexera](https://www.rexera.com/) | Real Estate (GenAI Native) | Copilot for domain-specific task | [Case study, 2024](https://blog.langchain.dev/customers-rexera/) |
|
||||
| [Abu Dhabi Government](https://www.tamm.abudhabi/) | Government | Search | [Case study, 2025](https://blog.langchain.com/customers-abu-dhabi-government/) |
|
||||
| [Tradestack](https://www.tradestack.uk/) | Software & Technology (GenAI Native) | Copilot for domain-specific task | [Case study, 2024](https://blog.langchain.dev/customers-tradestack/) |
|
||||
| [Uber](https://www.uber.com/) | Transportation | Developer productivity; Code generation | [Interrupt talk, 2025](https://youtu.be/Bugs0dVcNI8?feature=shared); [Presentation, 2024](https://dpe.org/sessions/ty-smith-adam-huda/this-year-in-ubers-ai-driven-developer-productivity-revolution/); [Video, 2024](https://www.youtube.com/watch?v=8rkA5vWUE4Y) |
|
||||
| [Unify](https://www.unifygtm.com/) | Software & Technology (GenAI Native) | Copilot for domain-specific task | [Interrupt talk, 2025](https://youtu.be/pKk-LfhujwI?feature=shared); [Blog post, 2024](https://blog.langchain.dev/unify-launches-agents-for-account-qualification-using-langgraph-and-langsmith/) |
|
||||
| [Vizient](https://www.vizientinc.com/) | Healthcare | Copilot for domain-specific task | [Video story, 2025](https://www.youtube.com/watch?v=vrjJ6NuyTWA); [Case study, 2025](https://blog.langchain.dev/p/3d2cd58c-13a5-4df9-bd84-7d54ed0ed82c/) |
|
||||
| [Uber](https://www.uber.com/) | Transportation | Developer productivity; Code generation | [Presentation, 2024](https://dpe.org/sessions/ty-smith-adam-huda/this-year-in-ubers-ai-driven-developer-productivity-revolution/); [Video, 2024](https://www.youtube.com/watch?v=8rkA5vWUE4Y) |
|
||||
| [Unify](https://www.unifygtm.com/) | Software & Technology (GenAI Native) | Copilot for domain-specific task | [Blog post, 2024](https://blog.langchain.dev/unify-launches-agents-for-account-qualification-using-langgraph-and-langsmith/) |
|
||||
| [Vizient](https://www.vizientinc.com/) | Healthcare | Copilot for domain-specific task | [Case study, 2025](https://blog.langchain.dev/p/3d2cd58c-13a5-4df9-bd84-7d54ed0ed82c/) |
|
||||
| [Vodafone](https://www.vodafone.com/) | Telecommunications | Code generation; internal search | [Case study, 2025](https://blog.langchain.dev/customers-vodafone/) |
|
||||
| [WebToon](https://www.webtoons.com/en/) | Media & Entertainment | Data extraction | [Case study, 2025](https://blog.langchain.com/customers-webtoon/) |
|
||||
| [11x](https://www.11x.ai/) | Software & Technology (GenAI Native) | Research & outreach | [Interrupt talk, 2025](https://youtu.be/fegwPmaAPQk?feature=shared) |
|
||||
|
||||
@@ -29,7 +29,7 @@ pip install -U langgraph "langchain[anthropic]"
|
||||
|
||||
!!! info
|
||||
|
||||
`langchain[anthropic]` is installed so the agent can call the [model](https://python.langchain.com/docs/integrations/chat/).
|
||||
LangChain is installed so the agent can call the [model](https://python.langchain.com/docs/integrations/chat/).
|
||||
|
||||
:::
|
||||
|
||||
@@ -41,14 +41,14 @@ npm install @langchain/langgraph @langchain/core @langchain/anthropic
|
||||
|
||||
!!! info
|
||||
|
||||
`@langchain/core` `@langchain/anthropic` are installed so the agent can call the [model](https://js.langchain.com/docs/integrations/chat/).
|
||||
LangChain is installed so the agent can call the [model](https://js.langchain.com/docs/integrations/chat/).
|
||||
|
||||
:::
|
||||
|
||||
## 2. Create an agent
|
||||
|
||||
:::python
|
||||
To create an agent, use @[`create_react_agent`][create_react_agent]:
|
||||
To create an agent, use [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]:
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
@@ -69,7 +69,7 @@ agent.invoke(
|
||||
)
|
||||
```
|
||||
|
||||
1. Define a tool for the agent to use. Tools can be defined as vanilla Python functions. For more advanced tool usage and customization, check the [tools](../how-tos/tool-calling.md) page.
|
||||
1. Define a tool for the agent to use. Tools can be defined as vanilla Python functions. For more advanced tool usage and customization, check the [tools](./tools.md) page.
|
||||
2. Provide a language model for the agent to use. To learn more about configuring language models for the agents, check the [models](./models.md) page.
|
||||
3. Provide a list of tools for the model to use.
|
||||
4. Provide a system prompt (instructions) to the language model used by the agent.
|
||||
|
||||
+151
-119
@@ -1,140 +1,45 @@
|
||||
# Context
|
||||
|
||||
**Context engineering** is the practice of building dynamic systems that provide the right information and tools, in the right format, so that an AI application can accomplish a task. Context can be characterized along two key dimensions:
|
||||
**Context engineering** is the practice of building dynamic systems that provide the right information and tools, in the right format, so that a language model can plausibly accomplish a task.
|
||||
|
||||
1. By **mutability**:
|
||||
- **Static context**: Immutable data that doesn't change during execution (e.g., user metadata, database connections, tools)
|
||||
- **Dynamic context**: Mutable data that evolves as the application runs (e.g., conversation history, intermediate results, tool call observations)
|
||||
2. By **lifetime**:
|
||||
- **Runtime context**: Data scoped to a single run or invocation
|
||||
- **Cross-conversation context**: Data that persists across multiple conversations or sessions
|
||||
Context includes _any_ data outside the message list that can shape behavior. This can be:
|
||||
|
||||
!!! tip "Runtime context vs LLM context"
|
||||
- Information passed at runtime, like a `user_id` or API credentials.
|
||||
- Internal state updated during a multi-step reasoning process.
|
||||
- Persistent memory or facts from previous interactions.
|
||||
|
||||
Runtime context refers to local context: data and dependencies your code needs to run. It does **not** refer to:
|
||||
LangGraph provides **three** primary ways to supply context:
|
||||
|
||||
* The LLM context, which is the data passed into the LLM's prompt.
|
||||
* The "context window", which is the maximum number of tokens that can be passed to the LLM.
|
||||
| Type | Description | Mutable? | Lifetime |
|
||||
| ---------------------------------------------------------------------------- | --------------------------------------------- | -------- | ----------------------- |
|
||||
| [**Config**](#config-static-context) | data passed at the start of a run | ❌ | per run |
|
||||
| [**Short-term memory (State)**](#short-term-memory-mutable-context) | dynamic data that can change during execution | ✅ | per run or conversation |
|
||||
| [**Long-term memory (Store)**](#long-term-memory-cross-conversation-context) | data that can be shared between conversations | ✅ | across conversations |
|
||||
|
||||
Runtime context can be used to optimize the LLM context. For example, you can use user metadata
|
||||
in the runtime context to fetch user preferences and feed them into the context window.
|
||||
## Provide runtime context
|
||||
|
||||
LangGraph provides three ways to manage context, which combines the mutability and lifetime dimensions:
|
||||
### Config (static context)
|
||||
|
||||
Config is for immutable data like user metadata or API keys. Use
|
||||
when you have values that don't change mid-run.
|
||||
|
||||
Specify configuration using a key called **"configurable"** which is reserved
|
||||
for this purpose:
|
||||
|
||||
:::python
|
||||
|
||||
| Context type | Description | Mutability | Lifetime | Access method |
|
||||
| ------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ---------- | ------------------ | --------------------------------------- |
|
||||
| [**Static runtime context**](#static-runtime-context) | User metadata, tools, db connections passed at startup | Static | Single run | `context` argument to `invoke`/`stream` |
|
||||
| [**Dynamic runtime context (state)**](#dynamic-runtime-context-state) | Mutable data that evolves during a single run | Dynamic | Single run | LangGraph state object |
|
||||
| [**Dynamic cross-conversation context (store)**](#dynamic-cross-conversation-context-store) | Persistent data shared across conversations | Dynamic | Cross-conversation | LangGraph store |
|
||||
|
||||
## Static runtime context
|
||||
|
||||
**Static runtime context** represents immutable data like user metadata, tools, and database connections that are passed to an application at the start of a run via the `context` argument to `invoke`/`stream`. This data does not change during execution.
|
||||
|
||||
!!! version-added "Added in version 0.6.0: `context` replaces `config['configurable']`"
|
||||
|
||||
Runtime context is now passed to the `context` argument of `invoke`/`stream`,
|
||||
which replaces the previous pattern of passing application configuration to `config['configurable']`.
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ContextSchema:
|
||||
user_name: str
|
||||
|
||||
graph.invoke( # (1)!
|
||||
{"messages": [{"role": "user", "content": "hi!"}]}, # (2)!
|
||||
# highlight-next-line
|
||||
context={"user_name": "John Smith"} # (3)!
|
||||
config={"configurable": {"user_id": "user_123"}} # (3)!
|
||||
)
|
||||
```
|
||||
|
||||
1. This is the invocation of the agent or graph. The `invoke` method runs the underlying graph with the provided input.
|
||||
2. This example uses messages as an input, which is common, but your application may use different input structures.
|
||||
3. This is where you pass the runtime data. The `context` parameter allows you to provide additional dependencies that the agent can use during its execution.
|
||||
|
||||
=== "Agent prompt"
|
||||
|
||||
```python
|
||||
from langchain_core.messages import AnyMessage
|
||||
from langgraph.runtime import get_runtime
|
||||
from langgraph.prebuilt.chat_agent_executor import AgentState
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
# highlight-next-line
|
||||
def prompt(state: AgentState) -> list[AnyMessage]:
|
||||
runtime = get_runtime(ContextSchema)
|
||||
system_msg = f"You are a helpful assistant. Address the user as {runtime.context.user_name}."
|
||||
return [{"role": "system", "content": system_msg}] + state["messages"]
|
||||
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
prompt=prompt,
|
||||
context_schema=ContextSchema
|
||||
)
|
||||
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
context={"user_name": "John Smith"}
|
||||
)
|
||||
```
|
||||
|
||||
* See [Agents](../agents/agents.md) for details.
|
||||
|
||||
=== "Workflow node"
|
||||
|
||||
```python
|
||||
from langgraph.runtime import Runtime
|
||||
|
||||
# highlight-next-line
|
||||
def node(state: State, runtime: Runtime[ContextSchema]):
|
||||
user_name = runtime.context.user_name
|
||||
...
|
||||
```
|
||||
|
||||
* See [the Graph API](https://langchain-ai.github.io/langgraph/how-tos/graph-api/#add-runtime-configuration) for details.
|
||||
|
||||
=== "In a tool"
|
||||
|
||||
```python
|
||||
from langgraph.runtime import get_runtime
|
||||
|
||||
@tool
|
||||
# highlight-next-line
|
||||
def get_user_email() -> str:
|
||||
"""Retrieve user information based on user ID."""
|
||||
# simulate fetching user info from a database
|
||||
runtime = get_runtime(ContextSchema)
|
||||
email = get_user_email_from_db(runtime.context.user_name)
|
||||
return email
|
||||
```
|
||||
|
||||
See the [tool calling guide](../how-tos/tool-calling.md#configuration) for details.
|
||||
|
||||
!!! tip
|
||||
|
||||
The `Runtime` object can be used to access static context and other utilities like the active store and stream writer.
|
||||
See the [Runtime][langgraph.runtime.Runtime] documentation for details.
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
|
||||
| Context type | Description | Mutability | Lifetime |
|
||||
| ------------------------------------------------------------------------------------------- | --------------------------------------------- | ---------- | ------------------ |
|
||||
| [**Config**](#config-static-context) | data passed at the start of a run | Static | Single run |
|
||||
| [**Dynamic runtime context (state)**](#dynamic-runtime-context-state) | Mutable data that evolves during a single run | Dynamic | Single run |
|
||||
| [**Dynamic cross-conversation context (store)**](#dynamic-cross-conversation-context-store) | Persistent data shared across conversations | Dynamic | Cross-conversation |
|
||||
|
||||
## Config (static context)
|
||||
|
||||
Config is for immutable data like user metadata or API keys. Use this when you have values that don't change mid-run.
|
||||
|
||||
Specify configuration using a key called **"configurable"** which is reserved for this purpose.
|
||||
|
||||
```typescript
|
||||
await graph.invoke(
|
||||
// (1)!
|
||||
@@ -146,9 +51,136 @@ await graph.invoke(
|
||||
|
||||
:::
|
||||
|
||||
## Dynamic runtime context (state)
|
||||
1. This is the invocation of the agent or graph. The `invoke` method runs the underlying graph with the provided input.
|
||||
2. This example uses messages as an input, which is common, but your application may use different input structures.
|
||||
3. This is where you pass the configuration data. The `config` parameter allows you to provide additional context that the agent can use during its execution.
|
||||
|
||||
**Dynamic runtime context** represents mutable data that can evolve during a single run and is managed through the LangGraph state object. This includes conversation history, intermediate results, and values derived from tools or LLM outputs. In LangGraph, the state object acts as [short-term memory](../concepts/memory.md) during a run.
|
||||
=== "Agent prompt"
|
||||
|
||||
:::python
|
||||
```python
|
||||
from langchain_core.messages import AnyMessage
|
||||
from langchain_core.runnables import RunnableConfig
|
||||
from langgraph.prebuilt.chat_agent_executor import AgentState
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
# highlight-next-line
|
||||
def prompt(state: AgentState, config: RunnableConfig) -> list[AnyMessage]:
|
||||
user_name = config["configurable"].get("user_name")
|
||||
system_msg = f"You are a helpful assistant. Address the user as {user_name}."
|
||||
return [{"role": "system", "content": system_msg}] + state["messages"]
|
||||
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
prompt=prompt
|
||||
)
|
||||
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
config={"configurable": {"user_name": "John Smith"}}
|
||||
)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import type { BaseMessage } from "@langchain/core/messages";
|
||||
import type { RunnableConfig } from "@langchain/core/runnables";
|
||||
import type { AgentState } from "@langchain/langgraph/prebuilt";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
|
||||
// highlight-next-line
|
||||
const prompt = (state: AgentState, config: RunnableConfig): BaseMessage[] => {
|
||||
const userName = config.configurable?.user_name;
|
||||
const systemMsg = `You are a helpful assistant. Address the user as ${userName}.`;
|
||||
return [{ role: "system", content: systemMsg }, ...state.messages];
|
||||
};
|
||||
|
||||
const agent = createReactAgent({
|
||||
llm: model,
|
||||
tools: [getWeather],
|
||||
prompt,
|
||||
});
|
||||
|
||||
await agent.invoke(
|
||||
{ messages: [{ role: "user", content: "what is the weather in sf" }] },
|
||||
// highlight-next-line
|
||||
{ configurable: { user_name: "John Smith" } }
|
||||
);
|
||||
```
|
||||
:::
|
||||
|
||||
* See [Agents](../agents/agents.md) for details.
|
||||
|
||||
=== "Workflow node"
|
||||
|
||||
:::python
|
||||
```python
|
||||
from langchain_core.runnables import RunnableConfig
|
||||
|
||||
# highlight-next-line
|
||||
def node(state: State, config: RunnableConfig):
|
||||
user_name = config["configurable"].get("user_name")
|
||||
...
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import type { RunnableConfig } from "@langchain/core/runnables";
|
||||
|
||||
// highlight-next-line
|
||||
const node = (state: State, config?: RunnableConfig) => {
|
||||
const userName = config?.configurable?.user_name;
|
||||
// ...
|
||||
};
|
||||
```
|
||||
:::
|
||||
|
||||
* See [the Graph API](https://langchain-ai.github.io/langgraph/how-tos/graph-api/#add-runtime-configuration) for details.
|
||||
|
||||
=== "In a tool"
|
||||
|
||||
:::python
|
||||
```python
|
||||
from langchain_core.runnables import RunnableConfig
|
||||
|
||||
@tool
|
||||
# highlight-next-line
|
||||
def get_user_info(config: RunnableConfig) -> str:
|
||||
"""Retrieve user information based on user ID."""
|
||||
user_id = config["configurable"].get("user_id")
|
||||
return "User is John Smith" if user_id == "user_123" else "Unknown user"
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import type { RunnableConfig } from "@langchain/core/runnables";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
// highlight-next-line
|
||||
const getUserInfo = tool(
|
||||
async (_, config: RunnableConfig): Promise<string> => {
|
||||
const userId = config.configurable?.user_id;
|
||||
return userId === "user_123" ? "User is John Smith" : "Unknown user";
|
||||
},
|
||||
{
|
||||
name: "get_user_info",
|
||||
description: "Retrieve user information based on user ID."
|
||||
}
|
||||
);
|
||||
```
|
||||
:::
|
||||
|
||||
See the [tool calling guide](../how-tos/tool-calling.md#configuration) for details.
|
||||
|
||||
### Short-term memory (mutable context)
|
||||
|
||||
State acts as [short-term memory](../concepts/memory.md) during a run. It holds dynamic data that can evolve during execution, such as values derived from tools or LLM outputs.
|
||||
|
||||
=== "In an agent"
|
||||
|
||||
@@ -301,8 +333,8 @@ await graph.invoke(
|
||||
|
||||
Please see the [memory guide](../how-tos/memory/add-memory.md) for more details on how to enable memory. This is a powerful feature that allows you to persist the agent's state across multiple invocations. Otherwise, the state is scoped only to a single run.
|
||||
|
||||
## Dynamic cross-conversation context (store)
|
||||
### Long-term memory (cross-conversation context)
|
||||
|
||||
**Dynamic cross-conversation context** represents persistent, mutable data that spans across multiple conversations or sessions and is managed through the LangGraph store. This includes user profiles, preferences, and historical interactions. The LangGraph store acts as [long-term memory](../concepts/memory.md#long-term-memory) across multiple runs. This can be used to read or update persistent facts (e.g., user profiles, preferences, prior interactions).
|
||||
For context that spans _across_ conversations or sessions, LangGraph allows access to **long-term memory** via a `store`. This can be used to read or update persistent facts (e.g., user profiles, preferences, prior interactions).
|
||||
|
||||
For more information, see the [Memory guide](../how-tos/memory/add-memory.md).
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
---
|
||||
search:
|
||||
boost: 2
|
||||
tags:
|
||||
- agent
|
||||
hide:
|
||||
- tags
|
||||
---
|
||||
|
||||
# Deployment
|
||||
|
||||
To deploy your LangGraph agent, create and configure a LangGraph app. This setup supports both local development and production deployments.
|
||||
|
||||
Features:
|
||||
|
||||
- 🖥️ Local server for development
|
||||
- 🧩 Studio Web UI for visual debugging
|
||||
- ☁️ Cloud and 🔧 self-hosted deployment options
|
||||
- 📊 LangSmith integration for tracing and observability
|
||||
|
||||
!!! info "Requirements"
|
||||
|
||||
- ✅ You **must** have a [LangSmith account](https://www.langchain.com/langsmith). You can sign up for **free** and get started with the free tier.
|
||||
|
||||
## Create a LangGraph app
|
||||
|
||||
:::python
|
||||
|
||||
```bash
|
||||
pip install -U "langgraph-cli[inmem]"
|
||||
langgraph new path/to/your/app --template new-langgraph-project-python
|
||||
```
|
||||
|
||||
This will create an empty LangGraph project. You can modify it by replacing the code in `src/agent/graph.py` with your agent code. For example:
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
def get_weather(city: str) -> str:
|
||||
"""Get weather for a given city."""
|
||||
return f"It's always sunny in {city}!"
|
||||
|
||||
graph = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
prompt="You are a helpful assistant"
|
||||
)
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
|
||||
```bash
|
||||
npm install -g @langchain/langgraph-cli
|
||||
langgraph new path/to/your/app --template new-langgraph-project-js
|
||||
```
|
||||
|
||||
This will create an empty LangGraph project. You can modify it by replacing the code in `src/agent/graph.ts` with your agent code. For example:
|
||||
|
||||
```typescript
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
const getWeather = tool(
|
||||
(input) => {
|
||||
return `It's always sunny in ${input.city}!`;
|
||||
},
|
||||
{
|
||||
name: "get_weather",
|
||||
description: "Get weather for a given city.",
|
||||
schema: z.object({
|
||||
city: z.string().describe("The city to get weather for"),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
export const graph = createReactAgent({
|
||||
llm: "anthropic:claude-3-5-sonnet-latest",
|
||||
tools: [getWeather],
|
||||
stateModifier: "You are a helpful assistant",
|
||||
});
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::python
|
||||
|
||||
### Install dependencies
|
||||
|
||||
In the root of your new LangGraph app, install the dependencies in `edit` mode so your local changes are used by the server:
|
||||
|
||||
```shell
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### Create an `.env` file
|
||||
|
||||
You will find a `.env.example` in the root of your new LangGraph app. Create
|
||||
a `.env` file in the root of your new LangGraph app and copy the contents of the `.env.example` file into it, filling in the necessary API keys:
|
||||
|
||||
```bash
|
||||
LANGSMITH_API_KEY=lsv2...
|
||||
ANTHROPIC_API_KEY=sk-
|
||||
```
|
||||
|
||||
## Launch LangGraph server locally
|
||||
|
||||
```shell
|
||||
langgraph dev
|
||||
```
|
||||
|
||||
This will start up the LangGraph API server locally. If this runs successfully, you should see something like:
|
||||
|
||||
> Ready!
|
||||
>
|
||||
> - API: [http://localhost:2024](http://localhost:2024/)
|
||||
>
|
||||
> - Docs: http://localhost:2024/docs
|
||||
>
|
||||
> - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
|
||||
|
||||
See this [tutorial](https://langchain-ai.github.io/langgraph/tutorials/langgraph-platform/local-server/) to learn more about running LangGraph app locally.
|
||||
|
||||
## LangGraph Studio Web UI
|
||||
|
||||
LangGraph Studio Web is a specialized UI that you can connect to LangGraph API server to enable visualization, interaction, and debugging of your application locally. Test your graph in the LangGraph Studio Web UI by visiting the URL provided in the output of the `langgraph dev` command.
|
||||
|
||||
> - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
|
||||
|
||||
## Deployment
|
||||
|
||||
Once your LangGraph app is running locally, you can deploy it using LangGraph Platform. Refer to the [deployment options guide](../concepts/deployment_options.md) for detailed instructions on all supported deployment models.
|
||||
@@ -17,7 +17,7 @@ To evaluate your agent's performance you can use `LangSmith` [evaluations](https
|
||||
def evaluator(*, outputs: dict, reference_outputs: dict):
|
||||
# compare agent outputs against reference outputs
|
||||
output_messages = outputs["messages"]
|
||||
reference_messages = reference_outputs["messages"]
|
||||
reference_messages = reference["messages"]
|
||||
score = compare_messages(output_messages, reference_messages)
|
||||
return {"key": "evaluator_score", "score": score}
|
||||
```
|
||||
|
||||
+13
-40
@@ -76,16 +76,14 @@ The `langchain-mcp-adapters` package enables agents to use tools defined across
|
||||
|
||||
=== "In a workflow"
|
||||
|
||||
```python title="Workflow using MCP tools with ToolNode"
|
||||
```python
|
||||
from langchain_mcp_adapters.client import MultiServerMCPClient
|
||||
from langgraph.graph import StateGraph, MessagesState, START
|
||||
from langgraph.prebuilt import ToolNode, tools_condition
|
||||
|
||||
from langchain.chat_models import init_chat_model
|
||||
from langgraph.graph import StateGraph, MessagesState, START, END
|
||||
from langgraph.prebuilt import ToolNode
|
||||
model = init_chat_model("openai:gpt-4.1")
|
||||
|
||||
# Initialize the model
|
||||
model = init_chat_model("anthropic:claude-3-5-sonnet-latest")
|
||||
|
||||
# Set up MCP client
|
||||
client = MultiServerMCPClient(
|
||||
{
|
||||
"math": {
|
||||
@@ -103,47 +101,22 @@ The `langchain-mcp-adapters` package enables agents to use tools defined across
|
||||
)
|
||||
tools = await client.get_tools()
|
||||
|
||||
# Bind tools to model
|
||||
model_with_tools = model.bind_tools(tools)
|
||||
def call_model(state: MessagesState):
|
||||
response = model.bind_tools(tools).invoke(state["messages"])
|
||||
return {"messages": response}
|
||||
|
||||
# Create ToolNode
|
||||
tool_node = ToolNode(tools)
|
||||
|
||||
def should_continue(state: MessagesState):
|
||||
messages = state["messages"]
|
||||
last_message = messages[-1]
|
||||
if last_message.tool_calls:
|
||||
return "tools"
|
||||
return END
|
||||
|
||||
# Define call_model function
|
||||
async def call_model(state: MessagesState):
|
||||
messages = state["messages"]
|
||||
response = await model_with_tools.ainvoke(messages)
|
||||
return {"messages": [response]}
|
||||
|
||||
# Build the graph
|
||||
builder = StateGraph(MessagesState)
|
||||
builder.add_node("call_model", call_model)
|
||||
builder.add_node("tools", tool_node)
|
||||
|
||||
builder.add_node(call_model)
|
||||
builder.add_node(ToolNode(tools))
|
||||
builder.add_edge(START, "call_model")
|
||||
builder.add_conditional_edges(
|
||||
"call_model",
|
||||
should_continue,
|
||||
tools_condition,
|
||||
)
|
||||
builder.add_edge("tools", "call_model")
|
||||
|
||||
# Compile the graph
|
||||
graph = builder.compile()
|
||||
|
||||
# Test the graph
|
||||
math_response = await graph.ainvoke(
|
||||
{"messages": [{"role": "user", "content": "what's (3 + 5) x 12?"}]}
|
||||
)
|
||||
weather_response = await graph.ainvoke(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in nyc?"}]}
|
||||
)
|
||||
math_response = await graph.ainvoke({"messages": "what's (3 + 5) x 12?"})
|
||||
weather_response = await graph.ainvoke({"messages": "what is the weather in nyc?"})
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
@@ -7,7 +7,7 @@ LangGraph provides built-in support for [LLMs (language models)](https://python.
|
||||
:::python
|
||||
Use [`init_chat_model`](https://python.langchain.com/docs/how_to/chat_models_universal_init/) to initialize models:
|
||||
|
||||
{% include-markdown "../../snippets/chat_model_tabs.md" %}
|
||||
{!snippets/chat_model_tabs.md!}
|
||||
:::
|
||||
|
||||
:::js
|
||||
@@ -145,76 +145,6 @@ const agent = createReactAgent({
|
||||
|
||||
:::
|
||||
|
||||
:::python
|
||||
|
||||
### Dynamic model selection
|
||||
|
||||
Pass a callable function to `create_react_agent` to dynamically select the model at runtime. This is useful for scenarios where you want to choose a model based on user input, configuration settings, or other runtime conditions.
|
||||
|
||||
The selector function must return a chat model. If you're using tools, you must bind the tools to the model within the selector function.
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
from typing import Literal
|
||||
from langchain.chat_models import init_chat_model
|
||||
from langchain_core.language_models import BaseChatModel
|
||||
from langchain_core.tools import tool
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
from langgraph.prebuilt.chat_agent_executor import AgentState
|
||||
from langgraph.runtime import Runtime
|
||||
|
||||
@tool
|
||||
def weather() -> str:
|
||||
"""Returns the current weather conditions."""
|
||||
return "It's nice and sunny."
|
||||
|
||||
|
||||
# Define the runtime context
|
||||
@dataclass
|
||||
class CustomContext:
|
||||
provider: Literal["anthropic", "openai"]
|
||||
|
||||
# Initialize models
|
||||
openai_model = init_chat_model("openai:gpt-4o")
|
||||
anthropic_model = init_chat_model("anthropic:claude-sonnet-4-20250514")
|
||||
|
||||
|
||||
# Selector function for model choice
|
||||
def select_model(state: AgentState, runtime: Runtime[CustomContext]) -> BaseChatModel:
|
||||
if runtime.context.provider == "anthropic":
|
||||
model = anthropic_model
|
||||
elif runtime.context.provider == "openai":
|
||||
model = openai_model
|
||||
else:
|
||||
raise ValueError(f"Unsupported provider: {runtime.context.provider}")
|
||||
|
||||
# With dynamic model selection, you must bind tools explicitly
|
||||
return model.bind_tools([weather])
|
||||
|
||||
|
||||
# Create agent with dynamic model selection
|
||||
agent = create_react_agent(select_model, tools=[weather])
|
||||
|
||||
# Invoke with context to select model
|
||||
output = agent.invoke(
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Which model is handling this?",
|
||||
}
|
||||
]
|
||||
},
|
||||
context=CustomContext(provider="openai"),
|
||||
)
|
||||
|
||||
print(output["messages"][-1].text())
|
||||
```
|
||||
|
||||
!!! version-added "Added in version 0.6.0"
|
||||
|
||||
:::
|
||||
|
||||
## Advanced model configuration
|
||||
|
||||
### Disable streaming
|
||||
@@ -351,13 +281,11 @@ If your desired LLM isn't officially supported by LangChain, consider these opti
|
||||
:::python
|
||||
|
||||
1. **Implement a custom LangChain chat model**: Create a model conforming to the [LangChain chat model interface](https://python.langchain.com/docs/how_to/custom_chat_model/). This enables full compatibility with LangGraph's agents and workflows but requires understanding of the LangChain framework.
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
|
||||
1. **Implement a custom LangChain chat model**: Create a model conforming to the [LangChain chat model interface](https://js.langchain.com/docs/how_to/custom_chat/). This enables full compatibility with LangGraph's agents and workflows but requires understanding of the LangChain framework.
|
||||
|
||||
:::
|
||||
|
||||
2. **Direct invocation with custom streaming**: Use your model directly by [adding custom streaming logic](../how-tos/streaming.md#use-with-any-llm) with `StreamWriter`.
|
||||
@@ -373,7 +301,6 @@ If your desired LLM isn't officially supported by LangChain, consider these opti
|
||||
- [Force model to call a specific tool](https://python.langchain.com/docs/how_to/tool_choice/)
|
||||
- [All chat model how-to guides](https://python.langchain.com/docs/how_to/#chat-models)
|
||||
- [Chat model integrations](https://python.langchain.com/docs/integrations/chat/)
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
@@ -384,5 +311,4 @@ If your desired LLM isn't officially supported by LangChain, consider these opti
|
||||
- [Force model to call a specific tool](https://js.langchain.com/docs/how_to/tool_choice/)
|
||||
- [All chat model how-to guides](https://js.langchain.com/docs/how_to/#chat-models)
|
||||
- [Chat model integrations](https://js.langchain.com/docs/integrations/chat/)
|
||||
|
||||
:::
|
||||
|
||||
@@ -317,17 +317,17 @@ To implement handoffs with `create_react_agent`, you need to:
|
||||
|
||||
3. Define a parent graph that contains individual agents as nodes:
|
||||
|
||||
```python
|
||||
from langgraph.graph import StateGraph, MessagesState
|
||||
multi_agent_graph = (
|
||||
StateGraph(MessagesState)
|
||||
.add_node(flight_assistant)
|
||||
.add_node(hotel_assistant)
|
||||
...
|
||||
)
|
||||
```
|
||||
```python
|
||||
from langgraph.graph import StateGraph, MessagesState
|
||||
multi_agent_graph = (
|
||||
StateGraph(MessagesState)
|
||||
.add_node(flight_assistant)
|
||||
.add_node(hotel_assistant)
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
:::
|
||||
:::
|
||||
|
||||
:::js
|
||||
This is used both by `@langchain/langgraph-supervisor` (supervisor hands off to individual agents) and `@langchain/langgraph-swarm` (an individual agent can hand off to other agents).
|
||||
@@ -367,13 +367,13 @@ To implement handoffs with `createReactAgent`, you need to:
|
||||
|
||||
3. Define a parent graph that contains individual agents as nodes:
|
||||
|
||||
```typescript
|
||||
import { StateGraph, MessagesZodState } from "@langchain/langgraph";
|
||||
const multiAgentGraph = new StateGraph(MessagesZodState)
|
||||
.addNode("flight_assistant", flightAssistant)
|
||||
.addNode("hotel_assistant", hotelAssistant)
|
||||
// ...
|
||||
```
|
||||
```typescript
|
||||
import { StateGraph, MessagesZodState } from "@langchain/langgraph";
|
||||
const multiAgentGraph = new StateGraph(MessagesZodState)
|
||||
.addNode("flight_assistant", flightAssistant)
|
||||
.addNode("hotel_assistant", hotelAssistant)
|
||||
// ...
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
@@ -619,12 +619,10 @@ for await (const chunk of multiAgentGraph.stream({
|
||||
3. Name of the agent or node to hand off to.
|
||||
4. Take the agent's messages and **add** them to the parent's **state** as part of the handoff. The next agent will see the parent state.
|
||||
5. Indicate to LangGraph that we need to navigate to agent node in a **parent** multi-agent graph.
|
||||
|
||||
:::
|
||||
:::
|
||||
|
||||
!!! Note
|
||||
|
||||
This handoff implementation assumes that:
|
||||
This handoff implementation assumes that:
|
||||
|
||||
- each agent receives overall message history (across all agents) in the multi-agent system as its input
|
||||
- each agent outputs its internal messages history to the overall message history of the multi-agent system
|
||||
|
||||
@@ -8,9 +8,9 @@ hide:
|
||||
- tags
|
||||
---
|
||||
|
||||
# Agent development using prebuilt components
|
||||
# Agent development with LangGraph
|
||||
|
||||
LangGraph provides both low-level primitives and high-level prebuilt components for building agent-based applications. This section focuses on the prebuilt, ready-to-use components designed to help you construct agentic systems quickly and reliably—without the need to implement orchestration, memory, or human feedback handling from scratch.
|
||||
**LangGraph** provides both low-level primitives and high-level prebuilt components for building agent-based applications. This section focuses on the **prebuilt**, **reusable** components designed to help you construct agentic systems quickly and reliably—without the need to implement orchestration, memory, or human feedback handling from scratch.
|
||||
|
||||
## What is an agent?
|
||||
|
||||
@@ -30,7 +30,7 @@ LangGraph includes several capabilities essential for building robust, productio
|
||||
- [**Memory integration**](../how-tos/memory/add-memory.md): Native support for _short-term_ (session-based) and _long-term_ (persistent across sessions) memory, enabling stateful behaviors in chatbots and assistants.
|
||||
- [**Human-in-the-loop control**](../concepts/human_in_the_loop.md): Execution can pause _indefinitely_ to await human feedback—unlike websocket-based solutions limited to real-time interaction. This enables asynchronous approval, correction, or intervention at any point in the workflow.
|
||||
- [**Streaming support**](../how-tos/streaming.md): Real-time streaming of agent state, model tokens, tool outputs, or combined streams.
|
||||
- [**Deployment tooling**](../tutorials/langgraph-platform/local-server.md): Includes infrastructure-free deployment tools. [**LangGraph Platform**](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/) supports testing, debugging, and deployment.
|
||||
- [**Deployment tooling**](./deployment.md): Includes infrastructure-free deployment tools. [**LangGraph Platform**](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/) supports testing, debugging, and deployment.
|
||||
- **[Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/)**: A visual IDE for inspecting and debugging workflows.
|
||||
- Supports multiple [**deployment options**](https://langchain-ai.github.io/langgraph/concepts/deployment_options.md) for production.
|
||||
|
||||
@@ -58,11 +58,11 @@ The high-level components are organized into several packages, each with a speci
|
||||
## Visualize an agent graph
|
||||
|
||||
Use the following tool to visualize the graph generated by
|
||||
@[`create_react_agent`][create_react_agent]
|
||||
[`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]
|
||||
and to view an outline of the corresponding code.
|
||||
It allows you to explore the infrastructure of the agent as defined by the presence of:
|
||||
|
||||
- [`tools`](../how-tos/tool-calling.md): A list of tools (functions, APIs, or other callable objects) that the agent can use to perform tasks.
|
||||
- [`tools`](../agents/tools.md): A list of tools (functions, APIs, or other callable objects) that the agent can use to perform tasks.
|
||||
- [`pre_model_hook`](../how-tos/create-react-agent-manage-message-history.ipynb): A function that is called before the model is invoked. It can be used to condense messages or perform other preprocessing tasks.
|
||||
- `post_model_hook`: A function that is called after the model is invoked. It can be used to implement guardrails, human-in-the-loop flows, or other postprocessing tasks.
|
||||
- [`response_format`](../agents/agents.md#6-configure-structured-output): A data structure used to constrain the type of the final output, e.g., a `pydantic` `BaseModel`.
|
||||
@@ -85,7 +85,7 @@ It allows you to explore the infrastructure of the agent as defined by the prese
|
||||
</div>
|
||||
|
||||
The following code snippet shows how to create the above agent (and underlying graph) with
|
||||
@[`create_react_agent`][create_react_agent]:
|
||||
[`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]:
|
||||
|
||||
<div class="language-python">
|
||||
<pre><code id="agent-code" class="language-python"></code></pre>
|
||||
@@ -159,7 +159,7 @@ function generateCodeSnippet({ tools, pre, post, response }) {
|
||||
if (post) lines.push(" post_model_hook=post_model_hook,");
|
||||
if (response) lines.push(" response_format=ResponseFormat,");
|
||||
|
||||
lines.push(")", "", "# Visualize the graph", "# For Jupyter or GUI environments:", "agent.get_graph().draw_mermaid_png()", "", "# To save PNG to file:", "png_data = agent.get_graph().draw_mermaid_png()", "with open(\"graph.png\", \"wb\") as f:", " f.write(png_data)", "", "# For terminal/ASCII output:", "agent.get_graph().draw_ascii()");
|
||||
lines.push(")", "", "agent.get_graph().draw_mermaid_png()");
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
@@ -208,12 +208,12 @@ The high-level components are organized into several packages, each with a speci
|
||||
|
||||
## Visualize an agent graph
|
||||
|
||||
Use the following tool to visualize the graph generated by @[`createReactAgent`][create_react_agent] and to view an outline of the corresponding code. It allows you to explore the infrastructure of the agent as defined by the presence of:
|
||||
Use the following tool to visualize the graph generated by [`createReactAgent`](/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html) and to view an outline of the corresponding code. It allows you to explore the infrastructure of the agent as defined by the presence of:
|
||||
|
||||
- [`tools`](./tools.md): A list of tools (functions, APIs, or other callable objects) that the agent can use to perform tasks.
|
||||
- `preModelHook`: A function that is called before the model is invoked. It can be used to condense messages or perform other preprocessing tasks.
|
||||
- `postModelHook`: A function that is called after the model is invoked. It can be used to implement guardrails, human-in-the-loop flows, or other postprocessing tasks.
|
||||
- [`responseFormat`](./agents.md#6-configure-structured-output): A data structure used to constrain the type of the final output (via Zod schemas).
|
||||
- [`responseFormat`](./agents.md#structured-output): A data structure used to constrain the type of the final output (via Zod schemas).
|
||||
|
||||
<div class="agent-layout">
|
||||
<div class="agent-graph-features-container">
|
||||
@@ -232,7 +232,7 @@ Use the following tool to visualize the graph generated by @[`createReactAgent`]
|
||||
</div>
|
||||
</div>
|
||||
|
||||
The following code snippet shows how to create the above agent (and underlying graph) with @[`createReactAgent`][create_react_agent]:
|
||||
The following code snippet shows how to create the above agent (and underlying graph) with [`createReactAgent`](/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html):
|
||||
|
||||
<div class="language-typescript">
|
||||
<pre><code id="agent-code" class="language-typescript"></code></pre>
|
||||
|
||||
@@ -10,19 +10,19 @@ below. These libraries can extend LangGraph's functionality in various ways.
|
||||
:::python
|
||||
| Name | GitHub URL | Description | Weekly Downloads | Stars |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| **trustcall** | https://github.com/hinthornw/trustcall | Tenacious tool calling built on LangGraph. | -12345 | 
|
||||
| **breeze-agent** | https://github.com/andrestorres123/breeze-agent | A streamlined research system built inspired on STORM and built on LangGraph. | -12345 | 
|
||||
| **langgraph-supervisor** | https://github.com/langchain-ai/langgraph-supervisor-py | Build supervisor multi-agent systems with LangGraph. | -12345 | 
|
||||
| **langmem** | https://github.com/langchain-ai/langmem | Build agents that learn and adapt from interactions over time. | -12345 | 
|
||||
| **langchain-mcp-adapters** | https://github.com/langchain-ai/langchain-mcp-adapters | Make Anthropic Model Context Protocol (MCP) tools compatible with LangGraph agents. | -12345 | 
|
||||
| **open-deep-research** | https://github.com/langchain-ai/open_deep_research | Open source assistant for iterative web research and report writing. | -12345 | 
|
||||
| **langgraph-swarm** | https://github.com/langchain-ai/langgraph-swarm-py | Build swarm-style multi-agent systems using LangGraph. | -12345 | 
|
||||
| **delve-taxonomy-generator** | https://github.com/andrestorres123/delve | A taxonomy generator for unstructured data | -12345 | 
|
||||
| **nodeology** | https://github.com/xyin-anl/Nodeology | Enable researcher to build scientific workflows easily with simplified interface. | -12345 | 
|
||||
| **langgraph-bigtool** | https://github.com/langchain-ai/langgraph-bigtool | Build LangGraph agents with large numbers of tools. | -12345 | 
|
||||
| **ai-data-science-team** | https://github.com/business-science/ai-data-science-team | An AI-powered data science team of agents to help you perform common data science tasks 10X faster. | -12345 | 
|
||||
| **langgraph-reflection** | https://github.com/langchain-ai/langgraph-reflection | LangGraph agent that runs a reflection step. | -12345 | 
|
||||
| **langgraph-codeact** | https://github.com/langchain-ai/langgraph-codeact | LangGraph implementation of CodeAct agent that generates and executes code instead of tool calling. | -12345 | 
|
||||
| **trustcall** | [hinthornw/trustcall](https://github.com/hinthornw/trustcall) | Tenacious tool calling built on LangGraph. | -12345 | 
|
||||
| **breeze-agent** | [andrestorres123/breeze-agent](https://github.com/andrestorres123/breeze-agent) | A streamlined research system built inspired on STORM and built on LangGraph. | -12345 | 
|
||||
| **langgraph-supervisor** | [langchain-ai/langgraph-supervisor-py](https://github.com/langchain-ai/langgraph-supervisor-py) | Build supervisor multi-agent systems with LangGraph. | -12345 | 
|
||||
| **langmem** | [langchain-ai/langmem](https://github.com/langchain-ai/langmem) | Build agents that learn and adapt from interactions over time. | -12345 | 
|
||||
| **langchain-mcp-adapters** | [langchain-ai/langchain-mcp-adapters](https://github.com/langchain-ai/langchain-mcp-adapters) | Make Anthropic Model Context Protocol (MCP) tools compatible with LangGraph agents. | -12345 | 
|
||||
| **open-deep-research** | [langchain-ai/open_deep_research](https://github.com/langchain-ai/open_deep_research) | Open source assistant for iterative web research and report writing. | -12345 | 
|
||||
| **langgraph-swarm** | [langchain-ai/langgraph-swarm-py](https://github.com/langchain-ai/langgraph-swarm-py) | Build swarm-style multi-agent systems using LangGraph. | -12345 | 
|
||||
| **delve-taxonomy-generator** | [andrestorres123/delve](https://github.com/andrestorres123/delve) | A taxonomy generator for unstructured data | -12345 | 
|
||||
| **nodeology** | [xyin-anl/Nodeology](https://github.com/xyin-anl/Nodeology) | Enable researcher to build scientific workflows easily with simplified interface. | -12345 | 
|
||||
| **langgraph-bigtool** | [langchain-ai/langgraph-bigtool](https://github.com/langchain-ai/langgraph-bigtool) | Build LangGraph agents with large numbers of tools. | -12345 | 
|
||||
| **ai-data-science-team** | [business-science/ai-data-science-team](https://github.com/business-science/ai-data-science-team) | An AI-powered data science team of agents to help you perform common data science tasks 10X faster. | -12345 | 
|
||||
| **langgraph-reflection** | [langchain-ai/langgraph-reflection](https://github.com/langchain-ai/langgraph-reflection) | LangGraph agent that runs a reflection step. | -12345 | 
|
||||
| **langgraph-codeact** | [langchain-ai/langgraph-codeact](https://github.com/langchain-ai/langgraph-codeact) | LangGraph implementation of CodeAct agent that generates and executes code instead of tool calling. | -12345 | 
|
||||
|
||||
## ✨ Contributing Your Library
|
||||
|
||||
@@ -47,10 +47,10 @@ Thanks for contributing! 🚀
|
||||
:::js
|
||||
| Name | GitHub URL | Description | Weekly Downloads | Stars |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| **@langchain/mcp-adapters** | https://github.com/langchain-ai/langchainjs | Make Anthropic Model Context Protocol (MCP) tools compatible with LangGraph agents. | -12345 | 
|
||||
| **@langchain/langgraph-supervisor** | https://github.com/langchain-ai/langgraphjs/tree/main/libs/langgraph-supervisor | Build supervisor multi-agent systems with LangGraph | -12345 | 
|
||||
| **@langchain/langgraph-swarm** | https://github.com/langchain-ai/langgraphjs/tree/main/libs/langgraph-swarm | Build multi-agent swarms with LangGraph | -12345 | 
|
||||
| **@langchain/langgraph-cua** | https://github.com/langchain-ai/langgraphjs/tree/main/libs/langgraph-cua | Build computer use agents with LangGraph | -12345 | 
|
||||
| **@langchain/mcp-adapters** | [langchain-ai/langchainjs](https://github.com/langchain-ai/langchainjs) | Make Anthropic Model Context Protocol (MCP) tools compatible with LangGraph agents. | -12345 | 
|
||||
| **@langchain/langgraph-supervisor** | [langchain-ai/langgraphjs](https://github.com/langchain-ai/langgraphjs) | Build supervisor multi-agent systems with LangGraph | -12345 | 
|
||||
| **@langchain/langgraph-swarm** | [langchain-ai/langgraphjs](https://github.com/langchain-ai/langgraphjs) | Build multi-agent swarms with LangGraph | -12345 | 
|
||||
| **@langchain/langgraph-cua** | [langchain-ai/langgraphjs](https://github.com/langchain-ai/langgraphjs) | Build computer use agents with LangGraph | -12345 | 
|
||||
|
||||
## ✨ Contributing Your Library
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Agents can be executed in two primary modes:
|
||||
:::python
|
||||
=== "Sync invocation"
|
||||
|
||||
```python
|
||||
````python
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
agent = create_react_agent(...)
|
||||
@@ -41,8 +41,8 @@ Agents can be executed in two primary modes:
|
||||
|
||||
=== "Async invocation"
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
````python
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
agent = create_react_agent(...)
|
||||
# highlight-next-line
|
||||
@@ -63,7 +63,7 @@ const response = await agent.invoke({
|
||||
{ "role": "user", "content": "what is the weather in sf" }
|
||||
]
|
||||
});
|
||||
```
|
||||
````
|
||||
|
||||
:::
|
||||
|
||||
@@ -105,25 +105,25 @@ more about [LangChain messages](https://js.langchain.com/docs/concepts/messages/
|
||||
|
||||
!!! tip "Using custom agent state"
|
||||
|
||||
:::python
|
||||
You can provide additional fields defined in your agent's state schema directly in the input dictionary. This allows dynamic behavior based on runtime data or prior tool outputs.
|
||||
See the [context guide](./context.md) for full details.
|
||||
:::
|
||||
:::python
|
||||
You can provide additional fields defined in your agent's state schema directly in the input dictionary. This allows dynamic behavior based on runtime data or prior tool outputs.
|
||||
See the [context guide](./context.md) for full details.
|
||||
:::
|
||||
|
||||
:::js
|
||||
You can provide additional fields defined in your agent's state directly in the state definition. This allows dynamic behavior based on runtime data or prior tool outputs.
|
||||
See the [context guide](./context.md) for full details.
|
||||
:::
|
||||
:::js
|
||||
You can provide additional fields defined in your agent's state directly in the state definition. This allows dynamic behavior based on runtime data or prior tool outputs.
|
||||
See the [context guide](./context.md) for full details.
|
||||
:::
|
||||
|
||||
!!! note
|
||||
|
||||
:::python
|
||||
A string input for `messages` is converted to a [HumanMessage](https://python.langchain.com/docs/concepts/messages/#humanmessage). This behavior differs from the `prompt` parameter in `create_react_agent`, which is interpreted as a [SystemMessage](https://python.langchain.com/docs/concepts/messages/#systemmessage) when passed as a string.
|
||||
:::
|
||||
:::python
|
||||
A string input for `messages` is converted to a [HumanMessage](https://python.langchain.com/docs/concepts/messages/#humanmessage). This behavior differs from the `prompt` parameter in `create_react_agent`, which is interpreted as a [SystemMessage](https://python.langchain.com/docs/concepts/messages/#systemmessage) when passed as a string.
|
||||
:::
|
||||
|
||||
:::js
|
||||
A string input for `messages` is converted to a [HumanMessage](https://js.langchain.com/docs/concepts/messages/#humanmessage). This behavior differs from the `prompt` parameter in `createReactAgent`, which is interpreted as a [SystemMessage](https://js.langchain.com/docs/concepts/messages/#systemmessage) when passed as a string.
|
||||
:::
|
||||
:::js
|
||||
A string input for `messages` is converted to a [HumanMessage](https://js.langchain.com/docs/concepts/messages/#humanmessage). This behavior differs from the `prompt` parameter in `createReactAgent`, which is interpreted as a [SystemMessage](https://js.langchain.com/docs/concepts/messages/#systemmessage) when passed as a string.
|
||||
:::
|
||||
|
||||
## Output format
|
||||
|
||||
@@ -133,7 +133,7 @@ Agent output is a dictionary containing:
|
||||
- `messages`: A list of all messages exchanged during execution (user input, assistant replies, tool invocations).
|
||||
- Optionally, `structured_response` if [structured output](./agents.md#6-configure-structured-output) is configured.
|
||||
- If using a custom `state_schema`, additional keys corresponding to your defined fields may also be present in the output. These can hold updated state values from tool execution or prompt logic.
|
||||
:::
|
||||
:::
|
||||
|
||||
:::js
|
||||
Agent output is a dictionary containing:
|
||||
@@ -141,7 +141,7 @@ Agent output is a dictionary containing:
|
||||
- `messages`: A list of all messages exchanged during execution (user input, assistant replies, tool invocations).
|
||||
- Optionally, `structuredResponse` if [structured output](./agents.md#6-configure-structured-output) is configured.
|
||||
- If using a custom state definition, additional keys corresponding to your defined fields may also be present in the output. These can hold updated state values from tool execution or prompt logic.
|
||||
:::
|
||||
:::
|
||||
|
||||
See the [context guide](./context.md) for more details on working with custom state schemas and accessing context.
|
||||
|
||||
|
||||
@@ -0,0 +1,699 @@
|
||||
---
|
||||
search:
|
||||
boost: 2
|
||||
tags:
|
||||
- agent
|
||||
hide:
|
||||
- tags
|
||||
---
|
||||
|
||||
# Tools
|
||||
|
||||
:::python
|
||||
[Tools](https://python.langchain.com/docs/concepts/tools/) are a way to encapsulate a function and its input schema in a way that can be passed to a chat model that supports tool calling. This allows the model to request the execution of this function with specific inputs.
|
||||
|
||||
You can either [define your own tools](#define-simple-tools) or use [prebuilt integrations](#prebuilt-tools) that LangChain provides.
|
||||
|
||||
## Define simple tools
|
||||
|
||||
You can pass a vanilla function to `create_react_agent` to use as a tool:
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers."""
|
||||
return a * b
|
||||
|
||||
create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet",
|
||||
tools=[multiply]
|
||||
)
|
||||
```
|
||||
|
||||
`create_react_agent` automatically converts vanilla functions to [LangChain tools](https://python.langchain.com/docs/concepts/tools/#tool-interface).
|
||||
:::
|
||||
|
||||
:::js
|
||||
[Tools](https://js.langchain.com/docs/concepts/tools/) are a way to encapsulate a function and its input schema in a way that can be passed to a chat model that supports tool calling. This allows the model to request the execution of this function with specific inputs.
|
||||
|
||||
You can either [define your own tools](#define-simple-tools) or use [prebuilt integrations](#prebuilt-tools) that LangChain provides.
|
||||
|
||||
## Define simple tools
|
||||
|
||||
You can pass a vanilla function to `createReactAgent` to use as a tool:
|
||||
|
||||
```typescript
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
|
||||
function multiply(a: number, b: number): number {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
createReactAgent({
|
||||
llm: new ChatAnthropic({ model: "anthropic:claude-3-7-sonnet" }),
|
||||
tools: [multiply],
|
||||
});
|
||||
```
|
||||
|
||||
`createReactAgent` automatically converts vanilla functions to [LangChain tools](https://js.langchain.com/docs/concepts/tools/#tool-interface).
|
||||
:::
|
||||
|
||||
## Customize tools
|
||||
|
||||
:::python
|
||||
For more control over tool behavior, use the `@tool` decorator:
|
||||
|
||||
```python
|
||||
# highlight-next-line
|
||||
from langchain_core.tools import tool
|
||||
|
||||
# highlight-next-line
|
||||
@tool("multiply_tool", parse_docstring=True)
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers.
|
||||
|
||||
Args:
|
||||
a: First operand
|
||||
b: Second operand
|
||||
"""
|
||||
return a * b
|
||||
```
|
||||
|
||||
You can also define a custom input schema using Pydantic:
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class MultiplyInputSchema(BaseModel):
|
||||
"""Multiply two numbers"""
|
||||
a: int = Field(description="First operand")
|
||||
b: int = Field(description="Second operand")
|
||||
|
||||
# highlight-next-line
|
||||
@tool("multiply_tool", args_schema=MultiplyInputSchema)
|
||||
def multiply(a: int, b: int) -> int:
|
||||
return a * b
|
||||
```
|
||||
|
||||
For additional customization, refer to the [custom tools guide](https://python.langchain.com/docs/how_to/custom_tools/).
|
||||
:::
|
||||
|
||||
:::js
|
||||
For more control over tool behavior, use the `tool` function:
|
||||
|
||||
```typescript
|
||||
// highlight-next-line
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
// highlight-next-line
|
||||
const multiply = tool(
|
||||
(input) => {
|
||||
return input.a * input.b;
|
||||
},
|
||||
{
|
||||
name: "multiply_tool",
|
||||
description: "Multiply two numbers",
|
||||
schema: z.object({
|
||||
a: z.number().describe("First operand"),
|
||||
b: z.number().describe("Second operand"),
|
||||
}),
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
For additional customization, refer to the [custom tools guide](https://js.langchain.com/docs/how_to/custom_tools/).
|
||||
:::
|
||||
|
||||
## Hide arguments from the model
|
||||
|
||||
Some tools require runtime-only arguments (e.g., user ID or session context) that should not be controllable by the model.
|
||||
|
||||
You can put these arguments in the `state` or `config` of the agent, and access
|
||||
this information inside the tool:
|
||||
|
||||
:::python
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import InjectedState
|
||||
from langgraph.prebuilt.chat_agent_executor import AgentState
|
||||
from langchain_core.runnables import RunnableConfig
|
||||
|
||||
def my_tool(
|
||||
# This will be populated by an LLM
|
||||
tool_arg: str,
|
||||
# access information that's dynamically updated inside the agent
|
||||
# highlight-next-line
|
||||
state: Annotated[AgentState, InjectedState],
|
||||
# access static data that is passed at agent invocation
|
||||
# highlight-next-line
|
||||
config: RunnableConfig,
|
||||
) -> str:
|
||||
"""My tool."""
|
||||
do_something_with_state(state["messages"])
|
||||
do_something_with_config(config)
|
||||
...
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
|
||||
```typescript
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { LangGraphRunnableConfig } from "@langchain/langgraph";
|
||||
import { z } from "zod";
|
||||
|
||||
const myTool = tool(
|
||||
async (input, config: LangGraphRunnableConfig) => {
|
||||
// This will be populated by an LLM
|
||||
const toolArg = input.toolArg;
|
||||
|
||||
// access information that's dynamically updated inside the agent
|
||||
// highlight-next-line
|
||||
const state = config.store;
|
||||
|
||||
// access static data that is passed at agent invocation
|
||||
// highlight-next-line
|
||||
const userId = config.configurable?.userId;
|
||||
|
||||
// Use state and config in your tool logic
|
||||
return "Tool result";
|
||||
},
|
||||
{
|
||||
name: "my_tool",
|
||||
description: "My tool",
|
||||
schema: z.object({
|
||||
toolArg: z.string().describe("Tool argument"),
|
||||
}),
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## Disable parallel tool calling
|
||||
|
||||
Some model providers support executing multiple tools in parallel, but
|
||||
allow users to disable this feature.
|
||||
|
||||
:::python
|
||||
For supported providers, you can disable parallel tool calling by setting `parallel_tool_calls=False` via the `model.bind_tools()` method:
|
||||
|
||||
```python
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
def add(a: int, b: int) -> int:
|
||||
"""Add two numbers"""
|
||||
return a + b
|
||||
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers."""
|
||||
return a * b
|
||||
|
||||
model = init_chat_model("anthropic:claude-3-5-sonnet-latest", temperature=0)
|
||||
tools = [add, multiply]
|
||||
agent = create_react_agent(
|
||||
# disable parallel tool calls
|
||||
# highlight-next-line
|
||||
model=model.bind_tools(tools, parallel_tool_calls=False),
|
||||
tools=tools
|
||||
)
|
||||
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "user", "content": "what's 3 + 5 and 4 * 7?"}]}
|
||||
)
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
For supported providers, you can disable parallel tool calling by setting `parallel_tool_calls: false` via the `bindTools()` method:
|
||||
|
||||
```typescript
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { z } from "zod";
|
||||
|
||||
const add = tool((input) => input.a + input.b, {
|
||||
name: "add",
|
||||
description: "Add two numbers",
|
||||
schema: z.object({
|
||||
a: z.number(),
|
||||
b: z.number(),
|
||||
}),
|
||||
});
|
||||
|
||||
const multiply = tool((input) => input.a * input.b, {
|
||||
name: "multiply",
|
||||
description: "Multiply two numbers",
|
||||
schema: z.object({
|
||||
a: z.number(),
|
||||
b: z.number(),
|
||||
}),
|
||||
});
|
||||
|
||||
const model = new ChatAnthropic({
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
temperature: 0,
|
||||
});
|
||||
const tools = [add, multiply];
|
||||
|
||||
const agent = createReactAgent({
|
||||
// disable parallel tool calls
|
||||
// highlight-next-line
|
||||
llm: model.bindTools(tools, { parallel_tool_calls: false }),
|
||||
tools,
|
||||
});
|
||||
|
||||
await agent.invoke({
|
||||
messages: [{ role: "user", content: "what's 3 + 5 and 4 * 7?" }],
|
||||
});
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## Return tool results directly
|
||||
|
||||
:::python
|
||||
Use `return_direct=True` to return tool results immediately and stop the agent loop:
|
||||
|
||||
```python
|
||||
from langchain_core.tools import tool
|
||||
|
||||
# highlight-next-line
|
||||
@tool(return_direct=True)
|
||||
def add(a: int, b: int) -> int:
|
||||
"""Add two numbers"""
|
||||
return a + b
|
||||
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[add]
|
||||
)
|
||||
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "user", "content": "what's 3 + 5?"}]}
|
||||
)
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
Use `returnDirect: true` to return tool results immediately and stop the agent loop:
|
||||
|
||||
```typescript
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
// highlight-next-line
|
||||
const add = tool((input) => input.a + input.b, {
|
||||
name: "add",
|
||||
description: "Add two numbers",
|
||||
schema: z.object({
|
||||
a: z.number(),
|
||||
b: z.number(),
|
||||
}),
|
||||
// highlight-next-line
|
||||
returnDirect: true,
|
||||
});
|
||||
|
||||
const agent = createReactAgent({
|
||||
llm: model,
|
||||
tools: [add],
|
||||
});
|
||||
|
||||
await agent.invoke({
|
||||
messages: [{ role: "user", content: "what's 3 + 5?" }],
|
||||
});
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## Force tool use
|
||||
|
||||
:::python
|
||||
To force the agent to use specific tools, you can set the `tool_choice` option in `model.bind_tools()`:
|
||||
|
||||
```python
|
||||
from langchain_core.tools import tool
|
||||
|
||||
# highlight-next-line
|
||||
@tool(return_direct=True)
|
||||
def greet(user_name: str) -> int:
|
||||
"""Greet user."""
|
||||
return f"Hello {user_name}!"
|
||||
|
||||
tools = [greet]
|
||||
|
||||
agent = create_react_agent(
|
||||
# highlight-next-line
|
||||
model=model.bind_tools(tools, tool_choice={"type": "tool", "name": "greet"}),
|
||||
tools=tools
|
||||
)
|
||||
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "user", "content": "Hi, I am Bob"}]}
|
||||
)
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
To force the agent to use specific tools, you can set the `tool_choice` option in `bindTools()`:
|
||||
|
||||
```typescript
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
// highlight-next-line
|
||||
const greet = tool((input) => `Hello ${input.userName}!`, {
|
||||
name: "greet",
|
||||
description: "Greet user",
|
||||
schema: z.object({
|
||||
userName: z.string(),
|
||||
}),
|
||||
// highlight-next-line
|
||||
returnDirect: true,
|
||||
});
|
||||
|
||||
const tools = [greet];
|
||||
|
||||
const agent = createReactAgent({
|
||||
// highlight-next-line
|
||||
llm: model.bindTools(tools, { tool_choice: { type: "tool", name: "greet" } }),
|
||||
tools,
|
||||
});
|
||||
|
||||
await agent.invoke({
|
||||
messages: [{ role: "user", content: "Hi, I am Bob" }],
|
||||
});
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
!!! Warning "Avoid infinite loops"
|
||||
|
||||
Forcing tool usage without stopping conditions can create infinite loops. Use one of the following safeguards:
|
||||
|
||||
- Mark the tool with [`return_direct=True`](#return-tool-results-directly) to end the loop after execution.
|
||||
- Set [`recursion_limit`](../concepts/low_level.md#recursion-limit) to restrict the number of execution steps.
|
||||
|
||||
## Handle tool errors
|
||||
|
||||
:::python
|
||||
By default, the agent will catch all exceptions raised during tool calls and will pass those as tool messages to the LLM. To control how the errors are handled, you can use the prebuilt [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] — the node that executes tools inside `create_react_agent` — via its `handle_tool_errors` parameter:
|
||||
:::
|
||||
|
||||
:::js
|
||||
By default, the agent will catch all exceptions raised during tool calls and will pass those as tool messages to the LLM. To control how the errors are handled, you can use the prebuilt [`ToolNode`][<insert-ref>] — the node that executes tools inside `createReactAgent` — via its `handleToolErrors` parameter:
|
||||
:::
|
||||
|
||||
=== "Enable error handling (default)"
|
||||
|
||||
:::python
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers."""
|
||||
if a == 42:
|
||||
raise ValueError("The ultimate error")
|
||||
return a * b
|
||||
|
||||
# Run with error handling (default)
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[multiply]
|
||||
)
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "user", "content": "what's 42 x 7?"}]}
|
||||
)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
const multiply = tool(
|
||||
(input) => {
|
||||
if (input.a === 42) {
|
||||
throw new Error("The ultimate error");
|
||||
}
|
||||
return input.a * input.b;
|
||||
},
|
||||
{
|
||||
name: "multiply",
|
||||
description: "Multiply two numbers",
|
||||
schema: z.object({
|
||||
a: z.number(),
|
||||
b: z.number(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
// Run with error handling (default)
|
||||
const agent = createReactAgent({
|
||||
llm: new ChatAnthropic({ model: "claude-3-7-sonnet-latest" }),
|
||||
tools: [multiply]
|
||||
});
|
||||
|
||||
await agent.invoke({
|
||||
messages: [{ role: "user", content: "what's 42 x 7?" }]
|
||||
});
|
||||
```
|
||||
:::
|
||||
|
||||
=== "Disable error handling"
|
||||
|
||||
:::python
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent, ToolNode
|
||||
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers."""
|
||||
if a == 42:
|
||||
raise ValueError("The ultimate error")
|
||||
return a * b
|
||||
|
||||
# highlight-next-line
|
||||
tool_node = ToolNode(
|
||||
[multiply],
|
||||
# highlight-next-line
|
||||
handle_tool_errors=False # (1)!
|
||||
)
|
||||
agent_no_error_handling = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=tool_node
|
||||
)
|
||||
agent_no_error_handling.invoke(
|
||||
{"messages": [{"role": "user", "content": "what's 42 x 7?"}]}
|
||||
)
|
||||
```
|
||||
|
||||
1. This disables error handling (enabled by default). See all available strategies in the [API reference][langgraph.prebuilt.tool_node.ToolNode].
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { ToolNode } from "@langchain/langgraph/prebuilt";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
const multiply = tool(
|
||||
(input) => {
|
||||
if (input.a === 42) {
|
||||
throw new Error("The ultimate error");
|
||||
}
|
||||
return input.a * input.b;
|
||||
},
|
||||
{
|
||||
name: "multiply",
|
||||
description: "Multiply two numbers",
|
||||
schema: z.object({
|
||||
a: z.number(),
|
||||
b: z.number(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
// highlight-next-line
|
||||
const toolNode = new ToolNode(
|
||||
[multiply],
|
||||
{
|
||||
// highlight-next-line
|
||||
handleToolErrors: false // (1)!
|
||||
}
|
||||
);
|
||||
|
||||
const agentNoErrorHandling = createReactAgent({
|
||||
llm: new ChatAnthropic({ model: "claude-3-7-sonnet-latest" }),
|
||||
tools: toolNode
|
||||
});
|
||||
|
||||
await agentNoErrorHandling.invoke({
|
||||
messages: [{ role: "user", content: "what's 42 x 7?" }]
|
||||
});
|
||||
```
|
||||
|
||||
1. This disables error handling (enabled by default). See all available strategies in the [API reference][toolnode].
|
||||
:::
|
||||
|
||||
=== "Custom error handling"
|
||||
|
||||
:::python
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent, ToolNode
|
||||
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers."""
|
||||
if a == 42:
|
||||
raise ValueError("The ultimate error")
|
||||
return a * b
|
||||
|
||||
# highlight-next-line
|
||||
tool_node = ToolNode(
|
||||
[multiply],
|
||||
# highlight-next-line
|
||||
handle_tool_errors=(
|
||||
"Can't use 42 as a first operand, you must switch operands!" # (1)!
|
||||
)
|
||||
)
|
||||
agent_custom_error_handling = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=tool_node
|
||||
)
|
||||
agent_custom_error_handling.invoke(
|
||||
{"messages": [{"role": "user", "content": "what's 42 x 7?"}]}
|
||||
)
|
||||
```
|
||||
|
||||
1. This provides a custom message to send to the LLM in case of an exception. See all available strategies in the [API reference][langgraph.prebuilt.tool_node.ToolNode].
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { ToolNode } from "@langchain/langgraph/prebuilt";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
const multiply = tool(
|
||||
(input) => {
|
||||
if (input.a === 42) {
|
||||
throw new Error("The ultimate error");
|
||||
}
|
||||
return input.a * input.b;
|
||||
},
|
||||
{
|
||||
name: "multiply",
|
||||
description: "Multiply two numbers",
|
||||
schema: z.object({
|
||||
a: z.number(),
|
||||
b: z.number(),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
// highlight-next-line
|
||||
const toolNode = new ToolNode(
|
||||
[multiply],
|
||||
{
|
||||
// highlight-next-line
|
||||
handleToolErrors: "Can't use 42 as a first operand, you must switch operands!" // (1)!
|
||||
}
|
||||
);
|
||||
|
||||
const agentCustomErrorHandling = createReactAgent({
|
||||
llm: new ChatAnthropic({ model: "claude-3-7-sonnet-latest" }),
|
||||
tools: toolNode
|
||||
});
|
||||
|
||||
await agentCustomErrorHandling.invoke({
|
||||
messages: [{ role: "user", content: "what's 42 x 7?" }]
|
||||
});
|
||||
```
|
||||
|
||||
1. This provides a custom message to send to the LLM in case of an exception. See all available strategies in the [API reference][toolnode].
|
||||
:::
|
||||
|
||||
:::python
|
||||
See [API reference][langgraph.prebuilt.tool_node.ToolNode] for more information on different tool error handling options.
|
||||
:::
|
||||
|
||||
:::js
|
||||
See [API reference][toolnode] for more information on different tool error handling options.
|
||||
:::
|
||||
|
||||
## Working with memory
|
||||
|
||||
LangGraph allows access to short-term and long-term memory from tools. See [Memory](../how-tos/memory/add-memory.md) guide for more information on:
|
||||
|
||||
- how to [read](../how-tos/memory/add-memory.md#read-short-term) from and [write](../how-tos/memory/add-memory.md#write-short-term) to **short-term** memory
|
||||
- how to [read](../how-tos/memory/add-memory.md#read-long-term) from and [write](../how-tos/memory/add-memory.md#write-long-term) to **long-term** memory
|
||||
|
||||
## Prebuilt tools
|
||||
|
||||
:::python
|
||||
You can use prebuilt tools from model providers by passing a dictionary with tool specs to the `tools` parameter of `create_react_agent`. For example, to use the `web_search_preview` tool from OpenAI:
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
agent = create_react_agent(
|
||||
model="openai:gpt-4o-mini",
|
||||
tools=[{"type": "web_search_preview"}]
|
||||
)
|
||||
response = agent.invoke(
|
||||
{"messages": ["What was a positive news story from today?"]}
|
||||
)
|
||||
```
|
||||
|
||||
Additionally, LangChain supports a wide range of prebuilt tool integrations for interacting with APIs, databases, file systems, web data, and more. These tools extend the functionality of agents and enable rapid development.
|
||||
|
||||
You can browse the full list of available integrations in the [LangChain integrations directory](https://python.langchain.com/docs/integrations/tools/).
|
||||
:::
|
||||
|
||||
:::js
|
||||
You can use prebuilt tools from model providers by passing a dictionary with tool specs to the `tools` parameter of `createReactAgent`. For example, to use the `web_search_preview` tool from OpenAI:
|
||||
|
||||
```typescript
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
|
||||
const agent = createReactAgent({
|
||||
llm: new ChatAnthropic({ model: "claude-3-7-sonnet-latest" }),
|
||||
tools: [{ type: "web_search_preview" }],
|
||||
});
|
||||
|
||||
const response = await agent.invoke({
|
||||
messages: [
|
||||
{ role: "user", content: "What was a positive news story from today?" },
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
Additionally, LangChain supports a wide range of prebuilt tool integrations for interacting with APIs, databases, file systems, web data, and more. These tools extend the functionality of agents and enable rapid development.
|
||||
|
||||
You can browse the full list of available integrations in the [LangChain integrations directory](https://js.langchain.com/docs/integrations/tools/).
|
||||
:::
|
||||
|
||||
Some commonly used tool categories include:
|
||||
|
||||
- **Search**: Bing, SerpAPI, Tavily
|
||||
- **Code interpreters**: Python REPL, Node.js REPL
|
||||
- **Databases**: SQL, MongoDB, Redis
|
||||
- **Web data**: Web scraping and browsing
|
||||
- **APIs**: OpenWeatherMap, NewsAPI, and others
|
||||
|
||||
These integrations can be configured and added to your agents using the same `tools` parameter shown in the examples above.
|
||||
@@ -13,7 +13,7 @@ You can use a prebuilt chat UI for interacting with any LangGraph agent through
|
||||
|
||||
## Run agent in UI
|
||||
|
||||
First, set up LangGraph API server [locally](../tutorials/langgraph-platform/local-server.md) or deploy your agent on [LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/quick_start/).
|
||||
First, set up LangGraph API server [locally](./deployment.md#launch-langgraph-server-locally) or deploy your agent on [LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/quick_start/).
|
||||
|
||||
Then, navigate to [Agent Chat UI](https://agentchat.vercel.app), or clone the repository and [run the dev server locally](https://github.com/langchain-ai/agent-chat-ui?tab=readme-ov-file#setup):
|
||||
|
||||
@@ -25,13 +25,13 @@ Then, navigate to [Agent Chat UI](https://agentchat.vercel.app), or clone the re
|
||||
|
||||
## Add human-in-the-loop
|
||||
|
||||
Agent Chat UI has full support for [human-in-the-loop](../concepts/human_in_the_loop.md) workflows. To try it out, replace the agent code in `src/agent/graph.py` (from the [deployment](../tutorials/langgraph-platform/local-server.md) guide) with this [agent implementation](../how-tos/human_in_the_loop/add-human-in-the-loop.md#add-interrupts-to-any-tool):
|
||||
Agent Chat UI has full support for [human-in-the-loop](../concepts/human_in_the_loop.md) workflows. To try it out, replace the agent code in `src/agent/graph.py` (from the [deployment](./deployment.md) guide) with this [agent implementation](../how-tos/human_in_the_loop/add-human-in-the-loop.md#add-interrupts-to-any-tool):
|
||||
|
||||
<video controls src="../assets/interrupt-chat-ui.mp4" type="video/mp4"></video>
|
||||
|
||||
!!! Important
|
||||
|
||||
Agent Chat UI works best if your LangGraph agent interrupts using the @[`HumanInterrupt` schema][HumanInterrupt]. If you do not use that schema, the Agent Chat UI will be able to render the input passed to the `interrupt` function, but it will not have full support for resuming your graph.
|
||||
Agent Chat UI works best if your LangGraph agent interrupts using the [`HumanInterrupt` schema][langgraph.prebuilt.interrupt.HumanInterrupt]. If you do not use that schema, the Agent Chat UI will be able to render the input passed to the `interrupt` function, but it will not have full support for resuming your graph.
|
||||
|
||||
## Generative UI
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
# Data Storage and Privacy
|
||||
|
||||
This document describes how data is processed in the LangGraph CLI and the LangGraph Server for both the in-memory server (`langgraph dev`) and the local Docker server (`langgraph up`). It also describes what data is tracked when interacting with the hosted LangGraph Studio frontend.
|
||||
|
||||
## CLI
|
||||
|
||||
LangGraph **CLI** is the command-line interface for building and running LangGraph applications; see the [CLI guide](../../concepts/langgraph_cli.md) to learn more.
|
||||
|
||||
By default, calls to most CLI commands log a single analytics event upon invocation. This helps us better prioritize improvements to the CLI experience. Each telemetry event contains the calling process's OS, OS version, Python version, the CLI version, the command name (`dev`, `up`, `run`, etc.), and booleans representing whether a flag was passed to the command. You can see the full analytics logic [here](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/langgraph_cli/analytics.py).
|
||||
|
||||
You can disable all CLI telemetry by setting `LANGGRAPH_CLI_NO_ANALYTICS=1`.
|
||||
|
||||
## LangGraph Server (in-memory & docker)
|
||||
|
||||
The [LangGraph Server](../../concepts/langgraph_server.md) provides a durable execution runtime that relies on persisting checkpoints of your application state, long-term memories, thread metadata, assistants, and similar resources to the local file system or a database. Unless you have deliberately customized the storage location, this information is either written to local disk (for `langgraph dev`) or a PostgreSQL database (for `langgraph up` and in all deployments).
|
||||
|
||||
### LangSmith Tracing
|
||||
|
||||
When running the LangGraph server (either in-memory or in Docker), LangSmith tracing may be enabled to facilitate faster debugging and offer observability of graph state and LLM prompts in production. You can always disable tracing by setting `LANGSMITH_TRACING=false` in your server's runtime environment.
|
||||
|
||||
### In-memory development server (`langgraph dev`)
|
||||
|
||||
`langgraph dev` runs an [in-memory development server](../../tutorials/langgraph-platform/local-server.md) as a single Python process, designed for quick development and testing. It saves all checkpointing and memory data to disk within a `.langgraph_api` directory in the current working directory. Apart from the telemetry data described in the [CLI](#cli) section, no data leaves the machine unless you have enabled tracing or your graph code explicitly contacts an external service.
|
||||
|
||||
### Standalone Container (`langgraph up`)
|
||||
|
||||
`langgraph up` builds your local package into a Docker image and runs the server as a [standalone container](../../concepts/deployment_options.md#standalone-container) consisting of three containers: the API server, a PostgreSQL container, and a Redis container. All persistent data (checkpoints, assistants, etc.) are stored in the PostgreSQL database. Redis is used as a pubsub connection for real-time streaming of events. You can encrypt all checkpoints before saving to the database by setting a valid `LANGGRAPH_AES_KEY` environment variable. You can also specify [TTLs](../../how-tos/ttl/configure_ttl.md) for checkpoints and cross-thread memories in `langgraph.json` to control how long data is stored. All persisted threads, memories, and other data can be deleted via the relevant API endpoints.
|
||||
|
||||
Additional API calls are made to confirm that the server has a valid license and to track the number of executed runs and tasks. Periodically, the API server validates the provided license key (or API key).
|
||||
|
||||
If you've disabled [tracing](#langsmith-tracing), no user data is persisted externally unless your graph code explicitly contacts an external service.
|
||||
|
||||
## Studio
|
||||
|
||||
[LangGraph Studio](../../concepts/langgraph_studio.md) is a graphical interface for interacting with your LangGraph server. It does not persist any private data (the data you send to your server is not sent to LangSmith). Though the studio interface is served at [smith.langchain.com](https://smith.langchain.com), it is run in your browser and connects directly to your local LangGraph server so that no data needs to be sent to LangSmith.
|
||||
|
||||
If you are logged in, LangSmith does collect some usage analytics to help improve studio's user experience. This includes:
|
||||
|
||||
- Page visits and navigation patterns
|
||||
- User actions (button clicks)
|
||||
- Browser type and version
|
||||
- Screen resolution and viewport size
|
||||
|
||||
Importantly, no application data or code (or other sensitive configuration details) are collected. All of that is stored in the persistence layer of your LangGraph server. When using Studio anonymously, no account creation is required and usage analytics are not collected.
|
||||
|
||||
## Quick reference
|
||||
|
||||
In summary, you can opt-out of server-side telemetry by turning off CLI analytics and disabling tracing.
|
||||
|
||||
| Variable | Purpose | Default |
|
||||
| ------------------------------ | ------------------------- | -------------------------------- |
|
||||
| `LANGGRAPH_CLI_NO_ANALYTICS=1` | Disable CLI analytics | Analytics enabled |
|
||||
| `LANGSMITH_API_KEY` | Enable LangSmith tracing | Tracing disabled |
|
||||
| `LANGSMITH_TRACING=false` | Disable LangSmith tracing | Depends on environment |
|
||||
@@ -0,0 +1,12 @@
|
||||
# Threads
|
||||
|
||||
A thread contains the accumulated state of a sequence of [runs](../../concepts/assistants.md#execution). When a run is executed, the [state](../../concepts/low_level.md#state) of the underlying graph of the assistant will be persisted to the thread.
|
||||
|
||||
A thread's current and historical state can be retrieved. To persist state, a thread must be created prior to executing a run.
|
||||
|
||||
The state of a thread at a particular point in time is called a [checkpoint](../../concepts/persistence.md#checkpoints). Checkpoints are persisted and can be used to restore the state of a thread at a later time.
|
||||
|
||||
## Learn more
|
||||
|
||||
* For more on threads and checkpoints, see this section of the [LangGraph conceptual guide](../../concepts/persistence.md).
|
||||
* The LangGraph Platform API provides several endpoints for creating and managing threads and thread state. See the [API reference](../../cloud/reference/api/api_ref.html#tag/threads) for more details.
|
||||
@@ -99,8 +99,8 @@ Starting from the `LangGraph Platform` view...
|
||||
1. In the top-right corner, select the gear icon (`Deployment Settings`).
|
||||
1. Update the `Git Branch` to the desired branch.
|
||||
1. Check/uncheck checkbox to `Automatically update deployment on push to branch`.
|
||||
1. Branch creation/deletion and tag creation/deletion events will not trigger an update. Only pushes to an existing branch will trigger an update.
|
||||
1. Pushes in quick succession to a branch will queue subsequent updates. Once a build completes, the most recent commit will begin building and the other queued builds will be skipped.
|
||||
1. Branch creation/deletion and tag creation/deletion events will not trigger an update. Only pushes to an existing branch will trigger an update.
|
||||
1. Pushes in quick succession to a branch will not trigger subsequent updates. In the future, this functionality may be changed/improved.
|
||||
|
||||
## Add or Remove GitHub Repositories
|
||||
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
# Egress for Subscription Metrics and Operational Metadata
|
||||
|
||||
> **Important: Self Hosted Only**
|
||||
> This section only applies to customers who are not running in offline mode and assumes you are using a self-hosted LangGraph Platform instance.
|
||||
> This does not apply to SaaS or Hybrid deployments.
|
||||
|
||||
Self-Hosted LangGraph Platform instances store all information locally and will never send sensitive information outside of your network. We currently only track platform usage for billing purposes according to the entitlements in your order. In order to better remotely support our customers, we do require egress to `https://beacon.langchain.com`.
|
||||
|
||||
In the future, we will be introducing support diagnostics to help us ensure that the LangGraph Platform is running at an optimal level within your environment.
|
||||
|
||||
> **Warning**
|
||||
> **This will require egress to `https://beacon.langchain.com` from your network.**
|
||||
> **If using an API key, you will also need to allow egress to `https://api.smith.langchain.com` or `https://eu.api.smith.langchain.com` for API key verification.**
|
||||
|
||||
Generally, data that we send to Beacon can be categorized as follows:
|
||||
|
||||
- **Subscription Metrics**
|
||||
- Subscription metrics are used to determine level of access and utilization of LangSmith. This includes, but are not limited to:
|
||||
- Nodes Executed
|
||||
- Runs Executed
|
||||
- License Key Verification
|
||||
- **Operational Metadata**
|
||||
- This metadata will contain and collect the above subscription metrics to assist with remote support, allowing the LangChain team to diagnose and troubleshoot performance issues more effectively and proactively.
|
||||
|
||||
## Example Payloads
|
||||
|
||||
In an effort to maximize transparency, we provide sample payloads here:
|
||||
|
||||
### License Verification (If using an Enterprise License)
|
||||
|
||||
**Endpoint:**
|
||||
|
||||
`POST beacon.langchain.com/v1/beacon/verify`
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"license": "<YOUR_LICENSE_KEY>"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "Valid JWT" // Short-lived JWT token to avoid repeated license checks
|
||||
}
|
||||
```
|
||||
|
||||
### Api Key Verification (If using a LangSmith API Key)
|
||||
|
||||
**Endpoint:**
|
||||
`POST api.smith.langchain.com/auth`
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
"Headers": {
|
||||
X-Api-Key: <YOUR_API_KEY>
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"org_config": {
|
||||
"org_id": "3a1c2b6f-4430-4b92-8a5b-79b8b567bbc1",
|
||||
... // Additional organization details
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Usage Reporting
|
||||
|
||||
**Endpoint:**
|
||||
|
||||
`POST beacon.langchain.com/v1/metadata/submit`
|
||||
|
||||
**Request:**
|
||||
|
||||
```json
|
||||
{
|
||||
"license": "<YOUR_LICENSE_KEY>",
|
||||
"from_timestamp": "2025-01-06T09:00:00Z",
|
||||
"to_timestamp": "2025-01-06T10:00:00Z",
|
||||
"tags": {
|
||||
"langgraph.python.version": "0.1.0",
|
||||
"langgraph_api.version": "0.2.0",
|
||||
"langgraph.platform.revision": "abc123",
|
||||
"langgraph.platform.variant": "standard",
|
||||
"langgraph.platform.host": "host-1",
|
||||
"langgraph.platform.tenant_id": "3a1c2b6f-4430-4b92-8a5b-79b8b567bbc1",
|
||||
"langgraph.platform.project_id": "c5b5f53a-4716-4326-8967-d4f7f7799735",
|
||||
"langgraph.platform.plan": "enterprise",
|
||||
"user_app.uses_indexing": "true",
|
||||
"user_app.uses_custom_app": "false",
|
||||
"user_app.uses_custom_auth": "true",
|
||||
"user_app.uses_thread_ttl": "true",
|
||||
"user_app.uses_store_ttl": "false"
|
||||
},
|
||||
"measures": {
|
||||
"langgraph.platform.runs": 150,
|
||||
"langgraph.platform.nodes": 450
|
||||
},
|
||||
"logs": []
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
"204 No Content"
|
||||
```
|
||||
|
||||
## Our Commitment
|
||||
|
||||
LangChain will not store any sensitive information in the Subscription Metrics or Operational Metadata. Any data collected will not be shared with a third party. If you have any concerns about the data being sent, please reach out to your account team.
|
||||
@@ -3,7 +3,7 @@
|
||||
Before deploying, review the [conceptual guide for the Self-Hosted Control Plane](../../concepts/langgraph_self_hosted_control_plane.md) deployment option.
|
||||
|
||||
!!! info "Important"
|
||||
The Self-Hosted Control Plane deployment option requires an [Enterprise](../../concepts/plans.md) plan.
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage and requires an [Enterprise](../../concepts/plans.md) plan.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -23,8 +23,6 @@ Before deploying, review the [conceptual guide for the Self-Hosted Control Plane
|
||||
|
||||
kubectl get storageclass
|
||||
|
||||
1. Egress to `https://beacon.langchain.com` from your network. This is required for license verification and usage reporting if not running in air-gapped mode. See the [Egress documentation](../../cloud/deployment/egress.md) for more details.
|
||||
|
||||
## Setup
|
||||
|
||||
1. As part of configuring your Self-Hosted LangSmith instance, you enable the `langgraphPlatform` option. This will provision a few key resources.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Before deploying, review the [conceptual guide for the Self-Hosted Data Plane](../../concepts/langgraph_self_hosted_data_plane.md) deployment option.
|
||||
|
||||
!!! info "Important"
|
||||
The Self-Hosted Data Plane deployment option requires an [Enterprise](../../concepts/plans.md) plan.
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage and requires an [Enterprise](../../concepts/plans.md) plan.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -15,15 +15,11 @@ Before deploying, review the [conceptual guide for the Self-Hosted Data Plane](.
|
||||
### Prerequisites
|
||||
1. `KEDA` is installed on your cluster.
|
||||
|
||||
helm repo add kedacore https://kedacore.github.io/charts
|
||||
helm repo add kedacore https://kedacore.github.io/charts
|
||||
helm install keda kedacore/keda --namespace keda --create-namespace
|
||||
|
||||
1. A valid `Ingress` controller is installed on your cluster.
|
||||
1. You have slack space in your cluster for multiple deployments. `Cluster-Autoscaler` is recommended to automatically provision new nodes.
|
||||
1. You will need to enable egress to two control plane URLs. The listener polls these endpoints for deployments:
|
||||
|
||||
https://api.host.langchain.com
|
||||
https://api.smith.langchain.com
|
||||
|
||||
### Setup
|
||||
|
||||
@@ -35,6 +31,7 @@ Before deploying, review the [conceptual guide for the Self-Hosted Data Plane](.
|
||||
1. Configure your `langgraph-dataplane-values.yaml` file.
|
||||
|
||||
config:
|
||||
langgraphPlatformLicenseKey: "" # Your LangGraph Platform license key
|
||||
langsmithApiKey: "" # API Key of your Workspace
|
||||
langsmithWorkspaceId: "" # Workspace ID
|
||||
hostBackendUrl: "https://api.host.langchain.com" # Only override this if on EU
|
||||
|
||||
@@ -95,7 +95,7 @@ my-app/
|
||||
|
||||
## Define Graphs
|
||||
|
||||
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each @[CompiledStateGraph][CompiledStateGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file).
|
||||
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledStateGraph][langgraph.graph.state.CompiledStateGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file).
|
||||
|
||||
Example `agent.py` file, which shows how to import from other modules you define (code for the modules is not shown here, please see [this repository](https://github.com/langchain-ai/langgraph-example) to see their implementation):
|
||||
|
||||
@@ -108,11 +108,11 @@ from langgraph.graph import StateGraph, END, START
|
||||
from my_agent.utils.nodes import call_model, should_continue, tool_node # import nodes
|
||||
from my_agent.utils.state import AgentState # import state
|
||||
|
||||
# Define the runtime context
|
||||
class GraphContext(TypedDict):
|
||||
# Define the config
|
||||
class GraphConfig(TypedDict):
|
||||
model_name: Literal["anthropic", "openai"]
|
||||
|
||||
workflow = StateGraph(AgentState, context_schema=GraphContext)
|
||||
workflow = StateGraph(AgentState, config_schema=GraphConfig)
|
||||
workflow.add_node("agent", call_model)
|
||||
workflow.add_node("action", tool_node)
|
||||
workflow.add_edge(START, "agent")
|
||||
|
||||
@@ -108,7 +108,7 @@ my-app/
|
||||
|
||||
## Define Graphs
|
||||
|
||||
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each @[CompiledStateGraph][CompiledStateGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file).
|
||||
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledStateGraph][langgraph.graph.state.CompiledStateGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file).
|
||||
|
||||
Example `agent.py` file, which shows how to import from other modules you define (code for the modules is not shown here, please see [this repository](https://github.com/langchain-ai/langgraph-example-pyproject) to see their implementation):
|
||||
|
||||
@@ -121,11 +121,11 @@ from langgraph.graph import StateGraph, END, START
|
||||
from my_agent.utils.nodes import call_model, should_continue, tool_node # import nodes
|
||||
from my_agent.utils.state import AgentState # import state
|
||||
|
||||
# Define the runtime context
|
||||
class GraphContext(TypedDict):
|
||||
# Define the config
|
||||
class GraphConfig(TypedDict):
|
||||
model_name: Literal["anthropic", "openai"]
|
||||
|
||||
workflow = StateGraph(AgentState, context_schema=GraphContext)
|
||||
workflow = StateGraph(AgentState, config_schema=GraphConfig)
|
||||
workflow.add_node("agent", call_model)
|
||||
workflow.add_node("action", tool_node)
|
||||
workflow.add_edge(START, "agent")
|
||||
|
||||
@@ -21,9 +21,9 @@ Before deploying, review the [conceptual guide for the Standalone Container](../
|
||||
|
||||
`<database_name_1>` and `database_name_2` are different databases within the same instance, but `<hostname_1>` is shared. **The same database cannot be used for separate deployments**.
|
||||
|
||||
1. `LANGSMITH_API_KEY`: (if using [Lite](../../concepts/langgraph_server.md#server-versions)) LangSmith API key. This will be used to authenticate ONCE at server start up.
|
||||
1. `LANGGRAPH_CLOUD_LICENSE_KEY`: (if using [Enterprise](../../concepts/langgraph_data_plane.md#licensing)) LangGraph Platform license key. This will be used to authenticate ONCE at server start up.
|
||||
1. `LANGSMITH_ENDPOINT`: To send traces to a [self-hosted LangSmith](https://docs.smith.langchain.com/self_hosting) instance, set `LANGSMITH_ENDPOINT` to the hostname of the self-hosted LangSmith instance.
|
||||
1. Egress to `https://beacon.langchain.com` from your network. This is required for license verification and usage reporting if not running in air-gapped mode. See the [Egress documentation](../../cloud/deployment/egress.md) for more details.
|
||||
|
||||
## Kubernetes (Helm)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
To review, edit, and approve tool calls in an agent or workflow, use LangGraph's [human-in-the-loop](../../concepts/human_in_the_loop.md) features.
|
||||
|
||||
## Dynamic interrupts
|
||||
## LangGraph API invoke & resume
|
||||
|
||||
=== "Python"
|
||||
|
||||
@@ -30,7 +30,9 @@ To review, edit, and approve tool calls in an agent or workflow, use LangGraph's
|
||||
# > [
|
||||
# > {
|
||||
# > 'value': {'text_to_revise': 'original text'},
|
||||
# > 'id': '...',
|
||||
# > 'resumable': True,
|
||||
# > 'ns': ['human_node:fc722478-2f21-0578-c572-d9fc4dd07c3b'],
|
||||
# > 'when': 'during'
|
||||
# > }
|
||||
# > ]
|
||||
|
||||
@@ -201,7 +203,9 @@ To review, edit, and approve tool calls in an agent or workflow, use LangGraph's
|
||||
# > [
|
||||
# > {
|
||||
# > 'value': {'text_to_revise': 'original text'},
|
||||
# > 'id': '...',
|
||||
# > 'resumable': True,
|
||||
# > 'ns': ['human_node:fc722478-2f21-0578-c572-d9fc4dd07c3b'],
|
||||
# > 'when': 'during'
|
||||
# > }
|
||||
# > ]
|
||||
|
||||
@@ -301,185 +305,6 @@ To review, edit, and approve tool calls in an agent or workflow, use LangGraph's
|
||||
}"
|
||||
```
|
||||
|
||||
## Static interrupts
|
||||
|
||||
Static interrupts (also known as static breakpoints) are triggered either before or after a node executes.
|
||||
|
||||
!!! warning
|
||||
|
||||
Static interrupts are **not** recommended for human-in-the-loop workflows. They are best used for debugging and testing.
|
||||
|
||||
You can set static interrupts by specifying `interrupt_before` and `interrupt_after` at compile time:
|
||||
|
||||
```python
|
||||
# highlight-next-line
|
||||
graph = graph_builder.compile( # (1)!
|
||||
# highlight-next-line
|
||||
interrupt_before=["node_a"], # (2)!
|
||||
# highlight-next-line
|
||||
interrupt_after=["node_b", "node_c"], # (3)!
|
||||
)
|
||||
```
|
||||
|
||||
1. The breakpoints are set during `compile` time.
|
||||
2. `interrupt_before` specifies the nodes where execution should pause before the node is executed.
|
||||
3. `interrupt_after` specifies the nodes where execution should pause after the node is executed.
|
||||
|
||||
Alternatively, you can set static interrupts at run time:
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# highlight-next-line
|
||||
await client.runs.wait( # (1)!
|
||||
thread_id,
|
||||
assistant_id,
|
||||
inputs=inputs,
|
||||
# highlight-next-line
|
||||
interrupt_before=["node_a"], # (2)!
|
||||
# highlight-next-line
|
||||
interrupt_after=["node_b", "node_c"] # (3)!
|
||||
)
|
||||
```
|
||||
|
||||
1. `client.runs.wait` is called with the `interrupt_before` and `interrupt_after` parameters. This is a run-time configuration and can be changed for every invocation.
|
||||
2. `interrupt_before` specifies the nodes where execution should pause before the node is executed.
|
||||
3. `interrupt_after` specifies the nodes where execution should pause after the node is executed.
|
||||
|
||||
=== "JavaScript"
|
||||
|
||||
```js
|
||||
// highlight-next-line
|
||||
await client.runs.wait( // (1)!
|
||||
threadID,
|
||||
assistantID,
|
||||
{
|
||||
input: input,
|
||||
// highlight-next-line
|
||||
interruptBefore: ["node_a"], // (2)!
|
||||
// highlight-next-line
|
||||
interruptAfter: ["node_b", "node_c"] // (3)!
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
1. `client.runs.wait` is called with the `interruptBefore` and `interruptAfter` parameters. This is a run-time configuration and can be changed for every invocation.
|
||||
2. `interruptBefore` specifies the nodes where execution should pause before the node is executed.
|
||||
3. `interruptAfter` specifies the nodes where execution should pause after the node is executed.
|
||||
|
||||
=== "cURL"
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data "{
|
||||
\"assistant_id\": \"agent\",
|
||||
\"interrupt_before\": [\"node_a\"],
|
||||
\"interrupt_after\": [\"node_b\", \"node_c\"],
|
||||
\"input\": <INPUT>
|
||||
}"
|
||||
```
|
||||
|
||||
The following example shows how to add static interrupts:
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
from langgraph_sdk import get_client
|
||||
client = get_client(url=<DEPLOYMENT_URL>)
|
||||
|
||||
# Using the graph deployed with the name "agent"
|
||||
assistant_id = "agent"
|
||||
|
||||
# create a thread
|
||||
thread = await client.threads.create()
|
||||
thread_id = thread["thread_id"]
|
||||
|
||||
# Run the graph until the breakpoint
|
||||
result = await client.runs.wait(
|
||||
thread_id,
|
||||
assistant_id,
|
||||
input=inputs # (1)!
|
||||
)
|
||||
|
||||
# Resume the graph
|
||||
await client.runs.wait(
|
||||
thread_id,
|
||||
assistant_id,
|
||||
input=None # (2)!
|
||||
)
|
||||
```
|
||||
|
||||
1. The graph is run until the first breakpoint is hit.
|
||||
2. The graph is resumed by passing in `None` for the input. This will run the graph until the next breakpoint is hit.
|
||||
|
||||
=== "JavaScript"
|
||||
|
||||
```js
|
||||
import { Client } from "@langchain/langgraph-sdk";
|
||||
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
|
||||
|
||||
// Using the graph deployed with the name "agent"
|
||||
const assistantID = "agent";
|
||||
|
||||
// create a thread
|
||||
const thread = await client.threads.create();
|
||||
const threadID = thread["thread_id"];
|
||||
|
||||
// Run the graph until the breakpoint
|
||||
const result = await client.runs.wait(
|
||||
threadID,
|
||||
assistantID,
|
||||
{ input: input } // (1)!
|
||||
);
|
||||
|
||||
// Resume the graph
|
||||
await client.runs.wait(
|
||||
threadID,
|
||||
assistantID,
|
||||
{ input: null } // (2)!
|
||||
);
|
||||
```
|
||||
|
||||
1. The graph is run until the first breakpoint is hit.
|
||||
2. The graph is resumed by passing in `null` for the input. This will run the graph until the next breakpoint is hit.
|
||||
|
||||
=== "cURL"
|
||||
|
||||
Create a thread:
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url <DEPLOYMENT_URL>/threads \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{}'
|
||||
```
|
||||
|
||||
Run the graph until the breakpoint:
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data "{
|
||||
\"assistant_id\": \"agent\",
|
||||
\"input\": <INPUT>
|
||||
}"
|
||||
```
|
||||
|
||||
Resume the graph:
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data "{
|
||||
\"assistant_id\": \"agent\"
|
||||
}"
|
||||
```
|
||||
|
||||
|
||||
## Learn more
|
||||
|
||||
- [Human-in-the-loop conceptual guide](../../concepts/human_in_the_loop.md): learn more about LangGraph human-in-the-loop features.
|
||||
|
||||
@@ -2,20 +2,21 @@
|
||||
|
||||
In this guide we will show how to create, configure, and manage an [assistant](../../concepts/assistants.md).
|
||||
|
||||
First, as a brief refresher on the concept of runtime context, consider the following simple `call_model` node and context schema. Observe that this node tries to read and use the `model_provider` as defined by the `Runtime` object's `context` property.
|
||||
First, as a brief refresher on the concept of configurations, consider the following simple `call_model` node and configuration schema. Observe that this node tries to read and use the `model_name` as defined by the `config` object's `configurable`.
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ContextSchema:
|
||||
llm_provider: str = "anthropic"
|
||||
|
||||
builder = StateGraph(AgentState, context_schema=ContextSchema)
|
||||
class ConfigSchema(TypedDict):
|
||||
model_name: str
|
||||
|
||||
def call_model(state, runtime: Runtime[ContextSchema]):
|
||||
builder = StateGraph(AgentState, config_schema=ConfigSchema)
|
||||
|
||||
def call_model(state, config):
|
||||
messages = state["messages"]
|
||||
model = _get_model(runtime.context.llm_provider)
|
||||
model_name = config.get('configurable', {}).get("model_name", "anthropic")
|
||||
model = _get_model(model_name)
|
||||
response = model.invoke(messages)
|
||||
# We return a list, because this will get added to the existing list
|
||||
return {"messages": [response]}
|
||||
@@ -43,9 +44,7 @@ First, as a brief refresher on the concept of runtime context, consider the foll
|
||||
}
|
||||
```
|
||||
|
||||
:::python
|
||||
For more information on runtime context, [see here](../../concepts/low_level.md#runtime-context).
|
||||
:::
|
||||
For more information on configurations, [see here](../../concepts/low_level.md#configuration).
|
||||
|
||||
## Create an assistant
|
||||
|
||||
@@ -329,4 +328,4 @@ If you now run your graph and pass in this assistant id, it will use the first v
|
||||
If using LangGraph Studio, to set the active version of your assistant, click the "Manage Assistants" button and locate the assistant you would like to use. Select the assistant and the version, and then click the "Active" toggle. This will update the assistant to make the selected version active.
|
||||
|
||||
!!! warning "Deleting Assistants"
|
||||
Deleting as assistant will delete ALL of its versions. There is currently no way to delete a single version, but by pointing your assistant to the correct version you can skip any versions that you don't wish to use.
|
||||
Deleting as assistant will delete ALL of its versions. There is currently no way to delete a single version, but by pointing your assistant to the correct version you can skip any versions that you don't wish to use.
|
||||
|
||||
@@ -30,33 +30,17 @@ export default {
|
||||
|
||||
Next, define your UI components in your `langgraph.json` configuration:
|
||||
|
||||
=== "Python agent"
|
||||
|
||||
```json title="langgraph.json"
|
||||
{
|
||||
"node_version": "20",
|
||||
"graphs": {
|
||||
"agent": "./src/agent.py:graph"
|
||||
},
|
||||
"ui": {
|
||||
"agent": "./src/agent/ui.tsx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS agent"
|
||||
|
||||
```json title="langgraph.json"
|
||||
{
|
||||
"node_version": "20",
|
||||
"graphs": {
|
||||
"agent": "./src/agent/index.ts:graph"
|
||||
},
|
||||
"ui": {
|
||||
"agent": "./src/agent/ui.tsx"
|
||||
}
|
||||
}
|
||||
```
|
||||
```json
|
||||
{
|
||||
"node_version": "20",
|
||||
"graphs": {
|
||||
"agent": "./src/agent/index.ts:graph"
|
||||
},
|
||||
"ui": {
|
||||
"agent": "./src/agent/ui.tsx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `ui` section points to the UI components that will be used by graphs. By default, we recommend using the same key as the graph name, but you can split out the components however you like, see [Customise the namespace of UI components](#customise-the-namespace-of-ui-components) for more details.
|
||||
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
# Set breakpoints using Server API
|
||||
|
||||
[Breakpoints](../../concepts/breakpoints.md) pause graph execution at defined points and let you step through each stage. They use LangGraph's [**persistence layer**](../../concepts/persistence.md), which saves the graph state after each step.
|
||||
|
||||
With breakpoints, you can inspect the graph's state and node inputs at any point. Execution pauses indefinitely until you resume, as the checkpointer preserves the state.
|
||||
|
||||
!!! tip
|
||||
|
||||
For conceptual information on breakpoints, see [Breakpoints](../../concepts/breakpoints.md).
|
||||
|
||||
## Set static breakpoints
|
||||
|
||||
Static breakpoints are triggered either before or after a node executes. You can set static breakpoints by specifying `interrupt_before` and `interrupt_after` at compile time or run time.
|
||||
|
||||
=== "Compile time"
|
||||
|
||||
```python
|
||||
# highlight-next-line
|
||||
graph = graph_builder.compile( # (1)!
|
||||
# highlight-next-line
|
||||
interrupt_before=["node_a"], # (2)!
|
||||
# highlight-next-line
|
||||
interrupt_after=["node_b", "node_c"], # (3)!
|
||||
)
|
||||
```
|
||||
|
||||
1. The breakpoints are set during `compile` time.
|
||||
2. `interrupt_before` specifies the nodes where execution should pause before the node is executed.
|
||||
3. `interrupt_after` specifies the nodes where execution should pause after the node is executed.
|
||||
|
||||
=== "Run time"
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
# highlight-next-line
|
||||
await client.runs.wait( # (1)!
|
||||
thread_id,
|
||||
assistant_id,
|
||||
inputs=inputs,
|
||||
# highlight-next-line
|
||||
interrupt_before=["node_a"], # (2)!
|
||||
# highlight-next-line
|
||||
interrupt_after=["node_b", "node_c"] # (3)!
|
||||
)
|
||||
```
|
||||
|
||||
1. `client.runs.wait` is called with the `interrupt_before` and `interrupt_after` parameters. This is a run-time configuration and can be changed for every invocation.
|
||||
2. `interrupt_before` specifies the nodes where execution should pause before the node is executed.
|
||||
3. `interrupt_after` specifies the nodes where execution should pause after the node is executed.
|
||||
|
||||
=== "JavaScript"
|
||||
|
||||
```js
|
||||
// highlight-next-line
|
||||
await client.runs.wait( // (1)!
|
||||
threadID,
|
||||
assistantID,
|
||||
{
|
||||
input: input,
|
||||
// highlight-next-line
|
||||
interruptBefore: ["node_a"], // (2)!
|
||||
// highlight-next-line
|
||||
interruptAfter: ["node_b", "node_c"] // (3)!
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
1. `client.runs.wait` is called with the `interruptBefore` and `interruptAfter` parameters. This is a run-time configuration and can be changed for every invocation.
|
||||
2. `interruptBefore` specifies the nodes where execution should pause before the node is executed.
|
||||
3. `interruptAfter` specifies the nodes where execution should pause after the node is executed.
|
||||
|
||||
=== "cURL"
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data "{
|
||||
\"assistant_id\": \"agent\",
|
||||
\"interrupt_before\": [\"node_a\"],
|
||||
\"interrupt_after\": [\"node_b\", \"node_c\"],
|
||||
\"input\": <INPUT>
|
||||
}"
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
This example shows how to add **static** breakpoints. See [Use breakpoints](../../how-tos/human_in_the_loop/breakpoints.md) for more options on adding breakpoints.
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
from langgraph_sdk import get_client
|
||||
client = get_client(url=<DEPLOYMENT_URL>)
|
||||
|
||||
# Using the graph deployed with the name "agent"
|
||||
assistant_id = "agent"
|
||||
|
||||
# create a thread
|
||||
thread = await client.threads.create()
|
||||
thread_id = thread["thread_id"]
|
||||
|
||||
# Run the graph until the breakpoint
|
||||
result = await client.runs.wait(
|
||||
thread_id,
|
||||
assistant_id,
|
||||
input=inputs # (1)!
|
||||
)
|
||||
|
||||
# Resume the graph
|
||||
await client.runs.wait(
|
||||
thread_id,
|
||||
assistant_id,
|
||||
input=None # (2)!
|
||||
)
|
||||
```
|
||||
|
||||
1. The graph is run until the first breakpoint is hit.
|
||||
2. The graph is resumed by passing in `None` for the input. This will run the graph until the next breakpoint is hit.
|
||||
|
||||
=== "JavaScript"
|
||||
|
||||
```js
|
||||
import { Client } from "@langchain/langgraph-sdk";
|
||||
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
|
||||
|
||||
// Using the graph deployed with the name "agent"
|
||||
const assistantID = "agent";
|
||||
|
||||
// create a thread
|
||||
const thread = await client.threads.create();
|
||||
const threadID = thread["thread_id"];
|
||||
|
||||
// Run the graph until the breakpoint
|
||||
const result = await client.runs.wait(
|
||||
threadID,
|
||||
assistantID,
|
||||
{ input: input } // (1)!
|
||||
);
|
||||
|
||||
// Resume the graph
|
||||
await client.runs.wait(
|
||||
threadID,
|
||||
assistantID,
|
||||
{ input: null } // (2)!
|
||||
);
|
||||
```
|
||||
|
||||
1. The graph is run until the first breakpoint is hit.
|
||||
2. The graph is resumed by passing in `null` for the input. This will run the graph until the next breakpoint is hit.
|
||||
|
||||
=== "cURL"
|
||||
|
||||
Create a thread:
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url <DEPLOYMENT_URL>/threads \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{}'
|
||||
```
|
||||
|
||||
Run the graph until the breakpoint:
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data "{
|
||||
\"assistant_id\": \"agent\",
|
||||
\"input\": <INPUT>
|
||||
}"
|
||||
```
|
||||
|
||||
Resume the graph:
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data "{
|
||||
\"assistant_id\": \"agent\"
|
||||
}"
|
||||
```
|
||||
@@ -4,11 +4,11 @@ LangGraph provides the [**time travel**](../../concepts/time-travel.md) function
|
||||
|
||||
To time travel using the LangGraph Server API (via the LangGraph SDK):
|
||||
|
||||
1. **Run the graph** with initial inputs using [LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/)'s @[`client.runs.wait`][client.runs.wait] or @[`client.runs.stream`][client.runs.stream] APIs.
|
||||
2. **Identify a checkpoint in an existing thread**: Use @[`client.threads.get_history`][client.threads.get_history] method to retrieve the execution history for a specific `thread_id` and locate the desired `checkpoint_id`.
|
||||
1. **Run the graph** with initial inputs using [LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/)'s [`client.runs.wait`][langgraph_sdk.client.RunsClient.wait] or [`client.runs.stream`][langgraph_sdk.client.RunsClient.stream] APIs.
|
||||
2. **Identify a checkpoint in an existing thread**: Use [`client.threads.get_history`][langgraph_sdk.client.ThreadsClient.get_history] method to retrieve the execution history for a specific `thread_id` and locate the desired `checkpoint_id`.
|
||||
Alternatively, set a [breakpoint](./human_in_the_loop_breakpoint.md) before the node(s) where you want execution to pause. You can then find the most recent checkpoint recorded up to that breakpoint.
|
||||
3. **(Optional) modify the graph state**: Use the @[`client.threads.update_state`][client.threads.update_state] method to modify the graph’s state at the checkpoint and resume execution from alternative state.
|
||||
4. **Resume execution from the checkpoint**: Use the @[`client.runs.wait`][client.runs.wait] or @[`client.runs.stream`][client.runs.stream] APIs with an input of `None` and the appropriate `thread_id` and `checkpoint_id`.
|
||||
3. **(Optional) modify the graph state**: Use the [`client.threads.update_state`][langgraph_sdk.client.ThreadsClient.update_state] method to modify the graph’s state at the checkpoint and resume execution from alternative state.
|
||||
4. **Resume execution from the checkpoint**: Use the [`client.runs.wait`][langgraph_sdk.client.RunsClient.wait] or [`client.runs.stream`][langgraph_sdk.client.RunsClient.stream] APIs with an input of `None` and the appropriate `thread_id` and `checkpoint_id`.
|
||||
|
||||
## Use time travel in a workflow
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ Click the dropdown next to "Submit" and click the toggle to enable/disable strea
|
||||
To run your graph with breakpoints, click the "Interrupt" button. Select a node and whether to pause before and/or after that node has executed. Click "Continue" in the thread log to resume execution.
|
||||
|
||||
|
||||
For more information on breakpoints see [here](../../concepts/human_in_the_loop.md).
|
||||
For more information on breakpoints see [here](../../concepts/breakpoints.md).
|
||||
|
||||
### Submit run
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# How to integrate LangGraph into your React application
|
||||
How to integrate LangGraph into your React application# How to integrate LangGraph into your React application
|
||||
|
||||
!!! info "Prerequisites"
|
||||
|
||||
@@ -137,7 +137,7 @@ const thread = useStream<{ messages: Message[] }>({
|
||||
|
||||
You can also manually manage the resuming process by using the run callbacks to persist the run metadata and the `joinStream` function to resume the stream. Make sure to pass `streamResumable: true` when creating the run; otherwise some events might be lost.
|
||||
|
||||
```tsx
|
||||
````tsx
|
||||
import type { Message } from "@langchain/langgraph-sdk";
|
||||
import { useStream } from "@langchain/langgraph-sdk/react";
|
||||
import { useCallback, useState, useEffect, useRef } from "react";
|
||||
@@ -236,7 +236,7 @@ const thread = useStream<{ messages: Message[] }>({
|
||||
threadId: threadId,
|
||||
onThreadId: setThreadId,
|
||||
});
|
||||
```
|
||||
````
|
||||
|
||||
We recommend storing the `threadId` in your URL's query parameters to let users resume conversations after page refreshes.
|
||||
|
||||
@@ -503,74 +503,6 @@ const handleSubmit = (text: string) => {
|
||||
};
|
||||
```
|
||||
|
||||
### Cached Thread Display
|
||||
|
||||
Use the `initialValues` option to display cached thread data immediately while the history is being loaded from the server. This improves user experience by showing cached data instantly when navigating to existing threads.
|
||||
|
||||
```tsx
|
||||
import { useStream } from "@langchain/langgraph-sdk/react";
|
||||
|
||||
const CachedThreadExample = ({ threadId, cachedThreadData }) => {
|
||||
const stream = useStream({
|
||||
apiUrl: "http://localhost:2024",
|
||||
assistantId: "agent",
|
||||
threadId,
|
||||
// Show cached data immediately while history loads
|
||||
initialValues: cachedThreadData?.values,
|
||||
messagesKey: "messages",
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
{stream.messages.map((message) => (
|
||||
<div key={message.id}>{message.content as string}</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### Optimistic Thread Creation
|
||||
|
||||
Use the `threadId` option in `submit` function to enable optimistic UI patterns where you need to know the thread ID before the thread is actually created.
|
||||
|
||||
```tsx
|
||||
import { useState } from "react";
|
||||
import { useStream } from "@langchain/langgraph-sdk/react";
|
||||
|
||||
const OptimisticThreadExample = () => {
|
||||
const [threadId, setThreadId] = useState<string | null>(null);
|
||||
const [optimisticThreadId] = useState(() => crypto.randomUUID());
|
||||
|
||||
const stream = useStream({
|
||||
apiUrl: "http://localhost:2024",
|
||||
assistantId: "agent",
|
||||
threadId,
|
||||
onThreadId: setThreadId, // (3) Updated after thread has been created.
|
||||
messagesKey: "messages",
|
||||
});
|
||||
|
||||
const handleSubmit = (text: string) => {
|
||||
// (1) Perform a soft navigation to /threads/${optimisticThreadId}
|
||||
// without waiting for thread creation.
|
||||
window.history.pushState({}, "", `/threads/${optimisticThreadId}`);
|
||||
|
||||
// (2) Submit message to create thread with the predetermined ID.
|
||||
stream.submit(
|
||||
{ messages: [{ type: "human", content: text }] },
|
||||
{ threadId: optimisticThreadId }
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Thread ID: {threadId ?? optimisticThreadId}</p>
|
||||
{/* Rest of component */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
|
||||
The `useStream()` hook is friendly for apps written in TypeScript and you can specify types for the state to get better type safety and IDE support.
|
||||
|
||||
@@ -140,22 +140,6 @@ https://my-server.app/my-webhook-endpoint?token=YOUR_SECRET_TOKEN
|
||||
|
||||
Your server should extract and validate this token before processing requests.
|
||||
|
||||
## Disable webhooks
|
||||
|
||||
As of `langgraph-api>=0.2.78`, developers can disable webhooks in the `langgraph.json` file:
|
||||
|
||||
```json
|
||||
{
|
||||
"http": {
|
||||
"disable_webhooks": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This feature is primarily intended for self-hosted deployments, where platform administrators or developers may prefer to disable webhooks to simplify their security posture—especially if they are not configuring firewall rules or other network controls. Disabling webhooks helps prevent untrusted payloads from being sent to internal endpoints.
|
||||
|
||||
For full configuration details, refer to the [configuration file reference](https://langchain-ai.github.io/langgraph/cloud/reference/cli/?h=disable_webhooks#configuration-file).
|
||||
|
||||
## Test webhooks
|
||||
|
||||
You can test your webhook using online services like:
|
||||
|
||||
@@ -154,9 +154,8 @@ You can now test the API:
|
||||
|
||||
```bash
|
||||
curl -s --request POST \
|
||||
--url <DEPLOYMENT_URL>/runs/stream \
|
||||
--url <DEPLOYMENT_URL> \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header "X-Api-Key: <LANGSMITH API KEY> \
|
||||
--data "{
|
||||
\"assistant_id\": \"agent\",
|
||||
\"input\": {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# LangGraph Server API Reference
|
||||
# API Reference
|
||||
|
||||
The LangGraph Server API reference is available within each deployment at the `/docs` endpoint (e.g. `http://localhost:8124/docs`).
|
||||
The LangGraph Platform API reference is available with each deployment at the `/docs` URL path (e.g. `http://localhost:8124/docs`).
|
||||
|
||||
Click <a href="/langgraph/cloud/reference/api/api_ref.html" target="_blank">here</a> to view the API reference.
|
||||
|
||||
## Authentication
|
||||
|
||||
For deployments to LangGraph Platform, authentication is required. Pass the `X-Api-Key` header with each request to the LangGraph Server. The value of the header should be set to a valid LangSmith API key for the organization where the LangGraph Server is deployed.
|
||||
For deployments to LangGraph Platform, authentication is required. Pass the `X-Api-Key` header with each request to the LangGraph Platform API. The value of the header should be set to a valid LangSmith API key for the organization where the API is deployed.
|
||||
|
||||
Example `curl` command:
|
||||
```shell
|
||||
@@ -18,5 +18,5 @@ curl --request POST \
|
||||
"metadata": {},
|
||||
"limit": 10,
|
||||
"offset": 0
|
||||
}'
|
||||
}'
|
||||
```
|
||||
|
||||
@@ -1,247 +0,0 @@
|
||||
# LangGraph Control Plane API Reference
|
||||
|
||||
The LangGraph Control Plane API is used to programmatically create and manage LangGraph Server deployments. For example, the APIs can be orchestrated to create custom CI/CD workflows.
|
||||
|
||||
Click <a href="https://api.host.langchain.com/docs" target="_blank">here</a> to view the API reference.
|
||||
|
||||
## Host
|
||||
|
||||
LangGraph Control Plane hosts for Cloud SaaS data regions:
|
||||
|
||||
| US | EU |
|
||||
|----|----|
|
||||
| `https://api.host.langchain.com` | `https://eu.api.host.langchain.com` |
|
||||
|
||||
**Note**: Self-hosted deployments of LangGraph Platform will have a custom host for the LangGraph Control Plane.
|
||||
|
||||
## Authentication
|
||||
|
||||
To authenticate with the LangGraph Control Plane API, set the `X-Api-Key` header to a valid LangSmith API key.
|
||||
|
||||
Example `curl` command:
|
||||
```shell
|
||||
curl --request GET \
|
||||
--url http://localhost:8124/v2/deployments \
|
||||
--header 'X-Api-Key: LANGSMITH_API_KEY'
|
||||
```
|
||||
|
||||
## Versioning
|
||||
|
||||
Each endpoint path is prefixed with a version (e.g. `v1`, `v2`).
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Call `POST /v2/deployments` to create a new Deployment. The response body contains the Deployment ID (`id`) and the ID of the latest (and first) revision (`latest_revision_id`).
|
||||
1. Call `GET /v2/deployments/{deployment_id}` to retrieve the Deployment. Set `deployment_id` in the URL to the value of Deployment ID (`id`).
|
||||
1. Poll for revision `status` until `status` is `DEPLOYED` by calling `GET /v2/deployments/{deployment_id}/revisions/{latest_revision_id}`.
|
||||
1. Call `PATCH /v2/deployments/{deployment_id}` to update the deployment.
|
||||
|
||||
## Example Code
|
||||
Below is example Python code that demonstrates how to orchestrate the LangGraph Control Plane APIs to create a deployment, update the deployment, and delete the deployment.
|
||||
```python
|
||||
import os
|
||||
import time
|
||||
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# required environment variables
|
||||
CONTROL_PLANE_HOST = os.getenv("CONTROL_PLANE_HOST")
|
||||
LANGSMITH_API_KEY = os.getenv("LANGSMITH_API_KEY")
|
||||
INTEGRATION_ID = os.getenv("INTEGRATION_ID")
|
||||
MAX_WAIT_TIME = 1800 # 30 mins
|
||||
|
||||
|
||||
def get_headers() -> dict:
|
||||
"""Return common headers for requests to LangGraph Control Plane API."""
|
||||
return {
|
||||
"X-Api-Key": LANGSMITH_API_KEY,
|
||||
}
|
||||
|
||||
|
||||
def create_deployment() -> str:
|
||||
"""Create deployment. Return deployment ID."""
|
||||
headers = get_headers()
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
deployment_name = "my_deployment"
|
||||
|
||||
request_body = {
|
||||
"name": deployment_name,
|
||||
"source": "github",
|
||||
"source_config": {
|
||||
"integration_id": INTEGRATION_ID,
|
||||
"repo_url": "https://github.com/langchain-ai/langgraph-example",
|
||||
"deployment_type": "dev",
|
||||
"build_on_push": False,
|
||||
"custom_url": None,
|
||||
"resource_spec": None,
|
||||
},
|
||||
"source_revision_config": {
|
||||
"repo_ref": "main",
|
||||
"langgraph_config_path": "langgraph.json",
|
||||
"image_uri": None,
|
||||
},
|
||||
"secrets": [
|
||||
{
|
||||
"name": "OPENAI_API_KEY",
|
||||
"value": "test_openai_api_key",
|
||||
},
|
||||
{
|
||||
"name": "ANTHROPIC_API_KEY",
|
||||
"value": "test_anthropic_api_key",
|
||||
},
|
||||
{
|
||||
"name": "TAVILY_API_KEY",
|
||||
"value": "test_tavily_api_key",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
url=f"{CONTROL_PLANE_HOST}/v2/deployments",
|
||||
headers=headers,
|
||||
json=request_body,
|
||||
)
|
||||
|
||||
if response.status_code != 201:
|
||||
raise Exception(f"Failed to create deployment: {response.text}")
|
||||
|
||||
deployment_id = response.json()["id"]
|
||||
print(f"Created deployment {deployment_name} ({deployment_id})")
|
||||
return deployment_id
|
||||
|
||||
|
||||
def get_deployment(deployment_id: str) -> dict:
|
||||
"""Get deployment."""
|
||||
response = requests.get(
|
||||
url=f"{CONTROL_PLANE_HOST}/v2/deployments/{deployment_id}",
|
||||
headers=get_headers(),
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Failed to get deployment ID {deployment_id}: {response.text}")
|
||||
|
||||
return response.json()
|
||||
|
||||
|
||||
def list_revisions(deployment_id: str) -> list[dict]:
|
||||
"""List revisions.
|
||||
|
||||
Return list is sorted by created_at in descending order (latest first).
|
||||
"""
|
||||
response = requests.get(
|
||||
url=f"{CONTROL_PLANE_HOST}/v2/deployments/{deployment_id}/revisions",
|
||||
headers=get_headers(),
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(
|
||||
f"Failed to list revisions for deployment ID {deployment_id}: {response.text}"
|
||||
)
|
||||
|
||||
return response.json()
|
||||
|
||||
|
||||
def get_revision(
|
||||
deployment_id: str,
|
||||
revision_id: str,
|
||||
) -> dict:
|
||||
"""Get revision."""
|
||||
response = requests.get(
|
||||
url=f"{CONTROL_PLANE_HOST}/v2/deployments/{deployment_id}/revisions/{revision_id}",
|
||||
headers=get_headers(),
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Failed to get revision ID {revision_id}: {response.text}")
|
||||
|
||||
return response.json()
|
||||
|
||||
|
||||
def patch_deployment(deployment_id: str) -> None:
|
||||
"""Patch deployment."""
|
||||
headers = get_headers()
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
response = requests.patch(
|
||||
url=f"{CONTROL_PLANE_HOST}/v2/deployments/{deployment_id}",
|
||||
headers=headers,
|
||||
json={
|
||||
"source_config": {
|
||||
"build_on_push": True,
|
||||
},
|
||||
"source_revision_config": {
|
||||
"repo_ref": "main",
|
||||
"langgraph_config_path": "langgraph.json",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Failed to patch deployment: {response.text}")
|
||||
|
||||
print(f"Patched deployment ID {deployment_id}")
|
||||
|
||||
|
||||
def wait_for_deployment(deployment_id: str, revision_id: str) -> None:
|
||||
"""Wait for revision status to be DEPLOYED."""
|
||||
start_time = time.time()
|
||||
revision, status = None, None
|
||||
while time.time() - start_time < MAX_WAIT_TIME:
|
||||
revision = get_revision(deployment_id, revision_id)
|
||||
status = revision["status"]
|
||||
if status == "DEPLOYED":
|
||||
break
|
||||
elif "FAILED" in status:
|
||||
raise Exception(f"Revision ID {revision_id} failed: {revision}")
|
||||
|
||||
print(f"Waiting for revision ID {revision_id} to be DEPLOYED...")
|
||||
time.sleep(60)
|
||||
|
||||
if status != "DEPLOYED":
|
||||
raise Exception(
|
||||
f"Timeout waiting for revision ID {revision_id} to be DEPLOYED: {revision}"
|
||||
)
|
||||
|
||||
|
||||
def delete_deployment(deployment_id: str) -> None:
|
||||
"""Delete deployment."""
|
||||
response = requests.delete(
|
||||
url=f"{CONTROL_PLANE_HOST}/v2/deployments/{deployment_id}",
|
||||
headers=get_headers(),
|
||||
)
|
||||
|
||||
if response.status_code != 204:
|
||||
raise Exception(
|
||||
f"Failed to delete deployment ID {deployment_id}: {response.text}"
|
||||
)
|
||||
|
||||
print(f"Deployment ID {deployment_id} deleted")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# create deployment and get the latest revision
|
||||
deployment_id = create_deployment()
|
||||
revisions = list_revisions(deployment_id)
|
||||
latest_revision = revisions["resources"][0]
|
||||
latest_revision_id = latest_revision["id"]
|
||||
|
||||
# wait for latest revision to be DEPLOYED
|
||||
wait_for_deployment(deployment_id, latest_revision_id)
|
||||
|
||||
# patch the deployment and get the latest revision
|
||||
patch_deployment(deployment_id)
|
||||
revisions = list_revisions(deployment_id)
|
||||
latest_revision = revisions["resources"][0]
|
||||
latest_revision_id = latest_revision["id"]
|
||||
|
||||
# wait for latest revision to be DEPLOYED
|
||||
wait_for_deployment(deployment_id, latest_revision_id)
|
||||
|
||||
# delete the deployment
|
||||
delete_deployment(deployment_id)
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
@@ -51,10 +51,9 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
|
||||
| <span style="white-space: nowrap;">`node_version`</span> | Specify `node_version: 20` to use LangGraph.js. |
|
||||
| <span style="white-space: nowrap;">`pip_config_file`</span> | Path to `pip` config file. |
|
||||
| <span style="white-space: nowrap;">`pip_installer`</span> | _(Added in v0.3)_ Optional. Python package installer selector. It can be set to `"auto"`, `"pip"`, or `"uv"`. From version 0.3 onward the default strategy is to run `uv pip`, which typically delivers faster builds while remaining a drop-in replacement. In the uncommon situation where `uv` cannot handle your dependency graph or the structure of your `pyproject.toml`, specify `"pip"` here to revert to the earlier behaviour. |
|
||||
| <span style="white-space: nowrap;">`keep_pkg_tools`</span> | _(Added in v0.3.4)_ Optional. Control whether to retain Python packaging tools (`pip`, `setuptools`, `wheel`) in the final image. Accepted values: <ul><li><code>true</code> : Keep all three tools (skip uninstall).</li><li><code>false</code> / omitted : Uninstall all three tools (default behaviour).</li><li><code>list[str]</code> : Names of tools <strong>to retain</strong>. Each value must be one of "pip", "setuptools", "wheel".</li></ul>. By default, all three tools are uninstalled. |
|
||||
| <span style="white-space: nowrap;">`dockerfile_lines`</span> | Array of additional lines to add to Dockerfile following the import from parent image. |
|
||||
| <span style="white-space: nowrap;">`checkpointer`</span> | Configuration for the checkpointer. Contains a `ttl` field which is an object with the following keys: <ul><li>`strategy`: How to handle expired checkpoints (e.g., `"delete"`).</li><li>`sweep_interval_minutes`: How often to check for expired checkpoints (integer).</li><li>`default_ttl`: Default time-to-live for checkpoints in **minutes** (integer). Defines how long checkpoints are kept before the specified strategy is applied.</li></ul> |
|
||||
| <span style="white-space: nowrap;">`http`</span> | HTTP server configuration with the following fields: <ul><li>`app`: Path to custom Starlette/FastAPI app (e.g., `"./src/agent/webapp.py:app"`). See [custom routes guide](../../how-tos/http/custom_routes.md).</li><li>`cors`: CORS configuration with fields for `allow_origins`, `allow_methods`, `allow_headers`, etc.</li><li>`configurable_headers`: Define which request headers to exclude or include as a run's configurable values.</li><li>`disable_assistants`: Disable `/assistants` routes</li><li>`disable_mcp`: Disable `/mcp` routes</li><li>`disable_meta`: Disable `/ok`, `/info`, `/metrics`, and `/docs` routes</li><li>`disable_runs`: Disable `/runs` routes</li><li>`disable_store`: Disable `/store` routes</li><li>`disable_threads`: Disable `/threads` routes</li><li>`disable_ui`: Disable `/ui` routes</li><li>`disable_webhooks`: Disable webhooks calls on run completion in all routes</li><li>`mount_prefix`: Prefix for mounted routes (e.g., "/my-deployment/api")</li></ul> |
|
||||
| <span style="white-space: nowrap;">`http`</span> | HTTP server configuration with the following fields: <ul><li>`app`: Path to custom Starlette/FastAPI app (e.g., `"./src/agent/webapp.py:app"`). See [custom routes guide](../../how-tos/http/custom_routes.md).</li><li>`disable_assistants`: Disable `/assistants` routes</li><li>`disable_threads`: Disable `/threads` routes</li><li>`disable_runs`: Disable `/runs` routes</li><li>`disable_store`: Disable `/store` routes</li><li>`disable_meta`: Disable `/ok`, `/info`, `/metrics`, and `/docs` routes</li><li>`disable_mcp`: Disable `/mcp` routes</li><li>`cors`: CORS configuration with fields for `allow_origins`, `allow_methods`, `allow_headers`, etc.</li><li>`configurable_headers`: Define which request headers to exclude or include as a run's configurable values.</li></ul> |
|
||||
|
||||
=== "JS"
|
||||
|
||||
@@ -396,7 +395,7 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
|
||||
|
||||
=== "Python"
|
||||
|
||||
Start LangGraph API server. For local testing, requires a LangSmith API key with access to LangGraph Platform. Requires a license key for production use.
|
||||
Start LangGraph API server. For local testing, requires a LangSmith API key with access to LangGraph Platform closed beta. Requires a license key for production use.
|
||||
|
||||
**Usage**
|
||||
|
||||
@@ -409,8 +408,6 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
|
||||
| Option | Default | Description |
|
||||
| ---------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
||||
| `--wait` | | Wait for services to start before returning. Implies --detach |
|
||||
| `--base-image TEXT` | `langchain/langgraph-api` | Base image to use for the LangGraph API server. Pin to specific versions using version tags. |
|
||||
| `--image TEXT` | | Docker image to use for the langgraph-api service. If specified, skips building and uses this image directly. |
|
||||
| `--postgres-uri TEXT` | Local database | Postgres URI to use for the database. |
|
||||
| `--watch` | | Restart on file changes |
|
||||
| `--debugger-base-url TEXT` | `http://127.0.0.1:[PORT]` | URL used by the debugger to access LangGraph API. |
|
||||
@@ -425,7 +422,7 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
|
||||
|
||||
=== "JS"
|
||||
|
||||
Start LangGraph API server. For local testing, requires a LangSmith API key with access to LangGraph Platform. Requires a license key for production use.
|
||||
Start LangGraph API server. For local testing, requires a LangSmith API key with access to LangGraph Platform closed beta. Requires a license key for production use.
|
||||
|
||||
**Usage**
|
||||
|
||||
@@ -438,8 +435,6 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
|
||||
| Option | Default | Description |
|
||||
| ---------------------------------------------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
||||
| <span style="white-space: nowrap;">`--wait`</span> | | Wait for services to start before returning. Implies --detach |
|
||||
| <span style="white-space: nowrap;">`--base-image TEXT`</span> | <span style="white-space: nowrap;">`langchain/langgraph-api`</span> | Base image to use for the LangGraph API server. Pin to specific versions using version tags. |
|
||||
| <span style="white-space: nowrap;">`--image TEXT`</span> | | Docker image to use for the langgraph-api service. If specified, skips building and uses this image directly. |
|
||||
| <span style="white-space: nowrap;">`--postgres-uri TEXT`</span> | Local database | Postgres URI to use for the database. |
|
||||
| <span style="white-space: nowrap;">`--watch`</span> | | Restart on file changes |
|
||||
| <span style="white-space: nowrap;">`-c, --config FILE`</span> | `langgraph.json` | Path to configuration file declaring dependencies, graphs and environment variables. |
|
||||
@@ -483,19 +478,19 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
|
||||
|
||||
RUN PIP_CONFIG_FILE=/pipconfig.txt PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt langchain_community langchain_anthropic langchain_openai wikipedia scikit-learn
|
||||
|
||||
ADD ./graphs /deps/outer-graphs/src
|
||||
ADD ./graphs /deps/__outer_graphs/src
|
||||
RUN set -ex && \
|
||||
for line in '[project]' \
|
||||
'name = "graphs"' \
|
||||
'version = "0.1"' \
|
||||
'[tool.setuptools.package-data]' \
|
||||
'"*" = ["**/*"]'; do \
|
||||
echo "$line" >> /deps/outer-graphs/pyproject.toml; \
|
||||
echo "$line" >> /deps/__outer_graphs/pyproject.toml; \
|
||||
done
|
||||
|
||||
RUN PIP_CONFIG_FILE=/pipconfig.txt PYTHONDONTWRITEBYTECODE=1 pip install --no-cache-dir -c /api/constraints.txt -e /deps/*
|
||||
|
||||
ENV LANGSERVE_GRAPHS='{"agent": "/deps/outer-graphs/src/agent.py:graph", "storm": "/deps/outer-graphs/src/storm.py:graph"}'
|
||||
ENV LANGSERVE_GRAPHS='{"agent": "/deps/__outer_graphs/src/agent.py:graph", "storm": "/deps/__outer_graphs/src/storm.py:graph"}'
|
||||
```
|
||||
|
||||
???+ note "Updating your langgraph.json file"
|
||||
|
||||
@@ -10,10 +10,6 @@ This environment variable should be set to `True` if the implementation of a gra
|
||||
|
||||
Defaults to `False`.
|
||||
|
||||
## `BG_JOB_SHUTDOWN_GRACE_PERIOD_SECS`
|
||||
|
||||
Specifies, in seconds, how long the server will wait for background jobs to finish after the queue receives a shutdown signal. After this period, the server will force termination. Defaults to `180` seconds. Set this to ensure jobs have enough time to complete cleanly during shutdown. Added in `langgraph-api==0.2.16`.
|
||||
|
||||
## `BG_JOB_TIMEOUT_SECS`
|
||||
|
||||
The timeout of a background run can be increased. However, the infrastructure for a Cloud SaaS deployment enforces a 1 hour timeout limit for API requests. This means the connection between client and server will timeout after 1 hour. This is not configurable.
|
||||
@@ -22,15 +18,16 @@ A background run can execute for longer than 1 hour, but a client must reconnect
|
||||
|
||||
Defaults to `3600`.
|
||||
|
||||
## `BG_JOB_SHUTDOWN_GRACE_PERIOD_SECS`
|
||||
|
||||
Specifies, in seconds, how long the server will wait for background jobs to finish after the queue receives a shutdown signal. After this period, the server will force termination. Defaults to `3600` seconds. Set this to ensure jobs have enough time to complete cleanly during shutdown. Added in `langgraph-api==0.2.16`.
|
||||
|
||||
## `DD_API_KEY`
|
||||
|
||||
Specify `DD_API_KEY` (your [Datadog API Key](https://docs.datadoghq.com/account_management/api-app-keys/)) to automatically enable Datadog tracing for the deployment. Specify other [`DD_*` environment variables](https://ddtrace.readthedocs.io/en/stable/configuration.html) to configure the tracing instrumentation.
|
||||
|
||||
If `DD_API_KEY` is specified, the application process is wrapped in the [`ddtrace-run` command](https://ddtrace.readthedocs.io/en/stable/installation_quickstart.html). Other `DD_*` environment variables (e.g. `DD_SITE`, `DD_ENV`, `DD_SERVICE`, `DD_TRACE_ENABLED`) are typically needed to properly configure the tracing instrumentation. See [`DD_*` environment variables](https://ddtrace.readthedocs.io/en/stable/configuration.html) for more details.
|
||||
|
||||
!!! note
|
||||
Enabling `DD_API_KEY` (and thus `ddtrace-run`) can override or interfere with other auto-instrumentation solutions (such as OpenTelemetry) that you may have instrumented into your application code.
|
||||
|
||||
## `LANGCHAIN_TRACING_SAMPLING_RATE`
|
||||
|
||||
Sampling rate for traces sent to LangSmith. Valid values: Any float between `0` and `1`.
|
||||
@@ -43,14 +40,6 @@ Type of authentication for the LangGraph Server deployment. Valid values: `langs
|
||||
|
||||
For deployments to LangGraph Platform, this environment variable is set automatically. For local development or deployments where authentication is handled externally (e.g. self-hosted), set this environment variable to `noop`.
|
||||
|
||||
## `LANGGRAPH_POSTGRES_POOL_MAX_SIZE`
|
||||
|
||||
Beginning with langgraph-api version `0.2.12`, the maximum size of the Postgres connection pool (per replica) can be controlled using the `LANGGRAPH_POSTGRES_POOL_MAX_SIZE` environment variable. By setting this variable, you can determine the upper bound on the number of simultaneous connections the server will establish with the Postgres database.
|
||||
|
||||
For example, if a deployment is scaled up to 10 replicas and `LANGGRAPH_POSTGRES_POOL_MAX_SIZE` is configured to `150`, then up to `1500` connections to Postgres can be established. This is particularly useful for deployments where database resources are limited (or more available) or where you need to tune connection behavior for performance or scaling reasons.
|
||||
|
||||
Defaults to `150` connections.
|
||||
|
||||
## `LANGSMITH_RUNS_ENDPOINTS`
|
||||
|
||||
For deployments with [self-hosted LangSmith](https://docs.smith.langchain.com/self_hosting) only.
|
||||
@@ -65,10 +54,6 @@ Set `LANGSMITH_TRACING` to `false` to disable tracing to LangSmith.
|
||||
|
||||
Defaults to `true`.
|
||||
|
||||
## `LOG_COLOR`
|
||||
|
||||
This is mainly relevant in the context of using the dev server via the `langgraph dev` command. Set `LOG_COLOR` to `true` to enable ANSI-colored console output when using the default console renderer. Disabling color output by setting this variable to `false` produces monochrome logs. Defaults to `true`.
|
||||
|
||||
## `LOG_LEVEL`
|
||||
|
||||
Configure [log level](https://docs.python.org/3/library/logging.html#logging-levels). Defaults to `INFO`.
|
||||
@@ -77,14 +62,9 @@ Configure [log level](https://docs.python.org/3/library/logging.html#logging-lev
|
||||
|
||||
Set `LOG_JSON` to `true` to render all log messages as JSON objects using the configured `JSONRenderer`. This produces structured logs that can be easily parsed or ingested by log management systems. Defaults to `false`.
|
||||
|
||||
## `MOUNT_PREFIX`
|
||||
## `LOG_COLOR`
|
||||
|
||||
!!! info "Only Allowed in Self-Hosted Deployments"
|
||||
The `MOUNT_PREFIX` environment variable is only allowed in Self-Hosted Deployment models, LangGraph Platform SaaS will not allow this environment variable.
|
||||
|
||||
Set `MOUNT_PREFIX` to serve the LangGraph Server under a specific path prefix. This is useful for deployments where the server is behind a reverse proxy or load balancer that requires a specific path prefix.
|
||||
|
||||
For example, if the server is to be served under `https://example.com/langgraph`, set `MOUNT_PREFIX` to `/langgraph`.
|
||||
This is mainly relevant in the context of using the dev server via the `langgraph dev` command. Set `LOG_COLOR` to `true` to enable ANSI-colored console output when using the default console renderer. Disabling color output by setting this variable to `false` produces monochrome logs. Defaults to `true`.
|
||||
|
||||
## `N_JOBS_PER_WORKER`
|
||||
|
||||
@@ -114,14 +94,16 @@ Database Connectivity:
|
||||
|
||||
- The custom Postgres instance must be accessible by the LangGraph Server. The user is responsible for ensuring connectivity.
|
||||
|
||||
## `REDIS_CLUSTER`
|
||||
## `LANGGRAPH_POSTGRES_POOL_MAX_SIZE`
|
||||
|
||||
!!! info "Only Allowed in Self-Hosted Deployments"
|
||||
Redis Cluster mode is only available in Self-Hosted Deployment models, LangGraph Platform SaaS will provision a redis instance for you by default.
|
||||
Beginning with langgraph-api version `0.2.12`, the maximum size of the Postgres connection pool can be controlled using the `LANGGRAPH_POSTGRES_POOL_MAX_SIZE` environment variable. By setting this variable, you can determine the upper bound on the number of simultaneous connections the server will establish with the Postgres database. This is particularly useful for deployments where database resources are limited (or more available) or where you need to tune connection behavior for performance or scaling reasons. If not specified, the pool size defaults to 150 connections.
|
||||
|
||||
Set `REDIS_CLUSTER` to `True` to enable Redis Cluster mode. When enabled, the system will connect to Redis using cluster mode. This is useful when connecting to a Redis Cluster deployment.
|
||||
## `REDIS_URI_CUSTOM`
|
||||
|
||||
Defaults to `False`.
|
||||
!!! info "Only for Self-Hosted Data Plane and Self-Hosted Control Plane"
|
||||
Custom Redis instances are only available for [Self-Hosted Data Plane](../../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../../concepts/langgraph_self_hosted_control_plane.md) deployments.
|
||||
|
||||
Specify `REDIS_URI_CUSTOM` to use a custom Redis instance. The value of `REDIS_URI_CUSTOM` must be a valid [Redis connection URI](https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis.from_url).
|
||||
|
||||
## `REDIS_KEY_PREFIX`
|
||||
|
||||
@@ -132,19 +114,20 @@ Specify a prefix for Redis keys. This allows multiple LangGraph Server instances
|
||||
|
||||
Defaults to `''`.
|
||||
|
||||
## `REDIS_URI_CUSTOM`
|
||||
## `REDIS_CLUSTER`
|
||||
|
||||
!!! info "Only for Self-Hosted Data Plane and Self-Hosted Control Plane"
|
||||
Custom Redis instances are only available for [Self-Hosted Data Plane](../../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../../concepts/langgraph_self_hosted_control_plane.md) deployments.
|
||||
!!! info "Only Allowed in Self-Hosted Deployments"
|
||||
Redis Cluster mode is only available in Self-Hosted Deployment models, LangGraph Platform SaaS will provision a redis instance for you by default.
|
||||
|
||||
Specify `REDIS_URI_CUSTOM` to use a custom Redis instance. The value of `REDIS_URI_CUSTOM` must be a valid [Redis connection URI](https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis.from_url).
|
||||
Set `REDIS_CLUSTER` to `True` to enable Redis Cluster mode. When enabled, the system will connect to Redis using cluster mode. This is useful when connecting to a Redis Cluster deployment.
|
||||
|
||||
## `RESUMABLE_STREAM_TTL_SECONDS`
|
||||
Defaults to `False`.
|
||||
|
||||
Time-to-live in seconds for resumable stream data in Redis.
|
||||
## `MOUNT_PREFIX`
|
||||
|
||||
When a run is created and the output is streamed, the stream can be configured to be resumable (e.g. `stream_resumable=True`). If a stream is resumable, output from the stream is temporarily stored in Redis. The TTL for this data can be configured by setting `RESUMABLE_STREAM_TTL_SECONDS`.
|
||||
!!! info "Only Allowed in Self-Hosted Deployments"
|
||||
The `MOUNT_PREFIX` environment variable is only allowed in Self-Hosted Deployment models, LangGraph Platform SaaS will not allow this environment variable.
|
||||
|
||||
See the [Python](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.RunsClient.stream) and [JS/TS](https://langchain-ai.github.io/langgraphjs/reference/classes/sdk_client.RunsClient.html#stream) SDKs for more details on how to implement resumable streams.
|
||||
Set `MOUNT_PREFIX` to serve the LangGraph Server under a specific path prefix. This is useful for deployments where the server is behind a reverse proxy or load balancer that requires a specific path prefix.
|
||||
|
||||
Defaults to `120` seconds.
|
||||
For example, if the server is to be served under `https://example.com/langgraph`, set `MOUNT_PREFIX` to `/langgraph`.
|
||||
|
||||
@@ -1,233 +0,0 @@
|
||||
# LangGraph Server Changelog
|
||||
|
||||
> **Note:** This changelog is no longer actively maintained. For the most up-to-date LangGraph Server changelog, please visit our new documentation site: [LangGraph Server Changelog](https://docs.langchain.com/langgraph-platform/langgraph-server-changelog#langgraph-server-changelog)
|
||||
|
||||
[LangGraph Server](../../concepts/langgraph_server.md) is an API platform for creating and managing agent-based applications. It provides built-in persistence, a task queue, and supports deploying, configuring, and running assistants (agentic workflows) at scale. This changelog documents all notable updates, features, and fixes to LangGraph Server releases.
|
||||
|
||||
---
|
||||
|
||||
## v0.2.111 (2025-07-29)
|
||||
- Started the heartbeat immediately upon connection to prevent JS graph streaming errors during long startups.
|
||||
|
||||
## v0.2.110 (2025-07-29)
|
||||
- Added interrupts as default values for all operations except streams to maintain consistent behavior.
|
||||
|
||||
## v0.2.109 (2025-07-28)
|
||||
- Fixed an issue where missing config schema occurred when `config_type` was not set.
|
||||
|
||||
## v0.2.108 (2025-07-28)
|
||||
- Added compatibility for langgraph v0.6, including new context API support and a migration to enhance context handling in assistant operations.
|
||||
|
||||
## v0.2.107 (2025-07-27)
|
||||
- Implemented caching for authentication processes to improve performance.
|
||||
- Merged count and select queries to improve database query efficiency.
|
||||
|
||||
## v0.2.106 (2025-07-27)
|
||||
- Log whether run uses resumable streams.
|
||||
|
||||
## v0.2.105 (2025-07-27)
|
||||
- Added a `/heapdump` endpoint to capture and save JS process heap data.
|
||||
|
||||
## v0.2.103 (2025-07-25)
|
||||
- Corrected the metadata endpoint to ensure accurate data retrieval.
|
||||
|
||||
## v0.2.102 (2025-07-24)
|
||||
- Captured interrupt events in the wait method to preserve legacy behavior and stream updates by default.
|
||||
- Added support for SDK structlog in the JavaScript environment, enhancing logging capabilities.
|
||||
|
||||
## v0.2.101 (2025-07-24)
|
||||
- Used the correct metadata endpoint for self-hosted environments, resolving an access issue.
|
||||
|
||||
## v0.2.99 (2025-07-22)
|
||||
- Improved license validation by adding an in-memory cache and handling Redis connection errors more effectively.
|
||||
- Automatically remove agents from memory that are removed from `langgraph.json` to prevent persistence issues.
|
||||
- Ensured the UI namespace for generated UI is a valid JavaScript property name to prevent errors.
|
||||
- Raised a 422 error for improved request validation feedback.
|
||||
|
||||
## v0.2.98 (2025-07-19)
|
||||
- Added langgraph node context for improved log filtering and trace visibility.
|
||||
|
||||
## v0.2.97 (2025-07-19)
|
||||
- Fixed scheduling issue with ckpt ingestion worker that occurred on isolated background loops.
|
||||
- Ensured queue worker starts only after all migrations have completed.
|
||||
- Added more detailed error messages for thread state issues and improved response handling when state updates fail.
|
||||
- Exposed interrupt ID while retrieving thread state for enhanced API response details.
|
||||
|
||||
## v0.2.96 (2025-07-17)
|
||||
- Added a fallback mechanism for configurable header patterns to handle exclude/include settings more effectively.
|
||||
|
||||
## v0.2.95 (2025-07-17)
|
||||
- Avoided setting the future if it is already done to prevent redundant operations.
|
||||
- Resolved compatibility errors in CI by switching from `typing.TypedDict` to `typing_extensions.TypedDict` for Python versions below 3.12.
|
||||
|
||||
## v0.2.94 (2025-07-16)
|
||||
- Improved performance by omitting pending sends for langgraph versions 0.5 and above.
|
||||
- Improved server startup logs to provide clearer warnings when the DD_API_KEY environment variable is set.
|
||||
|
||||
## v0.2.93 (2025-07-16)
|
||||
- Removed the GIN index for run metadata to improve performance.
|
||||
|
||||
## v0.2.92 (2025-07-16)
|
||||
- Enabled copying functionality for blobs and checkpoints, improving data management flexibility.
|
||||
|
||||
## v0.2.91 (2025-07-16)
|
||||
- Reduced writes to the `checkpoint_blobs` table by inlining small values (null, numeric, str, etc.). This means we don't need to store extra values for channels that haven't been updated.
|
||||
|
||||
## v0.2.90 (2025-07-16)
|
||||
- Improve checkpoint writes via node-local background queueing.
|
||||
|
||||
|
||||
## v0.2.89 (2025-07-15)
|
||||
- Decoupled checkpoint writing from thread/run state by removing foreign keys and updated logger to prevent timeout-related failures.
|
||||
|
||||
## v0.2.88 (2025-07-14)
|
||||
- Removed the foreign key constraint for `thread` in the `run` table to simplify database schema.
|
||||
|
||||
## v0.2.87 (2025-07-14)
|
||||
- Added more detailed logs for Redis worker signaling to improve debugging.
|
||||
|
||||
## v0.2.86 (2025-07-11)
|
||||
- Honored tool descriptions in the `/mcp` endpoint to align with expected functionality.
|
||||
|
||||
## v0.2.85 (2025-07-10)
|
||||
- Added support for the `on_disconnect` field to `runs/wait` and included disconnect logs for better debugging.
|
||||
|
||||
## v0.2.84 (2025-07-09)
|
||||
- Removed unnecessary status updates to streamline thread handling and updated version to 0.2.84.
|
||||
|
||||
## v0.2.83 (2025-07-09)
|
||||
- Reduced the default time-to-live for resumable streams to 2 minutes.
|
||||
- Enhanced data submission logic to send data to both Beacon and LangSmith instance based on license configuration.
|
||||
- Enabled submission of self-hosted data to a Langsmith instance when the endpoint is configured.
|
||||
|
||||
## v0.2.82 (2025-07-03)
|
||||
- Addressed a race condition in background runs by implementing a lock using join, ensuring reliable execution across CTEs.
|
||||
|
||||
## v0.2.81 (2025-07-03)
|
||||
- Optimized run streams by reducing initial wait time to improve responsiveness for older or non-existent runs.
|
||||
|
||||
## v0.2.80 (2025-07-03)
|
||||
- Corrected parameter passing in the `logger.ainfo()` API call to resolve a TypeError.
|
||||
|
||||
## v0.2.79 (2025-07-02)
|
||||
- Fixed a JsonDecodeError in checkpointing with remote graph by correcting JSON serialization to handle trailing slashes properly.
|
||||
- Introduced a configuration flag to disable webhooks globally across all routes.
|
||||
|
||||
## v0.2.78 (2025-07-02)
|
||||
- Added timeout retries to webhook calls to improve reliability.
|
||||
- Added HTTP request metrics, including a request count and latency histogram, for enhanced monitoring capabilities.
|
||||
|
||||
## v0.2.77 (2025-07-02)
|
||||
- Added HTTP metrics to improve performance monitoring.
|
||||
- Changed the Redis cache delimiter to reduce conflicts with subgraph message names and updated caching behavior.
|
||||
|
||||
## v0.2.76 (2025-07-01)
|
||||
- Updated Redis cache delimiter to prevent conflicts with subgraph messages.
|
||||
|
||||
## v0.2.74 (2025-06-30)
|
||||
- Scheduled webhooks in an isolated loop to ensure thread-safe operations and prevent errors with PYTHONASYNCIODEBUG=1.
|
||||
|
||||
## v0.2.73 (2025-06-27)
|
||||
- Fixed an infinite frame loop issue and removed the dict_parser due to structlog's unexpected behavior.
|
||||
- Throw a 409 error on deadlock occurrence during run cancellations to handle lock conflicts gracefully.
|
||||
|
||||
## v0.2.72 (2025-06-27)
|
||||
- Ensured compatibility with future langgraph versions.
|
||||
- Implemented a 409 response status to handle deadlock issues during cancellation.
|
||||
|
||||
## v0.2.71 (2025-06-26)
|
||||
- Improved logging for better clarity and detail regarding log types.
|
||||
|
||||
## v0.2.70 (2025-06-26)
|
||||
- Improved error handling to better distinguish and log TimeoutErrors caused by users from internal run timeouts.
|
||||
|
||||
## v0.2.69 (2025-06-26)
|
||||
- Added sorting and pagination to the crons API and updated schema definitions for improved accuracy.
|
||||
|
||||
## v0.2.66 (2025-06-26)
|
||||
- Fixed a 404 error when creating multiple runs with the same thread_id using `on_not_exist="create"`.
|
||||
|
||||
## v0.2.65 (2025-06-25)
|
||||
- Ensured that only fields from `assistant_versions` are returned when necessary.
|
||||
- Ensured consistent data types for in-memory and PostgreSQL users, improving internal authentication handling.
|
||||
|
||||
## v0.2.64 (2025-06-24)
|
||||
- Added descriptions to version entries for better clarity.
|
||||
|
||||
## v0.2.62 (2025-06-23)
|
||||
- Improved user handling for custom authentication in the JS Studio.
|
||||
- Added Prometheus-format run statistics to the metrics endpoint for better monitoring.
|
||||
- Added run statistics in Prometheus format to the metrics endpoint.
|
||||
|
||||
## v0.2.61 (2025-06-20)
|
||||
- Set a maximum idle time for Redis connections to prevent unnecessary open connections.
|
||||
|
||||
## v0.2.60 (2025-06-20)
|
||||
- Enhanced error logging to include traceback details for dictionary operations.
|
||||
- Added a `/metrics` endpoint to expose queue worker metrics for monitoring.
|
||||
|
||||
## v0.2.57 (2025-06-18)
|
||||
- Removed CancelledError from retriable exceptions to allow local interrupts while maintaining retriability for workers.
|
||||
- Introduced middleware to gracefully shut down the server after completing in-flight requests upon receiving a SIGINT.
|
||||
- Reduced metadata stored in checkpoint to only include necessary information.
|
||||
- Improved error handling in join runs to return error details when present.
|
||||
|
||||
## v0.2.56 (2025-06-17)
|
||||
- Improved application stability by adding a handler for SIGTERM signals.
|
||||
|
||||
## v0.2.55 (2025-06-17)
|
||||
- Improved the handling of cancellations in the queue entrypoint.
|
||||
- Improved cancellation handling in the queue entry point.
|
||||
|
||||
## v0.2.54 (2025-06-16)
|
||||
- Enhanced error message for LuaLock timeout during license validation.
|
||||
- Fixed the $contains filter in custom auth by requiring an explicit ::text cast and updated tests accordingly.
|
||||
- Ensured project and tenant IDs are formatted as UUIDs for consistency.
|
||||
|
||||
## v0.2.53 (2025-06-13)
|
||||
- Resolved a timing issue to ensure the queue starts only after the graph is registered.
|
||||
- Improved performance by setting thread and run status in a single query and enhanced error handling during checkpoint writes.
|
||||
- Reduced the default background grace period to 3 minutes.
|
||||
|
||||
## v0.2.52 (2025-06-12)
|
||||
- Now logging expected graphs when one is omitted to improve traceability.
|
||||
- Implemented a time-to-live (TTL) feature for resumable streams.
|
||||
- Improved query efficiency and consistency by adding a unique index and optimizing row locking.
|
||||
|
||||
## v0.2.51 (2025-06-12)
|
||||
- Handled `CancelledError` by marking tasks as ready to retry, improving error management in worker processes.
|
||||
- Added LG API version and request ID to metadata and logs for better tracking.
|
||||
- Added LG API version and request ID to metadata and logs to improve traceability.
|
||||
- Improved database performance by creating indexes concurrently.
|
||||
- Ensured postgres write is committed only after the Redis running marker is set to prevent race conditions.
|
||||
- Enhanced query efficiency and reliability by adding a unique index on thread_id/running, optimizing row locks, and ensuring deterministic run selection.
|
||||
- Resolved a race condition by ensuring Postgres updates only occur after the Redis running marker is set.
|
||||
|
||||
## v0.2.46 (2025-06-07)
|
||||
- Introduced a new connection for each operation while preserving transaction characteristics in Threads state `update()` and `bulk()` commands.
|
||||
|
||||
## v0.2.45 (2025-06-05)
|
||||
- Enhanced streaming feature by incorporating tracing contexts.
|
||||
- Removed an unnecessary query from the Crons.search function.
|
||||
- Resolved connection reuse issue when scheduling next run for multiple cron jobs.
|
||||
- Removed an unnecessary query in the Crons.search function to improve efficiency.
|
||||
- Resolved an issue with scheduling the next cron run by improving connection reuse.
|
||||
|
||||
## v0.2.44 (2025-06-04)
|
||||
- Enhanced the worker logic to exit the pipeline before continuing when the Redis message limit is reached.
|
||||
- Introduced a ceiling for Redis message size with an option to skip messages larger than 128 MB for improved performance.
|
||||
- Ensured the pipeline always closes properly to prevent resource leaks.
|
||||
|
||||
## v0.2.43 (2025-06-04)
|
||||
- Improved performance by omitting logs in metadata calls and ensuring output schema compliance in value streaming.
|
||||
- Ensured the connection is properly closed after use.
|
||||
- Aligned output format to strictly adhere to the specified schema.
|
||||
- Stopped sending internal logs in metadata requests to improve privacy.
|
||||
|
||||
## v0.2.42 (2025-06-04)
|
||||
- Added timestamps to track the start and end of a request's run.
|
||||
- Added tracer information to the configuration settings.
|
||||
- Added support for streaming with tracing contexts.
|
||||
|
||||
## v0.2.41 (2025-06-03)
|
||||
- Added locking mechanism to prevent errors in pipelined executions.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -97,7 +97,7 @@ Parallel processing is vital for efficient multi-agent systems and complex tasks
|
||||
- Implementation of map-reduce-like operations
|
||||
- Efficient handling of independent subtasks
|
||||
|
||||
For practical implementation, see our [map-reduce tutorial](../how-tos/graph-api.md#map-reduce-and-the-send-api)
|
||||
For practical implementation, see our [map-reduce tutorial](../how-tos/graph-api.ipynb#map-reduce-and-the-send-api)
|
||||
|
||||
### Subgraphs
|
||||
|
||||
@@ -107,7 +107,7 @@ For practical implementation, see our [map-reduce tutorial](../how-tos/graph-api
|
||||
- Hierarchical organization of agent teams
|
||||
- Controlled communication between agents and the main system
|
||||
|
||||
Subgraphs communicate with the parent graph through overlapping keys in the state schema. This enables flexible, modular agent design. For implementation details, refer to our [subgraph how-to guide](../how-tos/subgraph.md).
|
||||
Subgraphs communicate with the parent graph through overlapping keys in the state schema. This enables flexible, modular agent design. For implementation details, refer to our [subgraph how-to guide](../how-tos/subgraph.ipynb).
|
||||
|
||||
### Reflection
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ Below are examples of directory structures for applications:
|
||||
│ ├── utils # utilities for your graph
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── tools.py # tools for your graph
|
||||
│ │ ├── nodes.py # node functions for your graph
|
||||
│ │ ├── nodes.py # node functions for you graph
|
||||
│ │ └── state.py # state definition of your graph
|
||||
│ ├── __init__.py
|
||||
│ └── agent.py # code for constructing your graph
|
||||
@@ -61,6 +61,8 @@ Below are examples of directory structures for applications:
|
||||
|
||||
:::
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
|
||||
```plaintext
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Assistants
|
||||
|
||||
**Assistants** allow you to manage configurations (like prompts, LLM selection, tools) separately from your graph's core logic, enabling rapid changes that don't alter the graph architecture. It is a way to create multiple specialized versions of the same graph architecture, each optimized for different use cases through context/configuration variations rather than structural changes.
|
||||
**Assistants** allow you to manage configurations (like prompts, LLM selection, tools) separately from your graph's core logic, enabling rapid changes that don't alter the graph architecture. It is a way to create multiple specialized versions of the same graph architecture, each optimized for different use cases through configuration variations rather than structural changes.
|
||||
|
||||
For example, imagine a general-purpose writing agent built on a common graph architecture. While the structure remains the same, different writing styles—such as blog posts and tweets—require tailored configurations to optimize performance. To support these variations, you can create multiple assistants (e.g., one for blogs and another for tweets) that share the underlying graph but differ in model selection and system prompt.
|
||||
|
||||
@@ -14,11 +14,8 @@ The LangGraph Cloud API provides several endpoints for creating and managing ass
|
||||
|
||||
## Configuration
|
||||
|
||||
:::python
|
||||
Assistants build on the LangGraph open source concepts of configuration and [runtime context](low_level.md#runtime-context).
|
||||
:::
|
||||
|
||||
While these features are available in the open source LangGraph library, assistants are only present in [LangGraph Platform](langgraph_platform.md). This is due to the fact that assistants are tightly coupled to your deployed graph. Upon deployment, LangGraph Server will automatically create a default assistant for each graph using the graph's default context and configuration settings.
|
||||
Assistants build on the LangGraph open source concept of [configuration](low_level.md#configuration).
|
||||
While configuration is available in the open source LangGraph library, assistants are only present in [LangGraph Platform](langgraph_platform.md). This is due to the fact that assistants are tightly coupled to your deployed graph. Upon deployment, LangGraph Server will automatically create a default assistant for each graph using the graph's default configuration settings.
|
||||
|
||||
In practice, an assistant is just an _instance_ of a graph with a specific configuration. Therefore, multiple assistants can reference the same graph but can contain different configurations (e.g. prompts, models, tools). The LangGraph Server API provides several endpoints for creating and managing assistants. See the [API reference](../cloud/reference/api/api_ref.html) and [this how-to](../cloud/how-tos/configuration_cloud.md) for more details on how to create assistants.
|
||||
|
||||
@@ -29,6 +26,6 @@ Once you've created an assistant, subsequent edits to that assistant will create
|
||||
|
||||
## Execution
|
||||
|
||||
A **run** is an invocation of an assistant. Each run may have its own input, configuration, context, and metadata, which may affect execution and output of the underlying graph. A run can optionally be executed on a [thread](./persistence.md#threads).
|
||||
A **run** is an invocation of an assistant. Each run may have its own input, configuration, and metadata, which may affect execution and output of the underlying graph. A run can optionally be executed on a [thread](./persistence.md#threads).
|
||||
|
||||
The LangGraph Platform API provides several endpoints for creating and managing runs. See the [API reference](../cloud/reference/api/api_ref.html#tag/thread-runs/) for more details.
|
||||
|
||||
+10
-54
@@ -35,8 +35,7 @@ LangGraph Platform provides different security defaults:
|
||||
- Can be customized with your auth handler
|
||||
|
||||
!!! note "Custom auth"
|
||||
|
||||
Custom auth **is supported** for all plans in LangGraph Platform.
|
||||
Custom auth **is supported** for all plans in LangGraph Platform.
|
||||
|
||||
### Self-Hosted
|
||||
|
||||
@@ -44,6 +43,10 @@ LangGraph Platform provides different security defaults:
|
||||
- Complete flexibility to implement your security model
|
||||
- You control all aspects of authentication and authorization
|
||||
|
||||
!!! note "Custom auth"
|
||||
Custom auth is supported for **Enterprise** self-hosted deployments.
|
||||
Standalone Container (Lite) deployments do not support custom auth natively.
|
||||
|
||||
## System Architecture
|
||||
|
||||
A typical authentication setup involves three main components:
|
||||
@@ -92,7 +95,7 @@ Your [`@auth.authenticate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_s
|
||||
:::
|
||||
|
||||
:::js
|
||||
Your [`auth.authenticate`](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#authenticate) handler in LangGraph handles steps 4-6, while your [`auth.on`](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#on>) handlers implement step 7.
|
||||
Your [`auth.authenticate`](<insert-ref (https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#authenticate)>) handler in LangGraph handles steps 4-6, while your [`auth.on`](<insert-ref https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#on>) handlers implement step 7.
|
||||
:::
|
||||
|
||||
## Authentication
|
||||
@@ -139,11 +142,11 @@ The returned user information is available:
|
||||
:::
|
||||
|
||||
:::js
|
||||
Authentication in LangGraph runs as middleware on every request. Your [`authenticate`](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#authenticate>) handler receives request information and should:
|
||||
Authentication in LangGraph runs as middleware on every request. Your [`authenticate`](<insert-ref https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#authenticate>) handler receives request information and should:
|
||||
|
||||
1. Validate the credentials
|
||||
2. Return user information containing the user's identity and user information if valid
|
||||
3. Raise an [HTTPException](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#class-httpexception>) if invalid
|
||||
3. Raise an [HTTPException](<insert-ref https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#class-httpexception>) if invalid
|
||||
|
||||
```typescript
|
||||
import { Auth, HTTPException } from "@langchain/langgraph-sdk";
|
||||
@@ -192,7 +195,7 @@ The returned user information is available:
|
||||
:::
|
||||
|
||||
:::js
|
||||
The [`authenticate`](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#authenticate) handler can accept any of the following parameters:
|
||||
The [`authenticate`](<insert-ref https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#authenticate>) handler can accept any of the following parameters:
|
||||
|
||||
* request (Request): The raw request object
|
||||
* body (object): The parsed request body
|
||||
@@ -207,54 +210,6 @@ The returned user information is available:
|
||||
In many of our tutorials, we will just show the "authorization" parameter to be concise, but you can opt to accept more information as needed
|
||||
to implement your custom authentication scheme.
|
||||
|
||||
### Agent authentication
|
||||
|
||||
Custom authentication permits delegated access. The values you return in `@auth.authenticate` are added to the run context, giving agents user-scoped credentials lets them access resources on the user’s behalf.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
%% Actors
|
||||
participant ClientApp as Client
|
||||
participant AuthProv as Auth Provider
|
||||
participant LangGraph as LangGraph Backend
|
||||
participant SecretStore as Secret Store
|
||||
participant ExternalService as External Service
|
||||
|
||||
%% Platform login / AuthN
|
||||
ClientApp ->> AuthProv: 1. Login (username / password)
|
||||
AuthProv -->> ClientApp: 2. Return token
|
||||
ClientApp ->> LangGraph: 3. Request with token
|
||||
|
||||
Note over LangGraph: 4. Validate token (@auth.authenticate)
|
||||
LangGraph -->> AuthProv: 5. Fetch user info
|
||||
AuthProv -->> LangGraph: 6. Confirm validity
|
||||
|
||||
%% Fetch user tokens from secret store
|
||||
LangGraph ->> SecretStore: 6a. Fetch user tokens
|
||||
SecretStore -->> LangGraph: 6b. Return tokens
|
||||
|
||||
Note over LangGraph: 7. Apply access control (@auth.on.*)
|
||||
|
||||
%% External Service round-trip
|
||||
LangGraph ->> ExternalService: 8. Call external service (with header)
|
||||
Note over ExternalService: 9. External service validates header and executes action
|
||||
ExternalService -->> LangGraph: 10. Service response
|
||||
|
||||
%% Return to caller
|
||||
LangGraph -->> ClientApp: 11. Return resources
|
||||
```
|
||||
|
||||
After authentication, the platform creates a special configuration object that is passed to your graph and all nodes via the configurable context.
|
||||
This object contains information about the current user, including any custom fields you return from your [`@auth.authenticate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.authenticate) handler.
|
||||
|
||||
To enable an agent to act on behalf of the user, use [custom authentication middleware](../how-tos/auth/custom_auth.md). This will allow the agent to interact with external systems like MCP servers, external databases, and even other agents on behalf of the user.
|
||||
|
||||
For more information, see the [Use custom auth](../how-tos/auth/custom_auth.md#enable-agent-authentication) guide.
|
||||
|
||||
### Agent authentication with MCP
|
||||
|
||||
For information on how to authenticate an agent to an MCP server, see the [MCP conceptual guide](../concepts/mcp.md).
|
||||
|
||||
## Authorization
|
||||
|
||||
After authentication, LangGraph calls your authorization handlers to control access to specific resources (e.g., threads, assistants, crons). These handlers can:
|
||||
@@ -738,6 +693,7 @@ Each handler has type hints available for its `value` parameter. For example:
|
||||
):
|
||||
...
|
||||
```
|
||||
:::
|
||||
|
||||
More specific handlers provide better type hints since they handle fewer action types.
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
search:
|
||||
boost: 2
|
||||
---
|
||||
|
||||
# Breakpoints
|
||||
|
||||
[Breakpoints](../how-tos/human_in_the_loop/breakpoints.md) pause graph execution at defined points and let you step through each stage. They use LangGraph's [**persistence layer**](./persistence.md), which saves the graph state after each step.
|
||||
|
||||
With breakpoints, you can inspect the graph's state and node inputs at any point. Execution pauses **indefinitely** until you resume, as the checkpointer preserves the state.
|
||||
|
||||
<figure markdown="1">
|
||||
{: style="max-height:400px"}
|
||||
<figcaption>An example graph consisting of 3 sequential steps with a breakpoint before step_3. </figcaption> </figure>
|
||||
|
||||
!!! tip
|
||||
|
||||
For information on how to use breakpoints, see [Set breakpoints](../how-tos/human_in_the_loop/breakpoints.md) and [Set breakpoints using Server API](../cloud/how-tos/human_in_the_loop_breakpoint.md).
|
||||
@@ -7,7 +7,10 @@ search:
|
||||
|
||||
## Free deployment
|
||||
|
||||
[Local](../tutorials/langgraph-platform/local-server.md): Deploy for local testing and development.
|
||||
There are two free options for deploying LangGraph applications via the LangGraph Server:
|
||||
|
||||
1. [Local](../tutorials/langgraph-platform/local-server.md): Deploy for local testing and development.
|
||||
1. [Standalone Container (Lite)](../concepts/langgraph_standalone_container.md): A limited version of Standalone Container for deployments unlikely to see more that 1 million node executions per year and that do not need crons and other enterprise features. Standalone Container (Lite) deployment option is free with a LangSmith API key.
|
||||
|
||||
## Production deployment
|
||||
|
||||
@@ -15,9 +18,9 @@ There are 4 main options for deploying with the [LangGraph Platform](langgraph_p
|
||||
|
||||
1. [Cloud SaaS](#cloud-saas)
|
||||
|
||||
1. [Self-Hosted Data Plane](#self-hosted-data-plane)
|
||||
1. [Self-Hosted Data Plane<sup>(Beta)</sup>](#self-hosted-data-plane)
|
||||
|
||||
1. [Self-Hosted Control Plane](#self-hosted-control-plane)
|
||||
1. [Self-Hosted Control Plane<sup>(Beta)</sup>](#self-hosted-control-plane)
|
||||
|
||||
1. [Standalone Container](#standalone-container)
|
||||
|
||||
@@ -30,7 +33,8 @@ A quick comparison:
|
||||
| **CI/CD** | Managed internally by platform | Managed externally by you | Managed externally by you | Managed externally by you |
|
||||
| **Data/compute residency** | LangChain's cloud | Your cloud | Your cloud | Your cloud |
|
||||
| **LangSmith compatibility** | Trace to LangSmith SaaS | Trace to LangSmith SaaS | Trace to Self-Hosted LangSmith | Optional tracing |
|
||||
| **[Pricing](https://www.langchain.com/pricing-langgraph-platform)** | Plus | Enterprise | Enterprise | Enterprise |
|
||||
| **[Server version compatibility](../concepts/langgraph_server.md#server-versions)** | Enterprise | Enterprise | Enterprise | Lite, Enterprise |
|
||||
| **[Pricing](https://www.langchain.com/pricing-langgraph-platform)** | Plus | Enterprise | Enterprise | Developer |
|
||||
|
||||
## Cloud SaaS
|
||||
|
||||
@@ -46,7 +50,7 @@ For more information, please see:
|
||||
## Self-Hosted Data Plane
|
||||
|
||||
!!! info "Important"
|
||||
The Self-Hosted Data Plane deployment option requires an [Enterprise](../concepts/plans.md) plan.
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage and requires an [Enterprise](../concepts/plans.md) plan.
|
||||
|
||||
The [Self-Hosted Data Plane](./langgraph_self_hosted_data_plane.md) deployment option is a "hybrid" model for deployment where we manage the [control plane](./langgraph_control_plane.md) in our cloud and you manage the [data plane](./langgraph_data_plane.md) in your cloud. This option provides a way to securely manage your data plane infrastructure, while offloading control plane management to us.
|
||||
|
||||
@@ -62,7 +66,7 @@ For more information, please see:
|
||||
## Self-Hosted Control Plane
|
||||
|
||||
!!! info "Important"
|
||||
The Self-Hosted Control Plane deployment option requires an [Enterprise](../concepts/plans.md) plan.
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage and requires an [Enterprise](../concepts/plans.md) plan.
|
||||
|
||||
The [Self-Hosted Control Plane](./langgraph_self_hosted_control_plane.md) deployment option is a fully self-hosted model for deployment where you manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in your cloud. This option gives you full control and responsibility of the control plane and data plane infrastructure.
|
||||
|
||||
|
||||
@@ -21,16 +21,10 @@ To leverage durable execution in LangGraph, you need to:
|
||||
1. Enable [persistence](./persistence.md) in your workflow by specifying a [checkpointer](./persistence.md#checkpointer-libraries) that will save workflow progress.
|
||||
2. Specify a [thread identifier](./persistence.md#threads) when executing a workflow. This will track the execution history for a particular instance of the workflow.
|
||||
|
||||
:::python
|
||||
|
||||
3. Wrap any non-deterministic operations (e.g., random number generation) or operations with side effects (e.g., file writes, API calls) inside @[tasks][task] to ensure that when a workflow is resumed, these operations are not repeated for the particular run, and instead their results are retrieved from the persistence layer. For more information, see [Determinism and Consistent Replay](#determinism-and-consistent-replay).
|
||||
|
||||
:::python 3. Wrap any non-deterministic operations (e.g., random number generation) or operations with side effects (e.g., file writes, API calls) inside [tasks][langgraph.func.task] to ensure that when a workflow is resumed, these operations are not repeated for the particular run, and instead their results are retrieved from the persistence layer. For more information, see [Determinism and Consistent Replay](#determinism-and-consistent-replay).
|
||||
:::
|
||||
|
||||
:::js
|
||||
|
||||
3. Wrap any non-deterministic operations (e.g., random number generation) or operations with side effects (e.g., file writes, API calls) inside @[tasks][task] to ensure that when a workflow is resumed, these operations are not repeated for the particular run, and instead their results are retrieved from the persistence layer. For more information, see [Determinism and Consistent Replay](#determinism-and-consistent-replay).
|
||||
|
||||
:::js 3. Wrap any non-deterministic operations (e.g., random number generation) or operations with side effects (e.g., file writes, API calls) inside [tasks][<insert-ref>] to ensure that when a workflow is resumed, these operations are not repeated for the particular run, and instead their results are retrieved from the persistence layer. For more information, see [Determinism and Consistent Replay](#determinism-and-consistent-replay).
|
||||
:::
|
||||
|
||||
## Determinism and Consistent Replay
|
||||
@@ -47,59 +41,12 @@ To ensure that your workflow is deterministic and can be consistently replayed,
|
||||
|
||||
:::python
|
||||
For some examples of pitfalls to avoid, see the [Common Pitfalls](./functional_api.md#common-pitfalls) section in the functional API, which shows
|
||||
how to structure your code using **tasks** to avoid these issues. The same principles apply to the @[StateGraph (Graph API)][StateGraph].
|
||||
how to structure your code using **tasks** to avoid these issues. The same principles apply to the [StateGraph (Graph API)][langgraph.graph.state.StateGraph].
|
||||
:::
|
||||
|
||||
:::js
|
||||
For some examples of pitfalls to avoid, see the [Common Pitfalls](./functional_api.md#common-pitfalls) section in the functional API, which shows
|
||||
how to structure your code using **tasks** to avoid these issues. The same principles apply to the @[StateGraph (Graph API)][StateGraph].
|
||||
:::
|
||||
|
||||
## Durability modes
|
||||
|
||||
LangGraph supports three durability modes that allow you to balance performance and data consistency based on your application's requirements. The durability modes, from least to most durable, are as follows:
|
||||
|
||||
- [`"exit"`](#exit)
|
||||
- [`"async"`](#async)
|
||||
- [`"sync"`](#sync)
|
||||
|
||||
A higher durability mode add more overhead to the workflow execution.
|
||||
|
||||
!!! version-added "Added in version 0.6.0"
|
||||
|
||||
Use the `durability` parameter instead of `checkpoint_during` (deprecated in v0.6.0) for persistence policy management:
|
||||
|
||||
* `durability="async"` replaces `checkpoint_during=True`
|
||||
* `durability="exit"` replaces `checkpoint_during=False`
|
||||
|
||||
for persistence policy management, with the following mapping:
|
||||
|
||||
* `checkpoint_during=True` -> `durability="async"`
|
||||
* `checkpoint_during=False` -> `durability="exit"`
|
||||
|
||||
### `"exit"`
|
||||
|
||||
Changes are persisted only when graph execution completes (either successfully or with an error). This provides the best performance for long-running graphs but means intermediate state is not saved, so you cannot recover from mid-execution failures or interrupt the graph execution.
|
||||
|
||||
### `"async"`
|
||||
|
||||
Changes are persisted asynchronously while the next step executes. This provides good performance and durability, but there's a small risk that checkpoints might not be written if the process crashes during execution.
|
||||
|
||||
### `"sync"`
|
||||
|
||||
Changes are persisted synchronously before the next step starts. This ensures that every checkpoint is written before continuing execution, providing high durability at the cost of some performance overhead.
|
||||
|
||||
You can specify the durability mode when calling any graph execution method:
|
||||
|
||||
:::python
|
||||
|
||||
```python
|
||||
graph.stream(
|
||||
{"input": "test"},
|
||||
durability="sync"
|
||||
)
|
||||
```
|
||||
|
||||
how to structure your code using **tasks** to avoid these issues. The same principles apply to the [StateGraph (Graph API)][<insert-ref>].
|
||||
:::
|
||||
|
||||
## Using tasks in nodes
|
||||
@@ -114,7 +61,7 @@ If a [node](./low_level.md#nodes) contains multiple operations, you may find it
|
||||
from typing_extensions import TypedDict
|
||||
import uuid
|
||||
|
||||
from langgraph.checkpoint.memory import InMemorySaver
|
||||
from langgraph.checkpoint.memory import MemorySaver
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
import requests
|
||||
|
||||
@@ -140,7 +87,7 @@ If a [node](./low_level.md#nodes) contains multiple operations, you may find it
|
||||
builder.add_edge("call_api", END)
|
||||
|
||||
# Specify a checkpointer
|
||||
checkpointer = InMemorySaver()
|
||||
checkpointer = MemorySaver()
|
||||
|
||||
# Compile the graph with the checkpointer
|
||||
graph = builder.compile(checkpointer=checkpointer)
|
||||
@@ -160,7 +107,7 @@ If a [node](./low_level.md#nodes) contains multiple operations, you may find it
|
||||
from typing_extensions import TypedDict
|
||||
import uuid
|
||||
|
||||
from langgraph.checkpoint.memory import InMemorySaver
|
||||
from langgraph.checkpoint.memory import MemorySaver
|
||||
from langgraph.func import task
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
import requests
|
||||
@@ -195,7 +142,7 @@ If a [node](./low_level.md#nodes) contains multiple operations, you may find it
|
||||
builder.add_edge("call_api", END)
|
||||
|
||||
# Specify a checkpointer
|
||||
checkpointer = InMemorySaver()
|
||||
checkpointer = MemorySaver()
|
||||
|
||||
# Compile the graph with the checkpointer
|
||||
graph = builder.compile(checkpointer=checkpointer)
|
||||
@@ -314,27 +261,24 @@ Once you have enabled durable execution in your workflow, you can resume executi
|
||||
|
||||
:::python
|
||||
|
||||
- **Pausing and Resuming Workflows:** Use the @[interrupt][interrupt] function to pause a workflow at specific points and the @[Command] primitive to resume it with updated state. See [**Human-in-the-Loop**](./human_in_the_loop.md) for more details.
|
||||
- **Pausing and Resuming Workflows:** Use the [interrupt][langgraph.types.interrupt] function to pause a workflow at specific points and the [Command][langgraph.types.Command] primitive to resume it with updated state. See [**Human-in-the-Loop**](./human_in_the_loop.md) for more details.
|
||||
- **Recovering from Failures:** Automatically resume workflows from the last successful checkpoint after an exception (e.g., LLM provider outage). This involves executing the workflow with the same thread identifier by providing it with a `None` as the input value (see this [example](../how-tos/use-functional-api.md#resuming-after-an-error) with the functional API).
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
|
||||
- **Pausing and Resuming Workflows:** Use the @[interrupt][interrupt] function to pause a workflow at specific points and the @[Command] primitive to resume it with updated state. See [**Human-in-the-Loop**](./human_in_the_loop.md) for more details.
|
||||
- **Pausing and Resuming Workflows:** Use the [interrupt](insert-ref) function to pause a workflow at specific points and the [Command](insert-ref) primitive to resume it with updated state. See [**Human-in-the-Loop**](./human_in_the_loop.md) for more details.
|
||||
- **Recovering from Failures:** Automatically resume workflows from the last successful checkpoint after an exception (e.g., LLM provider outage). This involves executing the workflow with the same thread identifier by providing it with a `null` as the input value (see this [example](../how-tos/use-functional-api.md#resuming-after-an-error) with the functional API).
|
||||
|
||||
:::
|
||||
|
||||
## Starting Points for Resuming Workflows
|
||||
|
||||
:::python
|
||||
|
||||
- If you're using a @[StateGraph (Graph API)][StateGraph], the starting point is the beginning of the [**node**](./low_level.md#nodes) where execution stopped.
|
||||
- If you're using a [StateGraph (Graph API)][langgraph.graph.state.StateGraph], the starting point is the beginning of the [**node**](./low_level.md#nodes) where execution stopped.
|
||||
- If you're making a subgraph call inside a node, the starting point will be the **parent** node that called the subgraph that was halted.
|
||||
Inside the subgraph, the starting point will be the specific [**node**](./low_level.md#nodes) where execution stopped.
|
||||
- If you're using the Functional API, the starting point is the beginning of the [**entrypoint**](./functional_api.md#entrypoint) where execution stopped.
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
@@ -343,5 +287,4 @@ Once you have enabled durable execution in your workflow, you can resume executi
|
||||
- If you're making a subgraph call inside a node, the starting point will be the **parent** node that called the subgraph that was halted.
|
||||
Inside the subgraph, the starting point will be the specific [**node**](./low_level.md#nodes) where execution stopped.
|
||||
- If you're using the Functional API, the starting point is the beginning of the [**entrypoint**](./functional_api.md#entrypoint) where execution stopped.
|
||||
|
||||
:::
|
||||
|
||||
@@ -47,7 +47,7 @@ LangGraph is a stateful, orchestration framework that brings added control to ag
|
||||
|
||||
No. LangGraph Platform is proprietary software.
|
||||
|
||||
There is a free, self-hosted version of LangGraph Platform with access to basic features. The Cloud SaaS deployment option and the Self-Hosted deployment options are paid services. [Contact our sales team](https://www.langchain.com/contact-sales) to learn more.
|
||||
There is a free, self-hosted version of LangGraph Platform with access to basic features. The Self-Hosted deployment options are paid services. [Contact our sales team](https://www.langchain.com/contact-sales) to learn more.
|
||||
|
||||
For more information, see our [LangGraph Platform pricing page](https://www.langchain.com/pricing-langgraph-platform).
|
||||
|
||||
|
||||
@@ -29,18 +29,8 @@ This provides a minimal abstraction for building workflows with state management
|
||||
|
||||
!!! tip
|
||||
|
||||
For information on how to use the functional API, see [Use Functional API](../how-tos/use-functional-api.md).
|
||||
|
||||
## Functional API vs. Graph API
|
||||
|
||||
For users who prefer a more declarative approach, LangGraph's [Graph API](./low_level.md) allows you to define workflows using a Graph paradigm. Both APIs share the same underlying runtime, so you can use them together in the same application.
|
||||
|
||||
Here are some key differences:
|
||||
|
||||
- **Control flow**: The Functional API does not require thinking about graph structure. You can use standard Python constructs to define workflows. This will usually trim the amount of code you need to write.
|
||||
- **Short-term memory**: The **GraphAPI** requires declaring a [**State**](./low_level.md#state) and may require defining [**reducers**](./low_level.md#reducers) to manage updates to the graph state. `@entrypoint` and `@tasks` do not require explicit state management as their state is scoped to the function and is not shared across functions.
|
||||
- **Checkpointing**: Both APIs generate and use checkpoints. In the **Graph API** a new checkpoint is generated after every [superstep](./low_level.md). In the **Functional API**, when tasks are executed, their results are saved to an existing checkpoint associated with the given entrypoint instead of creating a new checkpoint.
|
||||
- **Visualization**: The Graph API makes it easy to visualize the workflow as a graph which can be useful for debugging, understanding the workflow, and sharing with others. The Functional API does not support visualization as the graph is dynamically generated during runtime.
|
||||
For users who prefer a more declarative approach, LangGraph's [Graph API](./low_level.md) allows you to define workflows using a Graph paradigm. Both APIs share the same underlying runtime, so you can use them together in the same application.
|
||||
Please see the [Functional API vs. Graph API](#functional-api-vs-graph-api) section for a comparison of the two paradigms.
|
||||
|
||||
## Example
|
||||
|
||||
@@ -49,7 +39,7 @@ Below we demonstrate a simple application that writes an essay and [interrupts](
|
||||
:::python
|
||||
|
||||
```python
|
||||
from langgraph.checkpoint.memory import InMemorySaver
|
||||
from langgraph.checkpoint.memory import MemorySaver
|
||||
from langgraph.func import entrypoint, task
|
||||
from langgraph.types import interrupt
|
||||
|
||||
@@ -59,7 +49,7 @@ def write_essay(topic: str) -> str:
|
||||
time.sleep(1) # A placeholder for a long-running task.
|
||||
return f"An essay about topic: {topic}"
|
||||
|
||||
@entrypoint(checkpointer=InMemorySaver())
|
||||
@entrypoint(checkpointer=MemorySaver())
|
||||
def workflow(topic: str) -> dict:
|
||||
"""A simple workflow that writes an essay and asks for a review."""
|
||||
essay = write_essay("cat").result()
|
||||
@@ -126,54 +116,51 @@ const workflow = entrypoint(
|
||||
```python
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from langgraph.func import entrypoint, task
|
||||
from langgraph.types import interrupt
|
||||
from langgraph.checkpoint.memory import InMemorySaver
|
||||
|
||||
from langgraph.checkpoint.memory import MemorySaver
|
||||
|
||||
@task
|
||||
def write_essay(topic: str) -> str:
|
||||
"""Write an essay about the given topic."""
|
||||
time.sleep(1) # This is a placeholder for a long-running task.
|
||||
time.sleep(1) # This is a placeholder for a long-running task.
|
||||
return f"An essay about topic: {topic}"
|
||||
|
||||
@entrypoint(checkpointer=InMemorySaver())
|
||||
@entrypoint(checkpointer=MemorySaver())
|
||||
def workflow(topic: str) -> dict:
|
||||
"""A simple workflow that writes an essay and asks for a review."""
|
||||
essay = write_essay("cat").result()
|
||||
is_approved = interrupt(
|
||||
{
|
||||
# Any json-serializable payload provided to interrupt as argument.
|
||||
# It will be surfaced on the client side as an Interrupt when streaming data
|
||||
# from the workflow.
|
||||
"essay": essay, # The essay we want reviewed.
|
||||
# We can add any additional information that we need.
|
||||
# For example, introduce a key called "action" with some instructions.
|
||||
"action": "Please approve/reject the essay",
|
||||
}
|
||||
)
|
||||
is_approved = interrupt({
|
||||
# Any json-serializable payload provided to interrupt as argument.
|
||||
# It will be surfaced on the client side as an Interrupt when streaming data
|
||||
# from the workflow.
|
||||
"essay": essay, # The essay we want reviewed.
|
||||
# We can add any additional information that we need.
|
||||
# For example, introduce a key called "action" with some instructions.
|
||||
"action": "Please approve/reject the essay",
|
||||
})
|
||||
|
||||
return {
|
||||
"essay": essay, # The essay that was generated
|
||||
"is_approved": is_approved, # Response from HIL
|
||||
"essay": essay, # The essay that was generated
|
||||
"is_approved": is_approved, # Response from HIL
|
||||
}
|
||||
|
||||
|
||||
thread_id = str(uuid.uuid4())
|
||||
config = {"configurable": {"thread_id": thread_id}}
|
||||
|
||||
config = {
|
||||
"configurable": {
|
||||
"thread_id": thread_id
|
||||
}
|
||||
}
|
||||
|
||||
for item in workflow.stream("cat", config):
|
||||
print(item)
|
||||
# > {'write_essay': 'An essay about topic: cat'}
|
||||
# > {
|
||||
# > '__interrupt__': (
|
||||
# > Interrupt(
|
||||
# > value={
|
||||
# > 'essay': 'An essay about topic: cat',
|
||||
# > 'action': 'Please approve/reject the essay'
|
||||
# > },
|
||||
# > id='b9b2b9d788f482663ced6dc755c9e981'
|
||||
# > ),
|
||||
# > )
|
||||
# > }
|
||||
```
|
||||
|
||||
```pycon
|
||||
{'write_essay': 'An essay about topic: cat'}
|
||||
{'__interrupt__': (Interrupt(value={'essay': 'An essay about topic: cat', 'action': 'Please approve/reject the essay'}, resumable=True, ns=['workflow:f7b8508b-21c0-8b4c-5958-4e8de74d2684'], when='during'),)}
|
||||
```
|
||||
|
||||
An essay has been written and is ready for review. Once the review is provided, we can resume the workflow:
|
||||
@@ -277,11 +264,11 @@ const workflow = entrypoint(
|
||||
## Entrypoint
|
||||
|
||||
:::python
|
||||
The @[`@entrypoint`][entrypoint] decorator can be used to create a workflow from a function. It encapsulates workflow logic and manages execution flow, including handling _long-running tasks_ and [interrupts](./human_in_the_loop.md).
|
||||
The [`@entrypoint`][langgraph.func.entrypoint] decorator can be used to create a workflow from a function. It encapsulates workflow logic and manages execution flow, including handling _long-running tasks_ and [interrupts](./human_in_the_loop.md).
|
||||
:::
|
||||
|
||||
:::js
|
||||
The @[`entrypoint`][entrypoint] function can be used to create a workflow from a function. It encapsulates workflow logic and manages execution flow, including handling _long-running tasks_ and [interrupts](./human_in_the_loop.md).
|
||||
The [`entrypoint`][<insert-ref>] function can be used to create a workflow from a function. It encapsulates workflow logic and manages execution flow, including handling _long-running tasks_ and [interrupts](./human_in_the_loop.md).
|
||||
:::
|
||||
|
||||
### Definition
|
||||
@@ -291,7 +278,7 @@ An **entrypoint** is defined by decorating a function with the `@entrypoint` dec
|
||||
|
||||
The function **must accept a single positional argument**, which serves as the workflow input. If you need to pass multiple pieces of data, use a dictionary as the input type for the first argument.
|
||||
|
||||
Decorating a function with an `entrypoint` produces a @[`Pregel`][Pregel.stream] instance which helps to manage the execution of the workflow (e.g., handles streaming, resumption, and checkpointing).
|
||||
Decorating a function with an `entrypoint` produces a [`Pregel`][langgraph.pregel.Pregel.stream] instance which helps to manage the execution of the workflow (e.g., handles streaming, resumption, and checkpointing).
|
||||
|
||||
You will usually want to pass a **checkpointer** to the `@entrypoint` decorator to enable persistence and use features like **human-in-the-loop**.
|
||||
|
||||
@@ -351,18 +338,27 @@ const myWorkflow = entrypoint(
|
||||
|
||||
The **inputs** and **outputs** of entrypoints must be JSON-serializable to support checkpointing. Please see the [serialization](#serialization) section for more details.
|
||||
|
||||
:::python
|
||||
|
||||
### Injectable parameters
|
||||
|
||||
When declaring an `entrypoint`, you can request access to additional parameters that will be injected automatically at run time. These parameters include:
|
||||
When declaring an `entrypoint`, you can request access to additional parameters that will be injected automatically at run time by using the [`getPreviousState()`](<insert-ref https://langchain-ai.github.io/langgraphjs/reference/functions/langgraph.getPreviousState.html>) function. These parameters include:
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **previous** | Access the state associated with the previous `checkpoint` for the given thread. See [short-term-memory](#short-term-memory). |
|
||||
| **store** | An instance of [BaseStore][langgraph.store.base.BaseStore]. Useful for [long-term memory](../how-tos/use-functional-api.md#long-term-memory). |
|
||||
| **writer** | Use to access the StreamWriter when working with Async Python < 3.11. See [streaming with functional API for details](../how-tos/use-functional-api.md#streaming). |
|
||||
| **config** | For accessing run time configuration. See [RunnableConfig](https://python.langchain.com/docs/concepts/runnables/#runnableconfig) for information. |
|
||||
:::python
|
||||
| Parameter | Description |
|
||||
|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **previous** | Access the state associated with the previous `checkpoint` for the given thread. See [short-term-memory](#short-term-memory). |
|
||||
| **store** | An instance of [BaseStore][langgraph.store.base.BaseStore]. Useful for [long-term memory](../how-tos/use-functional-api.md#long-term-memory). |
|
||||
| **writer** | Use to access the StreamWriter when working with Async Python < 3.11. See [streaming with functional API for details](../how-tos/use-functional-api.md#streaming). |
|
||||
| **config** | For accessing run time configuration. See [RunnableConfig](https://python.langchain.com/docs/concepts/runnables/#runnableconfig) for information. |
|
||||
:::
|
||||
|
||||
:::js
|
||||
| Parameter | Description |
|
||||
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **config** | For accessing runtime configuration. Automatically populated as the second argument to the `entrypoint` function (but not `task`, since tasks can have a variable number of arguments). See [RunnableConfig](https://js.langchain.com/docs/concepts/runnables/#runnableconfig) for information. |
|
||||
| **config.store** | An instance of [BaseStore](/langgraphjs/reference/classes/checkpoint.BaseStore.html). Useful for [long-term memory](#long-term-memory). |
|
||||
| **config.writer** | A `writer` used for streaming back custom data. See the [guide on streaming custom data](../how-tos/streaming-content.ipynb) |
|
||||
| **getPreviousState()** | Access the state associated with the previous `checkpoint` for the given thread using [`getPreviousState`](/langgraphjs/reference/functions/langgraph.getPreviousState.html). See [state management](#state-management). |
|
||||
:::
|
||||
|
||||
!!! important
|
||||
|
||||
@@ -370,6 +366,7 @@ When declaring an `entrypoint`, you can request access to additional parameters
|
||||
|
||||
??? example "Requesting Injectable Parameters"
|
||||
|
||||
:::python
|
||||
```python
|
||||
from langchain_core.runnables import RunnableConfig
|
||||
from langgraph.func import entrypoint
|
||||
@@ -391,13 +388,32 @@ When declaring an `entrypoint`, you can request access to additional parameters
|
||||
config: RunnableConfig # For accessing the configuration passed to the entrypoint
|
||||
) -> ...:
|
||||
```
|
||||
:::
|
||||
|
||||
:::
|
||||
:::js
|
||||
```typescript
|
||||
import { entrypoint, BaseStore, InMemoryStore, LangGraphRunnableConfig } from "@langchain/langgraph";
|
||||
|
||||
const inMemoryStore = new InMemoryStore(); // An instance of InMemoryStore for long-term memory
|
||||
|
||||
const myWorkflow = entrypoint(
|
||||
{
|
||||
checkpointer, name: "workflow", // Specify the checkpointer
|
||||
store: inMemoryStore, // Specify the store
|
||||
name: "myWorkflow",
|
||||
},
|
||||
async (someInput: Record<string, any>) => {
|
||||
const previous = getPreviousState<any>(); // For short-term memory
|
||||
// Rest of workflow logic...
|
||||
}
|
||||
);
|
||||
```
|
||||
:::
|
||||
|
||||
### Executing
|
||||
|
||||
:::python
|
||||
Using the [`@entrypoint`](#entrypoint) yields a @[`Pregel`][Pregel.stream] object that can be executed using the `invoke`, `ainvoke`, `stream`, and `astream` methods.
|
||||
Using the [`@entrypoint`](#entrypoint) yields a [`Pregel`][langgraph.pregel.Pregel.stream] object that can be executed using the `invoke`, `ainvoke`, `stream`, and `astream` methods.
|
||||
|
||||
=== "Invoke"
|
||||
|
||||
@@ -482,7 +498,7 @@ Using the [`entrypoint`](#entrypoint) function will return an object that can be
|
||||
### Resuming
|
||||
|
||||
:::python
|
||||
Resuming an execution after an @[interrupt][interrupt] can be done by passing a **resume** value to the @[Command] primitive.
|
||||
Resuming an execution after an [interrupt][langgraph.types.interrupt] can be done by passing a **resume** value to the [Command][langgraph.types.Command] primitive.
|
||||
|
||||
=== "Invoke"
|
||||
|
||||
@@ -545,7 +561,7 @@ Resuming an execution after an @[interrupt][interrupt] can be done by passing a
|
||||
:::
|
||||
|
||||
:::js
|
||||
Resuming an execution after an @[interrupt][interrupt] can be done by passing a **resume** value to the @[`Command`][Command] primitive.
|
||||
Resuming an execution after an [`interrupt`](insert-ref) can be done by passing a **resume** value to the [`Command`](insert-ref) primitive.
|
||||
|
||||
=== "Invoke"
|
||||
|
||||
@@ -592,6 +608,7 @@ To resume after an error, run the `entrypoint` with a `None` and the same **thre
|
||||
|
||||
This assumes that the underlying **error** has been resolved and execution can proceed successfully.
|
||||
|
||||
:::python
|
||||
=== "Invoke"
|
||||
|
||||
```python
|
||||
@@ -742,7 +759,7 @@ await myWorkflow.invoke(2, config); // 3 (previous was 1 from the previous invoc
|
||||
#### `entrypoint.final`
|
||||
|
||||
:::python
|
||||
@[`entrypoint.final`][entrypoint.final] is a special primitive that can be returned from an entrypoint and allows **decoupling** the value that is **saved in the checkpoint** from the **return value of the entrypoint**.
|
||||
[`entrypoint.final`][langgraph.func.entrypoint.final] is a special primitive that can be returned from an entrypoint and allows **decoupling** the value that is **saved in the checkpoint** from the **return value of the entrypoint**.
|
||||
|
||||
The first value is the return value of the entrypoint, and the second value is the value that will be saved in the checkpoint. The type annotation is `entrypoint.final[return_type, save_type]`.
|
||||
|
||||
@@ -768,7 +785,7 @@ my_workflow.invoke(1, config) # 6 (previous was 3 * 2 from the previous invocat
|
||||
:::
|
||||
|
||||
:::js
|
||||
@[`entrypoint.final`][entrypoint.final] is a special primitive that can be returned from an entrypoint and allows **decoupling** the value that is **saved in the checkpoint** from the **return value of the entrypoint**.
|
||||
[`entrypoint.final`](insert-ref) is a special primitive that can be returned from an entrypoint and allows **decoupling** the value that is **saved in the checkpoint** from the **return value of the entrypoint**.
|
||||
|
||||
The first value is the return value of the entrypoint, and the second value is the value that will be saved in the checkpoint.
|
||||
|
||||
@@ -928,6 +945,26 @@ While different runs of a workflow can produce different results, resuming a **s
|
||||
|
||||
Idempotency ensures that running the same operation multiple times produces the same result. This helps prevent duplicate API calls and redundant processing if a step is rerun due to a failure. Always place API calls inside **tasks** functions for checkpointing, and design them to be idempotent in case of re-execution. Re-execution can occur if a **task** starts, but does not complete successfully. Then, if the workflow is resumed, the **task** will run again. Use idempotency keys or verify existing results to avoid duplication.
|
||||
|
||||
## Functional API vs. Graph API
|
||||
|
||||
The **Functional API** and the [Graph APIs (StateGraph)](./low_level.md#stategraph) provide two different paradigms to create applications with LangGraph. Here are some key differences:
|
||||
|
||||
:::python
|
||||
|
||||
- **Control flow**: The Functional API does not require thinking about graph structure. You can use standard Python constructs to define workflows. This will usually trim the amount of code you need to write.
|
||||
- **Short-term memory**: The **Graph API** requires declaring a [**State**](./low_level.md#state) and may require defining [**reducers**](./low_level.md#reducers) to manage updates to the graph state. `@entrypoint` and `@tasks` do not require explicit state management as their state is scoped to the function and is not shared across functions.
|
||||
- **Checkpointing**: Both APIs generate and use checkpoints. In the **Graph API** a new checkpoint is generated after every [superstep](./low_level.md). In the **Functional API**, when tasks are executed, their results are saved to an existing checkpoint associated with the given entrypoint instead of creating a new checkpoint.
|
||||
- **Visualization**: The Graph API makes it easy to visualize the workflow as a graph which can be useful for debugging, understanding the workflow, and sharing with others. The Functional API does not support visualization as the graph is dynamically generated during runtime.
|
||||
:::
|
||||
|
||||
:::js
|
||||
|
||||
- **Control flow**: The Functional API does not require thinking about graph structure. You can use standard TypeScript constructs to define workflows. This will usually trim the amount of code you need to write.
|
||||
- **Short-term memory**: The **Graph API** requires declaring a [**State**](./low_level.md#state) and may require defining [**reducers**](./low_level.md#reducers) to manage updates to the graph state. `entrypoint` and `task` do not require explicit state management as their state is scoped to the function and is not shared across functions.
|
||||
- **Checkpointing**: Both APIs generate and use checkpoints. In the **Graph API** a new checkpoint is generated after every [superstep](./low_level.md). In the **Functional API**, when tasks are executed, their results are saved to an existing checkpoint associated with the given entrypoint instead of creating a new checkpoint.
|
||||
- **Visualization**: The Graph API makes it easy to visualize the workflow as a graph which can be useful for debugging, understanding the workflow, and sharing with others. The Functional API does not support visualization as the graph is dynamically generated during runtime.
|
||||
:::
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### Handling side effects
|
||||
|
||||
@@ -23,18 +23,9 @@ To review, edit, and approve tool calls in an agent or workflow, [use LangGraph'
|
||||
|
||||
## Key capabilities
|
||||
|
||||
* **Persistent execution state**: Interrupts use LangGraph's [persistence](./persistence.md) layer, which saves the graph state, to indefinitely pause graph execution until you resume. This is possible because LangGraph checkpoints the graph state after each step, which allows the system to persist execution context and later resume the workflow, continuing from where it left off. This supports asynchronous human review or input without time constraints.
|
||||
* **Persistent execution state**: LangGraph allows you to pause execution **indefinitely** — for minutes, hours, or even days—until human input is received. This is possible because LangGraph checkpoints the graph state after each step, which allows the system to persist execution context and later resume the workflow, continuing from where it left off. This supports asynchronous human review or input without time constraints.
|
||||
|
||||
There are two ways to pause a graph:
|
||||
|
||||
- [Dynamic interrupts](../how-tos/human_in_the_loop/add-human-in-the-loop.md#pause-using-interrupt): Use `interrupt` to pause a graph from inside a specific node, based on the current state of the graph.
|
||||
- [Static interrupts](../how-tos/human_in_the_loop/add-human-in-the-loop.md#debug-with-interrupts): Use `interrupt_before` and `interrupt_after` to pause the graph at pre-defined points, either before or after a node executes.
|
||||
|
||||
<figure markdown="1">
|
||||
{: style="max-height:400px"}
|
||||
<figcaption>An example graph consisting of 3 sequential steps with a breakpoint before step_3. </figcaption> </figure>
|
||||
|
||||
* **Flexible integration points**: Human-in-the-loop logic can be introduced at any point in the workflow. This allows targeted human involvement, such as approving API calls, correcting outputs, or guiding conversations.
|
||||
* **Flexible integration points**: HIL logic can be introduced at any point in the workflow. This allows targeted human involvement, such as approving API calls, correcting outputs, or guiding conversations.
|
||||
|
||||
## Patterns
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 121 KiB |
@@ -7,55 +7,53 @@ search:
|
||||
|
||||
**LangGraph CLI** is a multi-platform command-line tool for building and running the [LangGraph API server](./langgraph_server.md) locally. The resulting server includes all API endpoints for your graph's runs, threads, assistants, etc. as well as the other services required to run your agent, including a managed database for checkpointing and storage.
|
||||
|
||||
:::python
|
||||
::: python
|
||||
|
||||
## Installation
|
||||
|
||||
The LangGraph CLI can be installed via pip or [Homebrew](https://brew.sh/):
|
||||
|
||||
=== "pip"
|
||||
|
||||
```bash
|
||||
`bash
|
||||
pip install langgraph-cli
|
||||
```
|
||||
`
|
||||
|
||||
=== "Homebrew"
|
||||
|
||||
```bash
|
||||
`bash
|
||||
brew install langgraph-cli
|
||||
```
|
||||
`
|
||||
:::
|
||||
|
||||
:::js
|
||||
::: js
|
||||
|
||||
## Installation
|
||||
|
||||
The LangGraph.js CLI can be installed from the NPM registry:
|
||||
|
||||
=== "npx"
|
||||
```bash
|
||||
`bash
|
||||
npx @langchain/langgraph-cli
|
||||
```
|
||||
`
|
||||
|
||||
=== "npm"
|
||||
```bash
|
||||
`bash
|
||||
npm install @langchain/langgraph-cli
|
||||
```
|
||||
`
|
||||
|
||||
=== "yarn"
|
||||
```bash
|
||||
`bash
|
||||
yarn add @langchain/langgraph-cli
|
||||
```
|
||||
`
|
||||
|
||||
=== "pnpm"
|
||||
```bash
|
||||
`bash
|
||||
pnpm add @langchain/langgraph-cli
|
||||
```
|
||||
`
|
||||
|
||||
=== "bun"
|
||||
```bash
|
||||
`bash
|
||||
bun add @langchain/langgraph-cli
|
||||
```
|
||||
`
|
||||
:::
|
||||
|
||||
## Commands
|
||||
|
||||
@@ -26,7 +26,7 @@ The Control Plane UI is embedded in [LangSmith](https://docs.smith.langchain.com
|
||||
|
||||
## Control Plane API
|
||||
|
||||
This section describes the data model of the control plane API. The API is used to create, update, and delete deployments. See the [control plane API reference](../cloud/reference/api/api_ref_control_plane.md) for more details.
|
||||
This section describes data model of the control plane API. The API is used to create, update, and delete deployments. However, they are not publicly accessible.
|
||||
|
||||
### Deployment
|
||||
|
||||
@@ -34,7 +34,11 @@ A deployment is an instance of a LangGraph Server. A single deployment can have
|
||||
|
||||
### Revision
|
||||
|
||||
A revision is an iteration of a deployment. When a new deployment is created, an initial revision is automatically created. To deploy code changes or update secrets for a deployment, a new revision must be created.
|
||||
A revision is an iteration of a deployment. When a new deployment is created, an initial revision is automatically created. To deploy code changes or update environment variables for a deployment, a new revision must be created.
|
||||
|
||||
### Environment Variable
|
||||
|
||||
Environment variables are set for a deployment. All environment variables are stored as secrets (i.e. saved in a secrets store).
|
||||
|
||||
## Control Plane Features
|
||||
|
||||
@@ -44,42 +48,23 @@ This section describes various features of the control plane.
|
||||
|
||||
For simplicity, the control plane offers two deployment types with different resource allocations: `Development` and `Production`.
|
||||
|
||||
| **Deployment Type** | **CPU/Memory** | **Scaling** | **Database** |
|
||||
| ------------------- | --------------- | ----------------- | -------------------------------------------------------------------------------- |
|
||||
| Development | 1 CPU, 1 GB RAM | Up to 1 replica | 10 GB disk, no backups |
|
||||
| Production | 2 CPU, 2 GB RAM | Up to 10 replicas | Autoscaling disk, automatic backups, highly available (multi-zone configuration) |
|
||||
| **Deployment Type** | **CPU/Memory** | **Scaling** | **Database** |
|
||||
| ------------------- | --------------- | ------------------- | -------------------------------------------------------------------------------- |
|
||||
| Development | 1 CPU, 1 GB RAM | Up to 1 container | 10 GB disk, no backups |
|
||||
| Production | 2 CPU, 2 GB RAM | Up to 10 containers | Autoscaling disk, automatic backups, highly available (multi-zone configuration) |
|
||||
|
||||
CPU and memory resources are per replica.
|
||||
CPU and memory resources are per container.
|
||||
|
||||
!!! warning "Immutable Deployment Type"
|
||||
|
||||
Once a deployment is created, the deployment type cannot be changed.
|
||||
|
||||
!!! info "Self-Hosted Deployment"
|
||||
Resources for [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md) deployments can be fully customized. Deployment types are only applicable for [Cloud SaaS](../concepts/langgraph_cloud.md) deployments.
|
||||
!!! info "Resource Customization"
|
||||
For `Production` type deployments, resources can be manually increased on a case-by-case basis depending on use case and capacity constraints. Contact support@langchain.dev to request an increase in resources.
|
||||
|
||||
#### Production
|
||||
For `Development` types deployments, database disk size can be manually increased on a case-by-case basis depending on use case and capacity constraints. For most use cases, [TTLs](../how-tos/ttl/configure_ttl.md) should be configured to manage disk usage. Contact support@langchain.dev to request an increase in resources.
|
||||
|
||||
`Production` type deployments are suitable for "production" workloads. For example, select `Production` for customer-facing applications in the critical path.
|
||||
|
||||
Resources for `Production` type deployments can be manually increased on a case-by-case basis depending on use case and capacity constraints. Contact support@langchain.dev to request an increase in resources.
|
||||
|
||||
#### Development
|
||||
|
||||
`Development` type deployments are suitable development and testing. For example, select `Development` for internal testing environments. `Development` type deployments are not suitable for "production" workloads.
|
||||
|
||||
!!! danger "Preemptible Compute Infrastructure"
|
||||
`Development` type deployments (API server, queue server, and database) are provisioned on preemptible compute infrastructure. This means the compute infrastructure **may be terminated at any time without notice**. This may result in intermittent...
|
||||
|
||||
- Redis connection timeouts/errors
|
||||
- Postgres connection timeouts/errors
|
||||
- Failed or retrying background runs
|
||||
|
||||
This behavior is expected. Preemptible compute infrastructure **significantly reduces the cost to provision a `Development` type deployment**. By design, LangGraph Server is fault-tolerant. The implementation will automatically attempt to recover from Redis/Postgres connection errors and retry failed background runs.
|
||||
|
||||
`Production` type deployments are provisioned on durable compute infrastructure, not preemptible compute infrastructure.
|
||||
|
||||
Database disk size for `Development` type deployments can be manually increased on a case-by-case basis depending on use case and capacity constraints. For most use cases, [TTLs](../how-tos/ttl/configure_ttl.md) should be configured to manage disk usage. Contact support@langchain.dev to request an increase in resources.
|
||||
Resources for [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md) deployments can be fully customized.
|
||||
|
||||
### Database Provisioning
|
||||
|
||||
@@ -112,18 +97,11 @@ After a deployment is ready, the control plane monitors the deployment and recor
|
||||
- Number of container restarts.
|
||||
- Number of replicas (this will increase with [autoscaling](../concepts/langgraph_data_plane.md#autoscaling)).
|
||||
- [Postgres](../concepts/langgraph_data_plane.md#postgres) CPU, memory usage, and disk usage.
|
||||
- [LangGraph Server queue](../concepts/langgraph_server.md#persistence-and-task-queue) pending/active run count.
|
||||
- [LangGraph Server API](../concepts/langgraph_server.md) success response count, error response count, and latency.
|
||||
|
||||
These metrics are displayed as charts in the Control Plane UI.
|
||||
|
||||
### LangSmith Integration
|
||||
|
||||
A [LangSmith](https://docs.smith.langchain.com/) tracing project and LangSmith API key are automatically created for each deployment. The deployment uses the API key to automatically send traces to LangSmith.
|
||||
A [LangSmith](https://docs.smith.langchain.com/) tracing project is automatically created for each deployment. The tracing project has the same name as the deployment. When creating a deployment, the `LANGCHAIN_TRACING` and `LANGSMITH_API_KEY`/`LANGCHAIN_API_KEY` environment variables do not need to be specified; they are set automatically by the control plane.
|
||||
|
||||
- The tracing project has the same name as the deployment.
|
||||
- The API key has the description `LangGraph Platform: <deployment_name>`.
|
||||
- The API key is never revealed and cannot be deleted manually.
|
||||
- When creating a deployment, the `LANGCHAIN_TRACING` and `LANGSMITH_API_KEY`/`LANGCHAIN_API_KEY` environment variables do not need to be specified; they are set automatically by the control plane.
|
||||
|
||||
When a deployment is deleted, the traces and the tracing project are not deleted. However, the API will be deleted when the deployment is deleted.
|
||||
When a deployment is deleted, the traces and the tracing project are not deleted.
|
||||
|
||||
@@ -50,15 +50,6 @@ Runs in a LangGraph Server may be retried for specific failures (currently only
|
||||
|
||||
This section describes various features of the data plane.
|
||||
|
||||
### Data Region
|
||||
|
||||
!!! info "Only for Cloud SaaS"
|
||||
Data regions are only applicable for [Cloud SaaS](../concepts/langgraph_cloud.md) deployments.
|
||||
|
||||
Deployments can be created in 2 data regions: US and EU
|
||||
|
||||
The data region for a deployment is implied by the data region of the LangSmith organization where the deployment is created. Deployments and the underlying database for the deployments cannot be migrated between data regions.
|
||||
|
||||
### Autoscaling
|
||||
|
||||
[`Production` type](../concepts/langgraph_control_plane.md#deployment-types) deployments automatically scale up to 10 containers. Scaling is based on 3 metrics:
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
There are two versions of the self-hosted deployment: [Self-Hosted Data Plane](./deployment_options.md#self-hosted-data-plane) and [Self-Hosted Control Plane](./deployment_options.md#self-hosted-control-plane).
|
||||
|
||||
!!! info "Important"
|
||||
|
||||
The Self-Hosted Control Plane deployment option requires an [Enterprise](plans.md) plan.
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage and requires an [Enterprise](plans.md) plan.
|
||||
|
||||
## Requirements
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@ search:
|
||||
There are two versions of the self-hosted deployment: [Self-Hosted Data Plane](./deployment_options.md#self-hosted-data-plane) and [Self-Hosted Control Plane](./deployment_options.md#self-hosted-control-plane).
|
||||
|
||||
!!! info "Important"
|
||||
|
||||
The Self-Hosted Data Plane deployment option requires an [Enterprise](plans.md) plan.
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage and requires an [Enterprise](plans.md) plan.
|
||||
|
||||
## Requirements
|
||||
|
||||
|
||||
@@ -13,6 +13,21 @@ Use LangGraph Server to create and manage [assistants](assistants.md), [threads]
|
||||
|
||||
For detailed information on the API endpoints and data models, see [LangGraph Platform API reference docs](../cloud/reference/api/api_ref.html).
|
||||
|
||||
## Server versions
|
||||
|
||||
There are two versions of LangGraph Server:
|
||||
|
||||
- `Lite` is a limited version of the LangGraph Server that you can run locally or in a self-hosted manner (up to 1 million [nodes executed](../concepts/faq.md#what-does-nodes-executed-mean-for-langgraph-platform-usage) per year).
|
||||
- `Enterprise` is the full version of the LangGraph Server. To use the `Enterprise` version, you must acquire a license key that you will need to specify when running the Docker image. To acquire a license key, please email sales@langchain.dev.
|
||||
|
||||
Feature Differences:
|
||||
|
||||
| | Lite | Enterprise |
|
||||
|-------|------------|------------|
|
||||
| [Cron Jobs](../cloud/concepts/cron_jobs.md) |❌|✅|
|
||||
| [Custom Authentication](../concepts/auth.md) |❌|✅|
|
||||
| [Deployment options](../concepts/deployment_options.md) | Standalone container | Cloud SaaS, Self-Hosted Data Plane, Self-Hosted Control Plane, Standalone container
|
||||
|
||||
## Application structure
|
||||
|
||||
To deploy a LangGraph Server application, you need to specify the graph(s) you want to deploy, as well as any relevant configuration settings, such as dependencies and environment variables.
|
||||
|
||||
@@ -19,7 +19,7 @@ The Standalone Container deployment option is the least restrictive model for de
|
||||
|
||||
!!! warning
|
||||
|
||||
LangGraph Platform should not be deployed in serverless environments. Scale to zero may cause task loss and scaling up will not work reliably.
|
||||
LangGraph Platform should not be deployed in serverless environments.
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -34,3 +34,12 @@ The Standalone Container deployment option supports deploying data plane infrast
|
||||
### Docker
|
||||
|
||||
The Standalone Container deployment option supports deploying data plane infrastructure to any Docker-supported compute platform.
|
||||
|
||||
## Lite vs. Enterprise
|
||||
|
||||
The Standalone Container deployment option supports both of the [server versions](../concepts/langgraph_server.md#langgraph-server):
|
||||
|
||||
- The `Lite` version is free, but has limited features.
|
||||
- The `Enterprise` version has custom pricing and is fully featured.
|
||||
|
||||
For more details on feature difference, see [LangGraph Server](../concepts/langgraph_server.md#server-versions).
|
||||
|
||||
+74
-104
@@ -68,9 +68,9 @@ The first thing you do when you define a graph is define the `State` of the grap
|
||||
### Schema
|
||||
|
||||
:::python
|
||||
The main documented way to specify the schema of a graph is by using a [`TypedDict`](https://docs.python.org/3/library/typing.html#typing.TypedDict). If you want to provide default values in your state, use a [`dataclass`](https://docs.python.org/3/library/dataclasses.html). We also support using a Pydantic [BaseModel](../how-tos/graph-api.md#use-pydantic-models-for-graph-state) as your graph state if you want recursive data validation (though note that pydantic is less performant than a `TypedDict` or `dataclass`).
|
||||
The main documented way to specify the schema of a graph is by using `TypedDict`. However, we also support [using a Pydantic BaseModel](../how-tos/graph-api.ipynb#use-pydantic-models-for-graph-state) as your graph state to add **default values** and additional data validation.
|
||||
|
||||
By default, the graph will have the same input and output schemas. If you want to change this, you can also specify explicit input and output schemas directly. This is useful when you have a lot of keys, and some are explicitly for input and others for output. See the [guide here](../how-tos/graph-api.md#define-input-and-output-schemas) for how to use.
|
||||
By default, the graph will have the same input and output schemas. If you want to change this, you can also specify explicit input and output schemas directly. This is useful when you have a lot of keys, and some are explicitly for input and others for output. See the [guide here](../how-tos/graph-api.ipynb#define-input-and-output-schemas) for how to use.
|
||||
:::
|
||||
|
||||
:::js
|
||||
@@ -88,7 +88,9 @@ Typically, all graph nodes communicate with a single schema. This means that the
|
||||
|
||||
It is possible to have nodes write to private state channels inside the graph for internal node communication. We can simply define a private schema, `PrivateState`.
|
||||
|
||||
It is also possible to define explicit input and output schemas for a graph. In these cases, we define an "internal" schema that contains _all_ keys relevant to graph operations. But, we also define `input` and `output` schemas that are sub-sets of the "internal" schema to constrain the input and output of the graph. See [this guide](../how-tos/graph-api.md#define-input-and-output-schemas) for more detail.
|
||||
See [this guide](../how-tos/graph-api.ipynb#pass-private-state-between-nodes) for more detail.
|
||||
|
||||
It is also possible to define explicit input and output schemas for a graph. In these cases, we define an "internal" schema that contains _all_ keys relevant to graph operations. But, we also define `input` and `output` schemas that are sub-sets of the "internal" schema to constrain the input and output of the graph. See [this guide](../how-tos/graph-api.ipynb#define-input-and-output-schemas) for more detail.
|
||||
|
||||
Let's look at an example:
|
||||
|
||||
@@ -392,60 +394,47 @@ class State(MessagesState):
|
||||
## Nodes
|
||||
|
||||
:::python
|
||||
In LangGraph, nodes are typically python functions (sync or async) where the **first** positional argument is the [state](#state), and (optionally), the **second** positional argument is a "config", containing optional [configurable parameters](#configuration) (such as a `thread_id`).
|
||||
:::
|
||||
|
||||
In LangGraph, nodes are Python functions (either synchronous or asynchronous) that accept the following arguments:
|
||||
:::js
|
||||
In LangGraph, nodes are typically functions (sync or async) where the **first** positional argument is the [state](#state), and (optionally), the **second** positional argument is a "config", containing optional [configurable parameters](#configuration) (such as a `thread_id`).
|
||||
:::
|
||||
|
||||
1. `state`: The [state](#state) of the graph
|
||||
2. `config`: A `RunnableConfig` object that contains configuration information like `thread_id` and tracing information like `tags`
|
||||
3. `runtime`: A `Runtime` object that contains [runtime `context`](#runtime-context) and other information like `store` and `stream_writer`
|
||||
|
||||
Similar to `NetworkX`, you add these nodes to a graph using the @[add_node][add_node] method:
|
||||
:::python
|
||||
Similar to `NetworkX`, you add these nodes to a graph using the [add_node][langgraph.graph.StateGraph.add_node] method:
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from langchain_core.runnables import RunnableConfig
|
||||
from langgraph.graph import StateGraph
|
||||
from langgraph.runtime import Runtime
|
||||
|
||||
class State(TypedDict):
|
||||
input: str
|
||||
results: str
|
||||
|
||||
@dataclass
|
||||
class Context:
|
||||
user_id: str
|
||||
|
||||
builder = StateGraph(State)
|
||||
|
||||
def plain_node(state: State):
|
||||
|
||||
def my_node(state: State, config: RunnableConfig):
|
||||
print("In node: ", config["configurable"]["user_id"])
|
||||
return {"results": f"Hello, {state['input']}!"}
|
||||
|
||||
|
||||
# The second argument is optional
|
||||
def my_other_node(state: State):
|
||||
return state
|
||||
|
||||
def node_with_runtime(state: State, runtime: Runtime[Context]):
|
||||
print("In node: ", runtime.context.user_id)
|
||||
return {"results": f"Hello, {state['input']}!"}
|
||||
|
||||
def node_with_config(state: State, config: RunnableConfig):
|
||||
print("In node with thread_id: ", config["configurable"]["thread_id"])
|
||||
return {"results": f"Hello, {state['input']}!"}
|
||||
|
||||
|
||||
builder.add_node("plain_node", plain_node)
|
||||
builder.add_node("node_with_runtime", node_with_runtime)
|
||||
builder.add_node("node_with_config", node_with_config)
|
||||
builder.add_node("my_node", my_node)
|
||||
builder.add_node("other_node", my_other_node)
|
||||
...
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
|
||||
In LangGraph, nodes are typically functions (sync or async) that accept the following arguments:
|
||||
|
||||
1. `state`: The [state](#state) of the graph
|
||||
2. `config`: A `RunnableConfig` object that contains configuration information like `thread_id` and tracing information like `tags`
|
||||
|
||||
You can add nodes to a graph using the `addNode` method.
|
||||
|
||||
```typescript
|
||||
@@ -471,7 +460,7 @@ const builder = new StateGraph(State);
|
||||
|
||||
:::
|
||||
|
||||
Behind the scenes, functions are converted to [RunnableLambda](https://python.langchain.com/api_reference/core/runnables/langchain_core.runnables.base.RunnableLambda.html)s, which add batch and async support to your function, along with native tracing and debugging.
|
||||
Behind the scenes, functions are converted to [RunnableLambda](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.RunnableLambda.html#langchain_core.runnables.base.RunnableLambda)s, which add batch and async support to your function, along with native tracing and debugging.
|
||||
|
||||
If you add a node to a graph without specifying a name, it will be given a default name equivalent to the function name.
|
||||
|
||||
@@ -587,7 +576,7 @@ print(graph.invoke({"x": 5}, stream_mode='updates')) # (2)!
|
||||
[{'expensive_node': {'result': 10}, '__metadata__': {'cached': True}}]
|
||||
```
|
||||
|
||||
1. First run takes two seconds to run (due to mocked expensive computation).
|
||||
1. First run takes the full second to run (due to mocked expensive computation).
|
||||
2. Second run utilizes cache and returns quickly.
|
||||
:::
|
||||
|
||||
@@ -638,7 +627,7 @@ A node can have MULTIPLE outgoing edges. If a node has multiple out-going edges,
|
||||
### Normal Edges
|
||||
|
||||
:::python
|
||||
If you **always** want to go from node A to node B, you can use the @[add_edge][add_edge] method directly.
|
||||
If you **always** want to go from node A to node B, you can use the [add_edge][langgraph.graph.StateGraph.add_edge] method directly.
|
||||
|
||||
```python
|
||||
graph.add_edge("node_a", "node_b")
|
||||
@@ -647,7 +636,7 @@ graph.add_edge("node_a", "node_b")
|
||||
:::
|
||||
|
||||
:::js
|
||||
If you **always** want to go from node A to node B, you can use the @[`addEdge`][add_edge] method directly.
|
||||
If you **always** want to go from node A to node B, you can use the [`addEdge`](insert-ref) method directly.
|
||||
|
||||
```typescript
|
||||
graph.addEdge("nodeA", "nodeB");
|
||||
@@ -658,7 +647,7 @@ graph.addEdge("nodeA", "nodeB");
|
||||
### Conditional Edges
|
||||
|
||||
:::python
|
||||
If you want to **optionally** route to 1 or more edges (or optionally terminate), you can use the @[add_conditional_edges][add_conditional_edges] method. This method accepts the name of a node and a "routing function" to call after that node is executed:
|
||||
If you want to **optionally** route to 1 or more edges (or optionally terminate), you can use the [add_conditional_edges][langgraph.graph.StateGraph.add_conditional_edges] method. This method accepts the name of a node and a "routing function" to call after that node is executed:
|
||||
|
||||
```python
|
||||
graph.add_conditional_edges("node_a", routing_function)
|
||||
@@ -677,7 +666,7 @@ graph.add_conditional_edges("node_a", routing_function, {True: "node_b", False:
|
||||
:::
|
||||
|
||||
:::js
|
||||
If you want to **optionally** route to 1 or more edges (or optionally terminate), you can use the @[`addConditionalEdges`][add_conditional_edges] method. This method accepts the name of a node and a "routing function" to call after that node is executed:
|
||||
If you want to **optionally** route to 1 or more edges (or optionally terminate), you can use the [`addConditionalEdges`](insert-ref) method. This method accepts the name of a node and a "routing function" to call after that node is executed:
|
||||
|
||||
```typescript
|
||||
graph.addConditionalEdges("nodeA", routingFunction);
|
||||
@@ -699,13 +688,12 @@ graph.addConditionalEdges("nodeA", routingFunction, {
|
||||
:::
|
||||
|
||||
!!! tip
|
||||
|
||||
Use [`Command`](#command) instead of conditional edges if you want to combine state updates and routing in a single function.
|
||||
Use [`Command`](#command) instead of conditional edges if you want to combine state updates and routing in a single function.
|
||||
|
||||
### Entry Point
|
||||
|
||||
:::python
|
||||
The entry point is the first node(s) that are run when the graph starts. You can use the @[`add_edge`][add_edge] method from the virtual @[`START`][START] node to the first node to execute to specify where to enter the graph.
|
||||
The entry point is the first node(s) that are run when the graph starts. You can use the [`add_edge`][langgraph.graph.StateGraph.add_edge] method from the virtual [`START`][langgraph.constants.START] node to the first node to execute to specify where to enter the graph.
|
||||
|
||||
```python
|
||||
from langgraph.graph import START
|
||||
@@ -716,7 +704,7 @@ graph.add_edge(START, "node_a")
|
||||
:::
|
||||
|
||||
:::js
|
||||
The entry point is the first node(s) that are run when the graph starts. You can use the @[`addEdge`][add_edge] method from the virtual @[`START`][START] node to the first node to execute to specify where to enter the graph.
|
||||
The entry point is the first node(s) that are run when the graph starts. You can use the [`addEdge`](insert-ref) method from the virtual [`START`](insert-ref) node to the first node to execute to specify where to enter the graph.
|
||||
|
||||
```typescript
|
||||
import { START } from "@langchain/langgraph";
|
||||
@@ -729,7 +717,7 @@ graph.addEdge(START, "nodeA");
|
||||
### Conditional Entry Point
|
||||
|
||||
:::python
|
||||
A conditional entry point lets you start at different nodes depending on custom logic. You can use @[`add_conditional_edges`][add_conditional_edges] from the virtual @[`START`][START] node to accomplish this.
|
||||
A conditional entry point lets you start at different nodes depending on custom logic. You can use [`add_conditional_edges`][langgraph.graph.StateGraph.add_conditional_edges] from the virtual [`START`][langgraph.constants.START] node to accomplish this.
|
||||
|
||||
```python
|
||||
from langgraph.graph import START
|
||||
@@ -746,7 +734,7 @@ graph.add_conditional_edges(START, routing_function, {True: "node_b", False: "no
|
||||
:::
|
||||
|
||||
:::js
|
||||
A conditional entry point lets you start at different nodes depending on custom logic. You can use @[`addConditionalEdges`][add_conditional_edges] from the virtual @[`START`][START] node to accomplish this.
|
||||
A conditional entry point lets you start at different nodes depending on custom logic. You can use [`addConditionalEdges`](insert-ref) from the virtual [`START`](insert-ref) node to accomplish this.
|
||||
|
||||
```typescript
|
||||
import { START } from "@langchain/langgraph";
|
||||
@@ -770,7 +758,7 @@ graph.addConditionalEdges(START, routingFunction, {
|
||||
:::python
|
||||
By default, `Nodes` and `Edges` are defined ahead of time and operate on the same shared state. However, there can be cases where the exact edges are not known ahead of time and/or you may want different versions of `State` to exist at the same time. A common example of this is with [map-reduce](https://langchain-ai.github.io/langgraph/how-tos/map-reduce/) design patterns. In this design pattern, a first node may generate a list of objects, and you may want to apply some other node to all those objects. The number of objects may be unknown ahead of time (meaning the number of edges may not be known) and the input `State` to the downstream `Node` should be different (one for each generated object).
|
||||
|
||||
To support this design pattern, LangGraph supports returning @[`Send`][Send] objects from conditional edges. `Send` takes two arguments: first is the name of the node, and second is the state to pass to that node.
|
||||
To support this design pattern, LangGraph supports returning [`Send`][langgraph.types.Send] objects from conditional edges. `Send` takes two arguments: first is the name of the node, and second is the state to pass to that node.
|
||||
|
||||
```python
|
||||
def continue_to_jokes(state: OverallState):
|
||||
@@ -784,7 +772,7 @@ graph.add_conditional_edges("node_a", continue_to_jokes)
|
||||
:::js
|
||||
By default, `Nodes` and `Edges` are defined ahead of time and operate on the same shared state. However, there can be cases where the exact edges are not known ahead of time and/or you may want different versions of `State` to exist at the same time. A common example of this is with map-reduce design patterns. In this design pattern, a first node may generate a list of objects, and you may want to apply some other node to all those objects. The number of objects may be unknown ahead of time (meaning the number of edges may not be known) and the input `State` to the downstream `Node` should be different (one for each generated object).
|
||||
|
||||
To support this design pattern, LangGraph supports returning @[`Send`][Send] objects from conditional edges. `Send` takes two arguments: first is the name of the node, and second is the state to pass to that node.
|
||||
To support this design pattern, LangGraph supports returning [`Send`](insert-ref) objects from conditional edges. `Send` takes two arguments: first is the name of the node, and second is the state to pass to that node.
|
||||
|
||||
```typescript
|
||||
import { Send } from "@langchain/langgraph";
|
||||
@@ -799,7 +787,7 @@ graph.addConditionalEdges("nodeA", (state) => {
|
||||
## `Command`
|
||||
|
||||
:::python
|
||||
It can be useful to combine control flow (edges) and state updates (nodes). For example, you might want to BOTH perform state updates AND decide which node to go to next in the SAME node. LangGraph provides a way to do so by returning a @[`Command`][Command] object from node functions:
|
||||
It can be useful to combine control flow (edges) and state updates (nodes). For example, you might want to BOTH perform state updates AND decide which node to go to next in the SAME node. LangGraph provides a way to do so by returning a [`Command`][langgraph.types.Command] object from node functions:
|
||||
|
||||
```python
|
||||
def my_node(state: State) -> Command[Literal["my_other_node"]]:
|
||||
@@ -819,6 +807,7 @@ def my_node(state: State) -> Command[Literal["my_other_node"]]:
|
||||
return Command(update={"foo": "baz"}, goto="my_other_node")
|
||||
```
|
||||
|
||||
Check out this [how-to guide](../how-tos/graph-api.ipynb#combine-control-flow-and-state-updates-with-command) for an end-to-end example of how to use `Command`.
|
||||
:::
|
||||
|
||||
:::js
|
||||
@@ -858,18 +847,25 @@ builder.addNode("myNode", myNode, {
|
||||
});
|
||||
```
|
||||
|
||||
Check out this [how-to guide](../how-tos/graph-api.ipynb#combine-control-flow-and-state-updates-with-command) for an end-to-end example of how to use `Command`.
|
||||
:::
|
||||
:::
|
||||
|
||||
!!! important
|
||||
|
||||
When returning `Command` in your node functions, you must add return type annotations with the list of node names the node is routing to, e.g. `Command[Literal["my_other_node"]]`. This is necessary for the graph rendering and tells LangGraph that `my_node` can navigate to `my_other_node`.
|
||||
|
||||
Check out this [how-to guide](../how-tos/graph-api.md#combine-control-flow-and-state-updates-with-command) for an end-to-end example of how to use `Command`.
|
||||
|
||||
### When should I use Command instead of conditional edges?
|
||||
|
||||
- Use `Command` when you need to **both** update the graph state **and** route to a different node. For example, when implementing [multi-agent handoffs](./multi_agent.md#handoffs) where it's important to route to a different agent and pass some information to that agent.
|
||||
- Use [conditional edges](#conditional-edges) to route between nodes conditionally without updating the state.
|
||||
:::python
|
||||
Use `Command` when you need to **both** update the graph state **and** route to a different node. For example, when implementing [multi-agent handoffs](./multi_agent.md#handoffs) where it's important to route to a different agent and pass some information to that agent.
|
||||
:::
|
||||
|
||||
:::js
|
||||
Use `Command` when you need to **both** update the graph state **and** route to a different node. For example, when implementing [multi-agent handoffs](./multi_agent.md#handoffs) where it's important to route to a different agent and pass some information to that agent.
|
||||
:::
|
||||
|
||||
Use [conditional edges](#conditional-edges) to route between nodes conditionally without updating the state.
|
||||
|
||||
### Navigating to a node in a parent graph
|
||||
|
||||
@@ -891,32 +887,7 @@ def my_node(state: State) -> Command[Literal["other_subgraph"]]:
|
||||
|
||||
!!! important "State updates with `Command.PARENT`"
|
||||
|
||||
When you send updates from a subgraph node to a parent graph node for a key that's shared by both parent and subgraph [state schemas](#schema), you **must** define a [reducer](#reducers) for the key you're updating in the parent graph state. See this [example](../how-tos/graph-api.md#navigate-to-a-node-in-a-parent-graph).
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
If you are using [subgraphs](./subgraphs.md), you might want to navigate from a node within a subgraph to a different subgraph (i.e. a different node in the parent graph). To do so, you can specify `graph: Command.PARENT` in `Command`:
|
||||
|
||||
```typescript
|
||||
import { Command } from "@langchain/langgraph";
|
||||
|
||||
graph.addNode("myNode", (state) => {
|
||||
return new Command({
|
||||
update: { foo: "bar" },
|
||||
goto: "otherSubgraph", // where `otherSubgraph` is a node in the parent graph
|
||||
graph: Command.PARENT,
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
Setting `graph` to `Command.PARENT` will navigate to the closest parent graph.
|
||||
|
||||
!!! important "State updates with `Command.PARENT`"
|
||||
|
||||
When you send updates from a subgraph node to a parent graph node for a key that's shared by both parent and subgraph [state schemas](#schema), you **must** define a [reducer](#reducers) for the key you're updating in the parent graph state.
|
||||
When you send updates from a subgraph node to a parent graph node for a key that's shared by both parent and subgraph [state schemas](#schema), you **must** define a [reducer](#reducers) for the key you're updating in the parent graph state. See this [example](../how-tos/graph-api.ipynb#navigate-to-a-node-in-a-parent-graph).
|
||||
|
||||
:::
|
||||
|
||||
@@ -947,13 +918,13 @@ graph.addNode("myNode", (state) => {
|
||||
|
||||
This is particularly useful when implementing [multi-agent handoffs](./multi_agent.md#handoffs).
|
||||
|
||||
Check out [this guide](../how-tos/graph-api.md#navigate-to-a-node-in-a-parent-graph) for detail.
|
||||
Check out [this guide](../how-tos/graph-api.ipynb#navigate-to-a-node-in-a-parent-graph) for detail.
|
||||
|
||||
### Using inside tools
|
||||
|
||||
A common use case is updating graph state from inside a tool. For example, in a customer support application you might want to look up customer information based on their account number or ID in the beginning of the conversation.
|
||||
|
||||
Refer to [this guide](../how-tos/graph-api.md#use-inside-tools) for detail.
|
||||
Refer to [this guide](../how-tos/graph-api.ipynb#use-inside-tools) for detail.
|
||||
|
||||
### Human-in-the-loop
|
||||
|
||||
@@ -975,29 +946,25 @@ LangGraph can easily handle migrations of graph definitions (nodes, edges, and s
|
||||
- State keys that are renamed lose their saved state in existing threads
|
||||
- State keys whose types change in incompatible ways could currently cause issues in threads with state from before the change -- if this is a blocker please reach out and we can prioritize a solution.
|
||||
|
||||
## Configuration
|
||||
|
||||
When creating a graph, you can also mark that certain parts of the graph are configurable. This is commonly done to enable easily switching between models or system prompts. This allows you to create a single "cognitive architecture" (the graph) but have multiple different instance of it.
|
||||
|
||||
You can optionally specify a config schema when creating a graph.
|
||||
|
||||
:::python
|
||||
|
||||
## Runtime Context
|
||||
|
||||
When creating a graph, you can specify a `context_schema` for runtime context passed to nodes. This is useful for passing
|
||||
information to nodes that is not part of the graph state. For example, you might want to pass dependencies such as model name or a database connection.
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ContextSchema:
|
||||
llm_provider: str = "openai"
|
||||
class ConfigSchema(TypedDict):
|
||||
llm: str
|
||||
|
||||
graph = StateGraph(State, context_schema=ContextSchema)
|
||||
graph = StateGraph(State, config_schema=ConfigSchema)
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
|
||||
When creating a graph, you can also mark that certain parts of the graph are configurable. This is commonly done to enable easily switching between models or system prompts. This allows you to create a single "cognitive architecture" (the graph) but have multiple different instance of it.
|
||||
|
||||
You can optionally specify a config schema when creating a graph.
|
||||
|
||||
```typescript
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -1010,17 +977,19 @@ const graph = new StateGraph(State, ConfigSchema);
|
||||
|
||||
:::
|
||||
|
||||
You can then pass this configuration into the graph using the `configurable` config field.
|
||||
|
||||
:::python
|
||||
You can then pass this context into the graph using the `context` parameter of the `invoke` method.
|
||||
|
||||
```python
|
||||
graph.invoke(inputs, context={"llm_provider": "anthropic"})
|
||||
config = {"configurable": {"llm": "anthropic"}}
|
||||
|
||||
graph.invoke(inputs, config=config)
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
You can then pass this configuration into the graph using the `configurable` config field.
|
||||
|
||||
```typescript
|
||||
const config = { configurable: { llm: "anthropic" } };
|
||||
@@ -1030,17 +999,18 @@ await graph.invoke(inputs, config);
|
||||
|
||||
:::
|
||||
|
||||
You can then access and use this context inside a node or conditional edge:
|
||||
You can then access and use this configuration inside a node or conditional edge:
|
||||
|
||||
:::python
|
||||
|
||||
```python
|
||||
from langgraph.runtime import Runtime
|
||||
|
||||
def node_a(state: State, runtime: Runtime[ContextSchema]):
|
||||
llm = get_llm(runtime.context.llm_provider)
|
||||
def node_a(state, config):
|
||||
llm_type = config.get("configurable", {}).get("llm", "openai")
|
||||
llm = get_llm(llm_type)
|
||||
...
|
||||
```
|
||||
|
||||
See [this guide](../how-tos/graph-api.md#add-runtime-configuration) for a full breakdown on configuration.
|
||||
See [this guide](../how-tos/graph-api.ipynb#add-runtime-configuration) for a full breakdown on configuration.
|
||||
:::
|
||||
|
||||
:::js
|
||||
@@ -1061,7 +1031,7 @@ graph.addNode("myNode", (state, config) => {
|
||||
The recursion limit sets the maximum number of [super-steps](#graphs) the graph can execute during a single execution. Once the limit is reached, LangGraph will raise `GraphRecursionError`. By default this value is set to 25 steps. The recursion limit can be set on any graph at runtime, and is passed to `.invoke`/`.stream` via the config dictionary. Importantly, `recursion_limit` is a standalone `config` key and should not be passed inside the `configurable` key as all other user-defined configuration. See the example below:
|
||||
|
||||
```python
|
||||
graph.invoke(inputs, config={"recursion_limit": 5}, context={"llm": "anthropic"})
|
||||
graph.invoke(inputs, config={"recursion_limit": 5, "configurable":{"llm": "anthropic"}})
|
||||
```
|
||||
|
||||
Read [this how-to](https://langchain-ai.github.io/langgraph/how-tos/recursion-limit/) to learn more about how the recursion limit works.
|
||||
@@ -1081,4 +1051,4 @@ await graph.invoke(inputs, {
|
||||
|
||||
## Visualization
|
||||
|
||||
It's often nice to be able to visualize graphs, especially as they get more complex. LangGraph comes with several built-in ways to visualize graphs. See [this how-to guide](../how-tos/graph-api.md#visualize-your-graph) for more info.
|
||||
It's often nice to be able to visualize graphs, especially as they get more complex. LangGraph comes with several built-in ways to visualize graphs. See [this how-to guide](../how-tos/graph-api.ipynb#visualize-your-graph) for more info.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user