Compare commits

...
Author SHA1 Message Date
Parker Rule 10dfc922af Simplify flat Dockerfile helpers 2026-08-28 12:36:27 -04:00
Parker Rule 87d05fc0da Refactor flat Dockerfile generation 2026-08-28 12:33:38 -04:00
Parker Rule f4c8adfc69 Expand flat Docker builds 2026-08-28 12:22:04 -04:00
Parker Rule ffd16825a4 Expand flat image integration coverage 2026-08-28 12:09:07 -04:00
Parker Rule d4cb3914be test(cli): matrix flat and layered image builds 2026-08-28 12:04:30 -04:00
Parker Rule 2b5cd95263 refactor(cli): simplify flat image plumbing 2026-08-28 11:43:55 -04:00
Parker Rule fc70ba12fb test(cli): remove redundant flat option assertion 2026-08-28 11:03:11 -04:00
Parker Rule e23540c63d test(cli): allow more time for service startup 2026-08-28 10:51:23 -04:00
Parker Rule f1a740e589 refactor(cli): clarify flat image environment variable 2026-08-28 10:32:16 -04:00
Parker Rule b12eb249cc test(cli): preserve standard builds alongside flat mode 2026-08-28 10:28:58 -04:00
Parker Rule 502053a050 refactor(cli): simplify single-layer Dockerfile generation 2026-08-27 21:15:18 -04:00
Parker Rule 58273fde86 feat(cli): support layer mode from environment 2026-08-25 22:36:09 -04:00
Parker Rule aeb9cdfef1 feat(cli): support single-layer user builds 2026-08-25 22:31:15 -04:00
John KennedyGitHublangsmith-fleet[bot] <langsmith-fleet[bot]@users.noreply.github.com>
38031739e5 docs: add Corridor agent instructions (#8677)
Add a repository-wide `<corridor>` block to `AGENTS.md` requiring agents
to plan first and run Corridor `analyzePlan` before generating or
modifying code. The tags are explicit and balanced so Corridor-specific
guidance remains scoped.

Validation: `git diff --check` and a tag-balance assertion.

---------

Co-authored-by: langsmith-fleet[bot] <langsmith-fleet[bot]@users.noreply.github.com>
2026-08-24 14:42:27 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
f09cfe8ffc chore(deps): bump langgraph-checkpoint-postgres from 3.0.5 to 3.1.1 in /libs/cli/uv-examples/monorepo in the uv group across 1 directory (#8646)
Bumps the uv group with 1 update in the /libs/cli/uv-examples/monorepo
directory:
[langgraph-checkpoint-postgres](https://github.com/langchain-ai/langgraph).

Updates `langgraph-checkpoint-postgres` from 3.0.5 to 3.1.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/langchain-ai/langgraph/releases">langgraph-checkpoint-postgres's
releases</a>.</em></p>
<blockquote>
<h2>langgraph-checkpoint-postgres==3.1.1</h2>
<p>Changes since checkpointpostgres==3.1.0</p>
<ul>
<li>release(checkpoint-postgres): 3.1.1 (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8480">#8480</a>)</li>
<li>fix(checkpoint-postgres,checkpoint-sqlite): scope namespace matching
to segment boundaries (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8478">#8478</a>)</li>
<li>feat(checkpoint,checkpoint-postgres): add opt-in omit_expired to
skip expired rows on read (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8354">#8354</a>)</li>
<li>chore(deps): bump the minor-and-patch group in
/libs/checkpoint-postgres with 5 updates (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8250">#8250</a>)</li>
<li>chore(deps): bump langsmith from 0.8.0 to 0.8.18 in
/libs/checkpoint-postgres (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8171">#8171</a>)</li>
<li>docs: standardize package <code>README.md</code> structure (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8064">#8064</a>)</li>
<li>chore: migrate Python type checking to ty (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8002">#8002</a>)</li>
<li>chore(deps): bump the minor-and-patch group in
/libs/checkpoint-postgres with 7 updates (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7965">#7965</a>)</li>
<li>release(checkpoint): 4.1.1 (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7890">#7890</a>)</li>
<li>chore(deps): bump idna from 3.11 to 3.15 in
/libs/checkpoint-postgres (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7861">#7861</a>)</li>
<li>chore(deps): bump langsmith from 0.7.31 to 0.8.0 in
/libs/checkpoint-postgres (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7785">#7785</a>)</li>
</ul>
<h2>langgraph-checkpoint-sqlite==3.1.1</h2>
<p>Changes since checkpointsqlite==3.1.0</p>
<ul>
<li>release(checkpoint-sqlite): 3.1.1 (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8481">#8481</a>)</li>
<li>fix(checkpoint-postgres,checkpoint-sqlite): scope namespace matching
to segment boundaries (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8478">#8478</a>)</li>
<li>chore(deps): bump the minor-and-patch group in
/libs/checkpoint-sqlite with 4 updates (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8249">#8249</a>)</li>
<li>chore(deps): bump langsmith from 0.8.0 to 0.8.18 in
/libs/checkpoint-sqlite (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8177">#8177</a>)</li>
<li>docs: standardize package <code>README.md</code> structure (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8064">#8064</a>)</li>
<li>chore: migrate Python type checking to ty (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8002">#8002</a>)</li>
<li>chore(deps): bump the minor-and-patch group in
/libs/checkpoint-sqlite with 3 updates (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7961">#7961</a>)</li>
<li>release(checkpoint): 4.1.1 (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7890">#7890</a>)</li>
<li>chore(deps): bump langsmith from 0.7.31 to 0.8.0 in
/libs/checkpoint-sqlite (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7786">#7786</a>)</li>
<li>chore(deps): bump idna from 3.11 to 3.15 in /libs/checkpoint-sqlite
(<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7862">#7862</a>)</li>
</ul>
<h2>langgraph-checkpoint-postgres==3.1.0</h2>
<p>Changes since checkpointpostgres==3.1.0a4</p>
<ul>
<li>release: bump alpha packages to official versions (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7775">#7775</a>)</li>
<li>chore(deps): bump urllib3 from 2.6.3 to 2.7.0 in
/libs/checkpoint-postgres (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7761">#7761</a>)</li>
<li>chore(deps): bump langchain-core from 1.3.2 to 1.3.3 in
/libs/checkpoint-postgres (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7754">#7754</a>)</li>
<li>fix(checkpoint-postgres): add column aliases to seed-blob branch of
delta stage-2 UNION ALL (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7728">#7728</a>)</li>
</ul>
<h2>langgraph-checkpoint-sqlite==3.1.0</h2>
<p>Changes since checkpointsqlite==3.1.0a1</p>
<ul>
<li>release: bump alpha packages to official versions (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7775">#7775</a>)</li>
<li>chore(deps): bump urllib3 from 2.6.3 to 2.7.0 in
/libs/checkpoint-sqlite (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7760">#7760</a>)</li>
<li>chore(deps): bump langchain-core from 1.2.28 to 1.3.3 in
/libs/checkpoint-sqlite (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7751">#7751</a>)</li>
<li>chore: remove keepset helper (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7745">#7745</a>)</li>
<li>chore(langgraph): add guide/conformance for delta channel
checkpointer (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7736">#7736</a>)</li>
</ul>
<h2>langgraph-checkpoint-postgres==3.1.0a4</h2>
<p>Changes since checkpointpostgres==3.1.0a3</p>
<ul>
<li>release: alpha bump (a4) for langgraph, checkpoint,
checkpoint-postgres (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/7701">#7701</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/langchain-ai/langgraph/commit/b2926a0ff9589c28c7e01fe7cdbb337b86d5a4b4"><code>b2926a0</code></a>
release(checkpoint-sqlite): 3.1.1 (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8481">#8481</a>)</li>
<li><a
href="https://github.com/langchain-ai/langgraph/commit/fcdf520938469c8e0992ca2075d6a9582c33260f"><code>fcdf520</code></a>
release(checkpoint-postgres): 3.1.1 (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8480">#8480</a>)</li>
<li><a
href="https://github.com/langchain-ai/langgraph/commit/66ebe1a0da921e73f0f9f879ba105d314c079f7c"><code>66ebe1a</code></a>
fix(checkpoint-postgres,checkpoint-sqlite): scope namespace matching to
segme...</li>
<li><a
href="https://github.com/langchain-ai/langgraph/commit/41341457342327166d72fc11952ab28fb61ec0bf"><code>4134145</code></a>
release(langgraph): 1.2.10 (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8462">#8462</a>)</li>
<li><a
href="https://github.com/langchain-ai/langgraph/commit/30c4d58db86455128e42ddec96b1ba53c553ba22"><code>30c4d58</code></a>
chore(deps): bump jupyterlab from 4.5.9 to 4.5.10 in /libs/langgraph (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8440">#8440</a>)</li>
<li><a
href="https://github.com/langchain-ai/langgraph/commit/1f2f88b2b74aa4e26c6a8be877dcb95bad2cef48"><code>1f2f88b</code></a>
chore(deps): bump js-yaml from 4.2.0 to 4.3.0 in
/libs/cli/js-monorepo-exampl...</li>
<li><a
href="https://github.com/langchain-ai/langgraph/commit/270820363d56cf8a8e594d2d3b19d543230337fb"><code>2708203</code></a>
chore(deps): bump setuptools from 82.0.1 to 83.0.0 in /libs/cli (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8434">#8434</a>)</li>
<li><a
href="https://github.com/langchain-ai/langgraph/commit/9f1e40bfeea28dee2155b4a57f5babd0a53534cf"><code>9f1e40b</code></a>
chore(deps): bump setuptools from 80.9.0 to 83.0.0 in /libs/langgraph
(<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8435">#8435</a>)</li>
<li><a
href="https://github.com/langchain-ai/langgraph/commit/1e1ca88dad9c7e708263257fa9fc27a3fbdfff68"><code>1e1ca88</code></a>
feat(langgraph): type v3 stream_events return and native projections (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8389">#8389</a>)</li>
<li><a
href="https://github.com/langchain-ai/langgraph/commit/31f90df3e6b0268fa77fd2d118a917d420b84a68"><code>31f90df</code></a>
revert(langgraph): delete TracePolicy (<a
href="https://redirect.github.com/langchain-ai/langgraph/issues/8403">#8403</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/langchain-ai/langgraph/compare/checkpointpostgres==3.0.5...checkpointsqlite==3.1.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=langgraph-checkpoint-postgres&package-manager=uv&previous-version=3.0.5&new-version=3.1.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/langchain-ai/langgraph/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-20 07:02:48 +00:00
10 changed files with 493 additions and 76 deletions
+33 -28
View File
@@ -17,6 +17,9 @@ jobs:
python-version:
- "3.10"
- "3.14"
build_mode:
- layered
- flat
example:
- name: A
workdir: libs/cli/examples
@@ -30,9 +33,11 @@ jobs:
- name: D
workdir: libs/cli/examples/graphs_reqs_b
tag: langgraph-test-d
name: "CLI integration test"
name: "CLI integration test (${{ matrix.python-version }}, ${{ matrix.example.name }}, ${{ matrix.build_mode }})"
env:
BUILD_ARGS: ${{ matrix.build_mode == 'flat' && '--flat' || '' }}
HAS_LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY != '' }}
TAG_SUFFIX: ${{ matrix.build_mode == 'flat' && '-flat' || '' }}
defaults:
run:
working-directory: libs/cli
@@ -58,7 +63,7 @@ jobs:
if: (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch')
working-directory: ${{ matrix.example.workdir }}
run: |
langgraph build -t ${{ matrix.example.tag }}
langgraph build $BUILD_ARGS -t ${{ matrix.example.tag }}$TAG_SUFFIX
- name: Test service ${{ matrix.example.name }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&env.HAS_LANGSMITH_API_KEY == 'true' }}
working-directory: ${{ matrix.example.workdir }}
@@ -71,98 +76,98 @@ jobs:
if [ -f ../.env ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> ../.env; fi
# Run the integration test using the built tag
REPO_ROOT=$(git rev-parse --show-toplevel)
timeout 60 python "$REPO_ROOT/.github/scripts/run_langgraph_cli_test.py" -t ${{ matrix.example.tag }}
timeout 60 python "$REPO_ROOT/.github/scripts/run_langgraph_cli_test.py" -t ${{ matrix.example.tag }}$TAG_SUFFIX
- name: Build JS service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') && matrix.example.name == 'A' }}
working-directory: libs/cli/js-examples
run: |
langgraph build -t langgraph-test-e
langgraph build $BUILD_ARGS -t langgraph-test-e$TAG_SUFFIX
- name: Build JS monorepo service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') && 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"
langgraph build $BUILD_ARGS -t langgraph-test-f$TAG_SUFFIX -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 || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') && matrix.example.name == 'A' }}
working-directory: libs/cli/python-monorepo-example
run: |
langgraph build -t langgraph-test-g -c apps/agent/langgraph.json
langgraph build $BUILD_ARGS -t langgraph-test-g$TAG_SUFFIX -c apps/agent/langgraph.json
- name: Test Python monorepo service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' && env.HAS_LANGSMITH_API_KEY == 'true' }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') && matrix.example.name == 'A' && env.HAS_LANGSMITH_API_KEY == 'true' }}
working-directory: libs/cli/python-monorepo-example
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
run: |
cp apps/agent/.env.example apps/agent/.env
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> apps/agent/.env
timeout 60 python ../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-g -c apps/agent/langgraph.json
timeout 60 python ../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-g$TAG_SUFFIX -c apps/agent/langgraph.json
- name: Build prerelease reqs service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') && matrix.example.name == 'A' }}
working-directory: libs/cli/examples/graph_prerelease_reqs
run: |
langgraph build -t langgraph-test-h
langgraph build $BUILD_ARGS -t langgraph-test-h$TAG_SUFFIX
- name: Test prerelease reqs service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' && env.HAS_LANGSMITH_API_KEY == 'true' }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') && matrix.example.name == 'A' && env.HAS_LANGSMITH_API_KEY == 'true' }}
working-directory: libs/cli/examples/graph_prerelease_reqs
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
run: |
cp ../.env.example .env
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-h
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-h$TAG_SUFFIX
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);")
LANGGRAPH_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h$TAG_SUFFIX python -c "import sys; from importlib.metadata import version; v = version('langgraph'); print(v);")
if [ "$LANGGRAPH_VERSION" != "1.1.5" ]; then
echo "LANGGRAPH_VERSION != 1.1.5; $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);")
LANGCHAIN_OPENAI_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h$TAG_SUFFIX python -c "import sys; from importlib.metadata import version; v = version('langchain-openai'); print(v);")
if [ "$LANGCHAIN_OPENAI_VERSION" != "1.1.14" ]; then
echo "LANGCHAIN_OPENAI_VERSION != 1.1.14; $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);")
LANGCHAIN_ANTHROPIC_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h$TAG_SUFFIX python -c "import sys; from importlib.metadata import version; v = version('langchain-anthropic'); print(v);")
if [ "$LANGCHAIN_ANTHROPIC_VERSION" != "1.4.6" ]; then
echo "LANGCHAIN_ANTHROPIC_VERSION != 1.4.6; $LANGCHAIN_ANTHROPIC_VERSION"
exit 1
fi
- name: Build and test prerelease reqs fail service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') && matrix.example.name == 'A' }}
working-directory: libs/cli/examples/graph_prerelease_reqs_fail
run: |
langgraph build -t langgraph-test-i || [ $? -eq 1 ]
langgraph build $BUILD_ARGS -t langgraph-test-i$TAG_SUFFIX || [ $? -eq 1 ]
- name: Build uv simple service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') && matrix.example.name == 'A' }}
working-directory: libs/cli/uv-examples/simple
run: |
langgraph build -t langgraph-test-uv-simple
langgraph build $BUILD_ARGS -t langgraph-test-uv-simple$TAG_SUFFIX
- name: Test uv simple service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' && env.HAS_LANGSMITH_API_KEY == 'true' }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') && matrix.example.name == 'A' && env.HAS_LANGSMITH_API_KEY == 'true' }}
working-directory: libs/cli/uv-examples/simple
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
run: |
cp .env.example .env
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-uv-simple
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-uv-simple$TAG_SUFFIX
- name: Build uv monorepo service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') && matrix.example.name == 'A' }}
working-directory: libs/cli/uv-examples/monorepo/apps/agent
run: |
langgraph build -t langgraph-test-uv-monorepo
langgraph build $BUILD_ARGS -t langgraph-test-uv-monorepo$TAG_SUFFIX
- name: Test uv monorepo service
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' && env.HAS_LANGSMITH_API_KEY == 'true' }}
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') && matrix.example.name == 'A' && env.HAS_LANGSMITH_API_KEY == 'true' }}
working-directory: libs/cli/uv-examples/monorepo/apps/agent
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
run: |
cp .env.example .env
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
timeout 60 python ../../../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-uv-monorepo
timeout 60 python ../../../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-uv-monorepo$TAG_SUFFIX
+1
View File
@@ -76,6 +76,7 @@ __pypackages__/
# Environments
.env
.env.*
.envrc
*.crt
*.key
+8
View File
@@ -2,6 +2,14 @@
This repository is a monorepo. Each library lives in a subdirectory under `libs/`.
<corridor>
## Corridor security analysis
When Corridor's `analyzePlan` tool is available, create a plan and use the tool to analyze it before generating or modifying code. Apply the resulting security guidance before writing code.
</corridor>
When you modify code in any library, run the following commands in that library's directory before creating a pull request:
- `make format` run code formatters
+8
View File
@@ -2,6 +2,14 @@
This repository is a monorepo. Each library lives in a subdirectory under `libs/`.
<corridor>
## Corridor security analysis
Before generating or modifying code, create a plan and use Corridor's `analyzePlan` tool to analyze it. Apply the resulting security guidance before writing code.
</corridor>
When you modify code in any library, run the following commands in that library's directory before creating a pull request:
- `make format` run code formatters
+8
View File
@@ -408,6 +408,12 @@ For production use, requires a license key in env var LANGGRAPH_CLOUD_LICENSE_KE
"--build-command",
help="Custom build command to run from the langgraph.json directory. If not provided, uses default build process.",
)
@click.option(
"--flat",
is_flag=True,
envvar="LANGGRAPH_CLI_FLAT_IMAGES",
help="Flatten generated build steps into one image layer when supported.",
)
@click.argument("docker_build_args", nargs=-1, type=click.UNPROCESSED)
@cli.command(
help="📦 Build LangGraph API server Docker image.",
@@ -426,6 +432,7 @@ def build(
tag: str,
install_command: str | None,
build_command: str | None,
flat: bool,
):
if install_command and langgraph_cli.config.has_disallowed_build_command_content(
install_command
@@ -461,6 +468,7 @@ def build(
docker_build_args,
install_command,
build_command,
flat=flat,
)
+292 -42
View File
@@ -1162,6 +1162,208 @@ def _build_runtime_env_vars(config: Config) -> list[str]:
return env_vars
def _faux_package_pyproject_command(package_name: str) -> str:
pyproject_path = shlex.quote(f"/deps/outer-{package_name}/pyproject.toml")
return f"""cat > {pyproject_path} <<'PYPROJECT'
[project]
name = {json.dumps(package_name)}
version = "0.1"
[tool.setuptools.package-data]
"*" = ["**/*"]
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"
PYPROJECT"""
_FLAT_BUILD_CONTEXT = pathlib.PurePosixPath("/__build_context")
_FLAT_ADDITIONAL_CONTEXTS = pathlib.PurePosixPath("/__additional_contexts")
_DEFAULT_NODE_BUILD_COMMAND = (
'(test ! -f /api/langgraph_api/js/build.mts && echo "Prebuild script not found, '
'skipping") || tsx /api/langgraph_api/js/build.mts'
)
def _render_flat_dockerfile(
*,
image: str,
dockerfile_lines: list[str],
env_vars: list[str],
commands: list[str],
workdir: str | None,
additional_context_names: dict[pathlib.Path, str] | None = None,
) -> str:
mounts = [f"--mount=type=bind,target={_FLAT_BUILD_CONTEXT},readonly"]
mounts.extend(
f"--mount=type=bind,from={name},"
f"target={_FLAT_ADDITIONAL_CONTEXTS / name},readonly"
for name in (additional_context_names or {}).values()
)
return os.linesep.join(
[
"# syntax=docker/dockerfile:1.7",
f"FROM {image}",
*dockerfile_lines,
*env_vars,
f"RUN {' '.join(mounts)} <<'USER_LAYER'",
*commands,
"USER_LAYER",
f"WORKDIR {workdir}" if workdir else "",
]
)
def _flat_context_source(
path: pathlib.Path,
relative_path: str,
additional_context_names: dict[pathlib.Path, str],
*,
additional_relative_path: str = ".",
) -> str:
if name := additional_context_names.get(path):
return str(_FLAT_ADDITIONAL_CONTEXTS / name / additional_relative_path)
return str(_FLAT_BUILD_CONTEXT / relative_path)
def _copy_directory_command(source: str, destination: str) -> str:
return f"""mkdir -p {shlex.quote(destination)}
cp -a {shlex.quote(f"{source}/.")} {shlex.quote(destination)}/"""
def _flat_local_dependency_commands(
*,
config_path: pathlib.Path,
local_deps: LocalDeps,
local_reqs_pip_install: str,
additional_context_names: dict[pathlib.Path, str],
) -> list[str]:
commands = []
for reqpath, destination in local_deps.pip_reqs:
source = _flat_context_source(
reqpath.parent,
str(reqpath.relative_to(config_path.parent)),
additional_context_names,
additional_relative_path=reqpath.name,
)
destination_parent = pathlib.PurePosixPath(destination).parent
commands.append(f"""mkdir -p {shlex.quote(str(destination_parent))}
cp {shlex.quote(source)} {shlex.quote(destination)}""")
if local_deps.pip_reqs:
requirements = " ".join(
f"-r {destination}" for _, destination in local_deps.pip_reqs
)
commands.append(f"{local_reqs_pip_install} {requirements}")
for full_path, (relative_path, name) in local_deps.real_pkgs.items():
source = _flat_context_source(
full_path, relative_path, additional_context_names
)
commands.append(_copy_directory_command(source, f"/deps/{name}"))
for full_path, (relative_path, destination) in local_deps.faux_pkgs.items():
source = _flat_context_source(
full_path, relative_path, additional_context_names
)
pyproject = _faux_package_pyproject_command(full_path.name)
commands.append(f"{_copy_directory_command(source, destination)}\n{pyproject}")
return commands
def _build_flat_python_commands(
*,
config_path: pathlib.Path,
config: Config,
local_deps: LocalDeps,
pypi_deps: list[str],
local_reqs_pip_install: str,
local_deps_install_command: str,
pip_cleanup: str,
additional_context_names: dict[pathlib.Path, str],
js_working_dir: str | None,
) -> list[str]:
commands = ["set -eu"]
if js_working_dir:
commands.append("/storage/install-node.sh")
if pip_config_file := config.get("pip_config_file"):
source = shlex.quote(str(_FLAT_BUILD_CONTEXT / pip_config_file))
commands.append(f"cp {source} /pipconfig.txt")
if pypi_deps:
commands.append(f"{local_reqs_pip_install} {' '.join(pypi_deps)}")
commands.extend(
_flat_local_dependency_commands(
config_path=config_path,
local_deps=local_deps,
local_reqs_pip_install=local_reqs_pip_install,
additional_context_names=additional_context_names,
)
)
commands.append(local_deps_install_command)
if js_working_dir:
working_dir = shlex.quote(js_working_dir)
commands.append(
f"cd {working_dir}\n"
f"{_get_node_pm_install_cmd(config_path.parent)} "
"&& tsx /api/langgraph_api/js/build.mts"
)
commands.extend(
line.removeprefix("RUN ")
for line in pip_cleanup.splitlines()
if line and not line.startswith("#")
)
return commands
def _build_flat_python_dockerfile(
config_path: pathlib.Path,
config: Config,
local_deps: LocalDeps,
pypi_deps: list[str],
local_reqs_pip_install: str,
local_deps_install_command: str,
pip_cleanup: str,
image: str,
env_vars: list[str],
additional_context_names: dict[pathlib.Path, str],
) -> str:
js_working_dir = (
local_deps.working_dir
if config.get("ui") or config.get("node_version")
else None
)
commands = _build_flat_python_commands(
config_path=config_path,
config=config,
local_deps=local_deps,
pypi_deps=pypi_deps,
local_reqs_pip_install=local_reqs_pip_install,
local_deps_install_command=local_deps_install_command,
pip_cleanup=pip_cleanup,
additional_context_names=additional_context_names,
js_working_dir=js_working_dir,
)
if js_working_dir:
env_vars = [
f"ENV NODE_VERSION={config.get('node_version') or DEFAULT_NODE_VERSION}",
*env_vars,
]
return _render_flat_dockerfile(
image=image,
dockerfile_lines=config["dockerfile_lines"],
env_vars=env_vars,
commands=commands,
workdir=local_deps.working_dir,
additional_context_names=additional_context_names,
)
def _get_node_pm_install_cmd(project_dir: pathlib.Path) -> str:
def test_file(file_name):
full_path = project_dir / file_name
@@ -1267,6 +1469,7 @@ def python_config_to_docker(
api_version: str | None = None,
*,
escape_variables: bool = False,
flat: bool = False,
) -> tuple[str, dict[str, str]]:
"""Generate a Dockerfile from the configuration."""
source_kind = _get_source_kind(config)
@@ -1428,6 +1631,36 @@ ADD {relpath} /deps/{name}
]
)
image_str = docker_tag(config, base_image, api_version)
dep_vname = "$$dep" if escape_variables else "$dep"
local_deps_install_command = f"""for dep in /deps/*; do \
echo "Installing {dep_vname}"; \
if [ -d "{dep_vname}" ]; then \
echo "Installing {dep_vname}"; \
(cd "{dep_vname}" && {global_reqs_pip_install} -e .); \
fi; \
done"""
pip_cleanup = _get_pip_cleanup_lines(
install_cmd=install_cmd,
to_uninstall=build_tools_to_uninstall,
pip_installer=pip_installer,
)
if flat:
return (
_build_flat_python_dockerfile(
config_path=config_path,
config=config,
local_deps=local_deps,
pypi_deps=pypi_deps,
local_reqs_pip_install=local_reqs_pip_install,
local_deps_install_command=local_deps_install_command,
pip_cleanup=pip_cleanup,
image=image_str,
env_vars=env_vars,
additional_context_names=additional_context_names,
),
additional_contexts,
)
# Prepare docker file contents
docker_file_contents = []
@@ -1442,14 +1675,6 @@ ADD {relpath} /deps/{name}
)
# Add main dockerfile content
dep_vname = "$$dep" if escape_variables else "$dep"
local_deps_install_str = f"""RUN for dep in /deps/*; do \
echo "Installing {dep_vname}"; \
if [ -d "{dep_vname}" ]; then \
echo "Installing {dep_vname}"; \
(cd "{dep_vname}" && {global_reqs_pip_install} -e .); \
fi; \
done"""
docker_file_contents.extend(
[
f"FROM {image_str}",
@@ -1459,18 +1684,14 @@ ADD {relpath} /deps/{name}
installs,
"",
"# -- Installing all local dependencies --",
local_deps_install_str,
f"RUN {local_deps_install_command}",
"# -- End of local dependencies install --",
os.linesep.join(env_vars),
"",
js_inst_str,
"",
# Add pip cleanup after all installations are complete
_get_pip_cleanup_lines(
install_cmd=install_cmd,
to_uninstall=build_tools_to_uninstall,
pip_installer=pip_installer,
),
pip_cleanup,
"",
f"WORKDIR {local_deps.working_dir}" if local_deps.working_dir else "",
]
@@ -1479,6 +1700,31 @@ ADD {relpath} /deps/{name}
return os.linesep.join(docker_file_contents), additional_contexts
def _build_flat_node_dockerfile(
*,
config: Config,
image: str,
env_vars: list[str],
install_workdir: str,
build_workdir: str,
install_command: str,
build_command: str,
) -> str:
commands = [
"set -eu",
_copy_directory_command(str(_FLAT_BUILD_CONTEXT), install_workdir),
f"cd {shlex.quote(install_workdir)}\n{install_command}",
f"cd {shlex.quote(build_workdir)}\n{build_command}",
]
return _render_flat_dockerfile(
image=image,
dockerfile_lines=config["dockerfile_lines"],
env_vars=env_vars,
commands=commands,
workdir=build_workdir,
)
def node_config_to_docker(
config_path: pathlib.Path,
config: Config,
@@ -1487,6 +1733,7 @@ def node_config_to_docker(
install_command: str | None = None,
build_command: str | None = None,
build_context: str | None = None,
flat: bool = False,
) -> tuple[str, dict[str, str]]:
# Calculate paths for monorepo support
install_root = (
@@ -1496,56 +1743,56 @@ def node_config_to_docker(
if build_context:
relative_workdir = _calculate_relative_workdir(config_path, build_context)
container_name = pathlib.Path(build_context).name
if relative_workdir:
faux_path = f"/deps/{container_name}/{relative_workdir}"
else:
faux_path = f"/deps/{container_name}"
install_workdir = f"/deps/{container_name}"
build_workdir = (
f"{install_workdir}/{relative_workdir}"
if relative_workdir
else install_workdir
)
else:
# Backward compatibility: use the original behavior
faux_path = f"/deps/{config_path.parent.name}"
install_workdir = build_workdir = f"/deps/{config_path.parent.name}"
image_str = docker_tag(config, base_image, api_version)
env_vars = _build_runtime_env_vars(config)
# For monorepo support, we need to handle install and build commands differently
if build_context:
# Monorepo case: install from root, build from config directory
container_root = f"/deps/{pathlib.Path(build_context).name}"
install_workdir = container_root
install_step = f"RUN {install_cmd}"
build_cmd = (
build_command
if build_context and build_command
else _DEFAULT_NODE_BUILD_COMMAND
)
if build_command:
build_step = f"RUN {build_command}"
else:
build_step = 'RUN (test ! -f /api/langgraph_api/js/build.mts && echo "Prebuild script not found, skipping") || tsx /api/langgraph_api/js/build.mts'
else:
# Original behavior: everything happens in the same directory
install_workdir = faux_path
install_step = f"RUN {install_cmd}"
build_step = 'RUN (test ! -f /api/langgraph_api/js/build.mts && echo "Prebuild script not found, skipping") || tsx /api/langgraph_api/js/build.mts'
if build_context:
build_workdir = faux_path
else:
build_workdir = faux_path
if flat:
return (
_build_flat_node_dockerfile(
config=config,
image=image_str,
env_vars=env_vars,
install_workdir=install_workdir,
build_workdir=build_workdir,
install_command=install_cmd,
build_command=build_cmd,
),
{},
)
docker_file_contents = [
f"FROM {image_str}",
"",
os.linesep.join(config["dockerfile_lines"]),
"",
f"ADD . {faux_path if not build_context else container_root}",
f"ADD . {install_workdir}",
"",
f"WORKDIR {install_workdir}",
"",
install_step,
f"RUN {install_cmd}",
"",
os.linesep.join(env_vars),
"",
f"WORKDIR {build_workdir}",
"",
build_step,
f"RUN {build_cmd}",
]
return os.linesep.join(docker_file_contents), {}
@@ -1625,6 +1872,7 @@ def config_to_docker(
build_command: str | None = None,
build_context: str | None = None,
escape_variables: bool = False,
flat: bool = False,
) -> tuple[str, dict[str, str]]:
base_image = base_image or default_base_image(config)
@@ -1637,6 +1885,7 @@ def config_to_docker(
install_command=install_command,
build_command=build_command,
build_context=build_context,
flat=flat,
)
return python_config_to_docker(
@@ -1645,6 +1894,7 @@ def config_to_docker(
base_image=base_image,
api_version=api_version,
escape_variables=escape_variables,
flat=flat,
)
+2
View File
@@ -345,6 +345,7 @@ def build_docker_image(
docker_command: Sequence[str] | None = None,
extra_flags: Sequence[str] = (),
verbose: bool = True,
flat: bool = False,
):
"""Build a Docker image from a LangGraph config."""
# pull latest images
@@ -387,6 +388,7 @@ def build_docker_image(
install_command=install_command,
build_command=build_command,
build_context=build_context,
flat=flat,
)
# add additional_contexts
if additional_contexts:
+16
View File
@@ -970,6 +970,22 @@ def python_config_to_docker_uv_lock(
f"{uv_export_project_dir}/uv.lock",
)
)
for package_root in sorted(
plan.all_workspace_roots,
key=lambda root: root.as_posix(),
):
if package_root == plan.project_root:
continue
package_relative_path = pathlib.PurePosixPath(
package_root.relative_to(plan.project_root).as_posix()
)
package_pyproject_path = package_relative_path / "pyproject.toml"
docker_plan.add_raw(
copy_from_project_root(
package_pyproject_path,
f"{uv_export_project_dir}/{package_pyproject_path.as_posix()}",
)
)
docker_plan.add_instruction("WORKDIR", uv_export_project_dir)
docker_plan.add_instruction(
"RUN",
+119
View File
@@ -723,6 +723,67 @@ WORKDIR /deps/outer-unit_tests/unit_tests\
}
def test_config_to_docker_flat():
dockerfile, additional_contexts = config_to_docker(
PATH_TO_CONFIG,
validate_config(
{"dependencies": ["."], "graphs": {"agent": "./agent.py:graph"}}
),
base_image="langchain/langgraph-api",
flat=True,
)
assert additional_contexts == {}
assert dockerfile.count("\nRUN ") == 1
assert "--mount=type=bind" in dockerfile
assert "cp -a /__build_context/. /deps/outer-unit_tests/unit_tests/" in dockerfile
assert "cat > /deps/outer-unit_tests/pyproject.toml <<'PYPROJECT'" in dockerfile
assert '[tool.setuptools.package-data]\n"*" = ["**/*"]' in dockerfile
assert dockerfile.endswith("WORKDIR /deps/outer-unit_tests/unit_tests")
def test_config_to_docker_flat_with_custom_lines_and_escaped_variables():
dockerfile, _ = config_to_docker(
PATH_TO_CONFIG,
validate_config(
{
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"dockerfile_lines": ["RUN echo custom"],
}
),
base_image="langchain/langgraph-api",
escape_variables=True,
flat=True,
)
assert dockerfile.index("RUN echo custom") < dockerfile.index("USER_LAYER")
assert 'echo "Installing $$dep"' in dockerfile
def test_config_to_docker_flat_with_additional_context():
dockerfile, additional_contexts = config_to_docker(
PATH_TO_CONFIG,
validate_config(
{"dependencies": [".", ".."], "graphs": {"agent": "./agent.py:graph"}}
),
base_image="langchain/langgraph-api",
flat=True,
)
assert additional_contexts == {
"outer-tests": str(pathlib.Path(__file__).parent.parent.absolute()),
}
assert (
"--mount=type=bind,from=outer-tests,"
"target=/__additional_contexts/outer-tests,readonly" in dockerfile
)
assert (
"cp -a /__additional_contexts/outer-tests/. /deps/outer-tests/tests/"
in dockerfile
)
def test_config_to_docker_outside_path():
graphs = {"agent": "./agent.py:graph"}
actual_docker_stdin, additional_contexts = config_to_docker(
@@ -998,6 +1059,28 @@ RUN (test ! -f /api/langgraph_api/js/build.mts && echo "Prebuild script not foun
assert additional_contexts == {}
def test_config_to_docker_nodejs_flat():
dockerfile, additional_contexts = config_to_docker(
PATH_TO_CONFIG,
validate_config(
{
"node_version": "20",
"graphs": {"agent": "./graphs/agent.js:graph"},
"dockerfile_lines": ["RUN echo custom"],
}
),
base_image="langchain/langgraphjs-api",
flat=True,
)
assert additional_contexts == {}
assert dockerfile.index("RUN echo custom") < dockerfile.index("USER_LAYER")
assert "cp -a /__build_context/. /deps/unit_tests/" in dockerfile
assert "cd /deps/unit_tests\nnpm i" in dockerfile
assert "tsx /api/langgraph_api/js/build.mts" in dockerfile
assert dockerfile.endswith("WORKDIR /deps/unit_tests")
def test_config_to_docker_python_encryption():
# Test that encryption config is included in validation
graphs = {"agent": "./agent.py:graph"}
@@ -1214,6 +1297,29 @@ WORKDIR /deps/outer-unit_tests/unit_tests"""
assert additional_contexts == {}
def test_config_to_docker_gen_ui_python_flat():
dockerfile, additional_contexts = config_to_docker(
PATH_TO_CONFIG,
validate_config(
{
"dependencies": ["."],
"graphs": {"agent": "./agent.py:graph"},
"ui": {"agent": "./graphs/agent.ui.jsx"},
}
),
base_image="langchain/langgraph-api",
flat=True,
)
assert additional_contexts == {}
assert dockerfile.count("\nRUN ") == 1
assert dockerfile.index("ENV NODE_VERSION=20") < dockerfile.index("\nRUN ")
assert dockerfile.index("ENV LANGGRAPH_UI=") < dockerfile.index("\nRUN ")
assert "/storage/install-node.sh" in dockerfile
assert "cd /deps/outer-unit_tests/unit_tests\nnpm i" in dockerfile
assert "tsx /api/langgraph_api/js/build.mts" in dockerfile
def test_config_to_docker_multiplatform():
graphs = {
"python": "./multiplatform/python.py:graph",
@@ -1403,6 +1509,19 @@ def test_config_to_docker_uv_lock():
"COPY --from=uv-workspace-root uv.lock /tmp/uv_export/project/uv.lock"
in docker
)
workspace_pyprojects = [
"apps/agent/pyproject.toml",
"libs/extra/pyproject.toml",
"libs/shared/pyproject.toml",
]
export_instruction = "RUN uv export --package agent"
for pyproject_path in workspace_pyprojects:
copy_instruction = (
"COPY --from=uv-workspace-root "
f"{pyproject_path} /tmp/uv_export/project/{pyproject_path}"
)
assert copy_instruction in docker
assert docker.index(copy_instruction) < docker.index(export_instruction)
assert additional_contexts == {"uv-workspace-root": str(project_root.resolve())}
assert (
+6 -6
View File
@@ -266,20 +266,20 @@ wheels = [
[[package]]
name = "langgraph-checkpoint"
version = "4.0.1"
version = "4.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "langchain-core" },
{ name = "ormsgpack" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b1/44/a8df45d1e8b4637e29789fa8bae1db022c953cc7ac80093cfc52e923547e/langgraph_checkpoint-4.0.1.tar.gz", hash = "sha256:b433123735df11ade28829e40ce25b9be614930cd50245ff2af60629234befd9", size = 158135, upload-time = "2026-02-27T21:06:16.092Z" }
sdist = { url = "https://files.pythonhosted.org/packages/dc/e1/089c4c9e0a2fec7f883f82ae8e6a727138d50074cfeb6644bc2d13b1019b/langgraph_checkpoint-4.2.0.tar.gz", hash = "sha256:51a593b6bee684b0818e5d6e58e28ab340c6db7794575056ce7bd1b746a84ed7", size = 180239, upload-time = "2026-08-07T20:05:03.756Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/65/4c/09a4a0c42f5d2fc38d6c4d67884788eff7fd2cfdf367fdf7033de908b4c0/langgraph_checkpoint-4.0.1-py3-none-any.whl", hash = "sha256:e3adcd7a0e0166f3b48b8cf508ce0ea366e7420b5a73aa81289888727769b034", size = 50453, upload-time = "2026-02-27T21:06:14.293Z" },
{ url = "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl", hash = "sha256:0547fd228935a0b758865de3a3d6d7a2537c308895d0f9ab092ce9151b5da942", size = 56833, upload-time = "2026-08-07T20:05:02.655Z" },
]
[[package]]
name = "langgraph-checkpoint-postgres"
version = "3.0.5"
version = "3.1.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "langgraph-checkpoint" },
@@ -287,9 +287,9 @@ dependencies = [
{ name = "psycopg" },
{ name = "psycopg-pool" },
]
sdist = { url = "https://files.pythonhosted.org/packages/95/7a/8f439966643d32111248a225e6cb33a182d07c90de780c4dbfc1e0377832/langgraph_checkpoint_postgres-3.0.5.tar.gz", hash = "sha256:a8fd7278a63f4f849b5cbc7884a15ca8f41e7d5f7467d0a66b31e8c24492f7eb", size = 127856, upload-time = "2026-03-18T21:25:29.785Z" }
sdist = { url = "https://files.pythonhosted.org/packages/06/92/1e8959f8cd1b56e672fde3227f6fd642be85af6c5fd662d73921074aa39d/langgraph_checkpoint_postgres-3.1.1.tar.gz", hash = "sha256:d320e147ddad8c374cd546df0b52b532dd54d0541dd9fd23fc738cbd5de76f41", size = 150413, upload-time = "2026-07-30T19:15:39.014Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e8/87/b0f98b33a67204bca9d5619bcd9574222f6b025cf3c125eedcec9a50ecbc/langgraph_checkpoint_postgres-3.0.5-py3-none-any.whl", hash = "sha256:86d7040a88fd70087eaafb72251d796696a0a2d856168f5c11ef620771411552", size = 42907, upload-time = "2026-03-18T21:25:28.75Z" },
{ url = "https://files.pythonhosted.org/packages/03/32/ba457698a48a0e18d786caa770033067049fbe36d6846f8e50f13b594b51/langgraph_checkpoint_postgres-3.1.1-py3-none-any.whl", hash = "sha256:6e353aecd8150de144fef8e51a49076f58b7d6830d4cf51392b7ad4d79832ba7", size = 50778, upload-time = "2026-07-30T19:15:37.405Z" },
]
[[package]]