Compare commits

..
Author SHA1 Message Date
Caspar Broekhuizen 4b6ac3e3d7 style(langgraph): fml 2025-10-16 11:57:54 -07:00
Caspar Broekhuizen 5eae68324a fix(langgraph): remove unnecessary code handling None invoke case 2025-10-16 11:56:16 -07:00
Caspar Broekhuizen dd02a773ab fix(langgraph): do NOT re-execute nodes on invoke(None, ...). fix tests 2025-10-16 11:33:43 -07:00
Caspar Broekhuizen 8b42793d30 style(langgraph): remove prints 2025-10-09 14:37:13 -07:00
Caspar Broekhuizen 7dba4f6791 style(langgraph): format lint 2025-10-09 14:33:30 -07:00
Caspar Broekhuizen b4549b436f fix(langgraph): don't save null writes to checkpoint 2025-10-09 14:22:53 -07:00
Caspar Broekhuizen 015563bd47 fix(langgraph): fix duplicate interrupt writes when resuming with None 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen 5e60b7eaeb fix(langgraph): add missing context var check 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen 8611ff7e98 fix(langgraph): add missing context check 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen c97f818c5c fix(langgraph): add context var check for async test 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen 330df89868 style(langgraph): fix spelling error 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen f2c3b3cc42 style(langgraph): lint 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen 26b7a6da77 fix(langgraph): cleanup rebase error 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen 9893a1602a refactor(langgraph): move helper 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen f06402ca80 style(langgraph): refactor and fml 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen 1b83cc280d fix(langgraph): add optimization support for node with multiple interrupts 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen eefe1f4d16 style(langgraph): rename vars and add comments for clarity 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen 9b48311b42 test(langgraph): add xfail test that node with multiple interrupts should not execute until both have been resumed 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen 6a58e0cd6a refactor(langgraph): clean up optimization logic 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen 29f1ae79ec fix(langgraph): fix interrupt optimization for AsyncPregelLoop 2025-10-08 15:43:31 -07:00
Caspar Broekhuizen 8420e966c4 test(langgraph): add async interrupt test. still failing test_interrupt_with_send_payloads_sequential_resume_async 2025-10-08 15:43:31 -07:00
Eugene YurtsevandCaspar Broekhuizen ab704272b8 x 2025-10-08 15:43:31 -07:00
Eugene YurtsevandCaspar Broekhuizen d23914adcc x 2025-10-08 15:43:31 -07:00
Eugene YurtsevandCaspar Broekhuizen e8cc79e3f7 x 2025-10-08 15:43:31 -07:00
Eugene YurtsevandCaspar Broekhuizen 711d81bc38 Test with multiple interrupts 2025-10-08 15:43:31 -07:00
Eugene YurtsevandCaspar Broekhuizen 40f0f72870 x 2025-10-08 15:43:31 -07:00
184 changed files with 7434 additions and 11996 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
name: "\U0001F41B Bug Report" 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. 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] labels: [pending,bug]
body: body:
- type: markdown - type: markdown
attributes: attributes:
@@ -15,7 +15,7 @@ body:
* [LangChain Forum](https://forum.langchain.com/), * [LangChain Forum](https://forum.langchain.com/),
* [LangGraph Github Issues](https://github.com/langchain-ai/langgraph/issues), * [LangGraph Github Issues](https://github.com/langchain-ai/langgraph/issues),
* [LangGraph how-to guides](https://langchain-ai.github.io/langgraph/how-tos/). * [LangGraph how-to guides](https://langchain-ai.github.io/langgraph/how-tos/).
* [LangChain documentation with the integrated search](https://docs.langchain.com/), * [LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction),
* [GitHub search](https://github.com/langchain-ai/langgraph), * [GitHub search](https://github.com/langchain-ai/langgraph),
- type: checkboxes - type: checkboxes
id: checks id: checks
+13 -37
View File
@@ -1,8 +1,7 @@
import logging
import pathlib import pathlib
import sys import sys
import time import time
from urllib import error, request from urllib import request, error
import langgraph_cli import langgraph_cli
import langgraph_cli.config import langgraph_cli.config
@@ -12,13 +11,9 @@ from langgraph_cli.constants import DEFAULT_PORT
from langgraph_cli.exec import Runner, subp_exec from langgraph_cli.exec import Runner, subp_exec
from langgraph_cli.progress import Progress from langgraph_cli.progress import Progress
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
def test(config: pathlib.Path, port: int, tag: str, verbose: bool): def test(config: pathlib.Path, port: int, tag: str, verbose: bool):
"""Spin up API with Postgres/Redis via docker compose and wait until ready.""" """Spin up API with Postgres/Redis via docker compose and wait until ready."""
logger.info("Starting test...")
with Runner() as runner, Progress(message="Pulling...") as set: with Runner() as runner, Progress(message="Pulling...") as set:
# Detect docker/compose capabilities # Detect docker/compose capabilities
capabilities = langgraph_cli.docker.check_capabilities(runner) capabilities = langgraph_cli.docker.check_capabilities(runner)
@@ -62,9 +57,7 @@ def test(config: pathlib.Path, port: int, tag: str, verbose: bool):
sys.stderr.write(f"docker compose up failed: {e}\n") sys.stderr.write(f"docker compose up failed: {e}\n")
try: try:
sys.stderr.write("\n== docker compose ps ==\n") sys.stderr.write("\n== docker compose ps ==\n")
runner.run( runner.run(subp_exec(*compose_cmd, *args, "ps", input=stdin, verbose=False))
subp_exec(*compose_cmd, *args, "ps", input=stdin, verbose=False)
)
except Exception: except Exception:
pass pass
try: try:
@@ -100,7 +93,7 @@ def test(config: pathlib.Path, port: int, tag: str, verbose: bool):
set("") set("")
base_url = f"http://localhost:{port}" base_url = f"http://localhost:{port}"
ok_url = f"{base_url}/ok" ok_url = f"{base_url}/ok"
logger.info(f"Waiting for {ok_url} to respond with 200...") print(f"Waiting for {ok_url} to respond with 200...")
deadline = time.time() + 30 deadline = time.time() + 30
last_err: Exception | None = None last_err: Exception | None = None
while time.time() < deadline: while time.time() < deadline:
@@ -114,16 +107,13 @@ def test(config: pathlib.Path, port: int, tag: str, verbose: bool):
break break
else: else:
last_err = RuntimeError(f"Unexpected status: {resp.status}") last_err = RuntimeError(f"Unexpected status: {resp.status}")
logger.error(f"Unexpected status: {resp.status}") print(f"Unexpected status: {resp.status}")
except error.URLError as e: except error.URLError as e:
logger.error(f"URLError: {e}")
last_err = e last_err = e
except Exception as e: # noqa: BLE001 except Exception as e: # noqa: BLE001
logger.error(f"Exception: {e}")
last_err = e last_err = e
time.sleep(0.5) time.sleep(0.5)
else: else:
logger.error("Timeout waiting for /ok to return 200")
# Bring stack down before raising # Bring stack down before raising
args_down = [*args, "down", "-v", "--remove-orphans"] args_down = [*args, "down", "-v", "--remove-orphans"]
try: try:
@@ -141,23 +131,15 @@ def test(config: pathlib.Path, port: int, tag: str, verbose: bool):
) )
# Clean up: bring compose stack down to free ports for next test # Clean up: bring compose stack down to free ports for next test
logger.info("Test succeeded. Bringing down compose stack...") args_down = [*args, "down", "-v", "--remove-orphans"]
try: runner.run(
args_down = [*args, "down", "-v", "--remove-orphans"] subp_exec(
runner.run( *compose_cmd,
subp_exec( *args_down,
*compose_cmd, input=stdin,
*args_down, verbose=verbose,
input=stdin,
verbose=verbose,
)
) )
logger.info("Compose stack down. Finishing...") )
except Exception:
logger.exception("Failed to bring down compose stack")
pass
logger.info("Test finished")
if __name__ == "__main__": if __name__ == "__main__":
@@ -168,10 +150,4 @@ if __name__ == "__main__":
parser.add_argument("-c", "--config", type=str, default="./langgraph.json") 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", type=int, default=DEFAULT_PORT)
args = parser.parse_args() args = parser.parse_args()
try: test(pathlib.Path(args.config), args.port, args.tag, verbose=True)
test(pathlib.Path(args.config), args.port, args.tag, verbose=True)
except BaseException:
logger.exception("Test failed")
raise
logger.info("Test execution finished")
+9 -17
View File
@@ -13,7 +13,7 @@ jobs:
matrix: matrix:
python-version: python-version:
- "3.10" - "3.10"
- "3.14" - "3.11"
example: example:
- name: A - name: A
workdir: libs/cli/examples workdir: libs/cli/examples
@@ -40,7 +40,7 @@ jobs:
filter: "libs/cli/**" filter: "libs/cli/**"
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
if: steps.changed-files.outputs.all if: steps.changed-files.outputs.all
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
enable-cache: true enable-cache: true
@@ -66,19 +66,19 @@ jobs:
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 }}
- name: Build JS service - 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 working-directory: libs/cli/js-examples
run: | run: |
langgraph build -t langgraph-test-e langgraph build -t langgraph-test-e
- name: Build JS monorepo service - name: Build JS monorepo service
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }} if: steps.changed-files.outputs.all
working-directory: libs/cli/js-monorepo-example working-directory: libs/cli/js-monorepo-example
run: | run: |
langgraph build -t langgraph-test-f -c apps/agent/langgraph.json --build-command "yarn run turbo build" --install-command "yarn install" 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 - name: Build Python monorepo service
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }} if: steps.changed-files.outputs.all
working-directory: libs/cli/python-monorepo-example working-directory: libs/cli/python-monorepo-example
run: | run: |
langgraph build -t langgraph-test-g -c apps/agent/langgraph.json langgraph build -t langgraph-test-g -c apps/agent/langgraph.json
@@ -87,32 +87,24 @@ jobs:
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 -c apps/agent/langgraph.json
- name: Build and test prerelease reqs service - name: Build and test prerelease reqs service
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }} if: steps.changed-files.outputs.all
working-directory: libs/cli/examples/graph_prerelease_reqs working-directory: libs/cli/examples/graph_prerelease_reqs
run: | run: |
langgraph build -t langgraph-test-h langgraph build -t langgraph-test-h
cp ../.env.example .env cp ../.env.example .env
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; fi 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 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);") 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 if [ "$LANGGRAPH_VERSION" != "1.0.0a2" ]; then
echo "LANGGRAPH_VERSION != 1.0.2; $LANGGRAPH_VERSION"
exit 1 exit 1
fi 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 python -c "import sys; from importlib.metadata import version; v = version('langchain-openai'); print(v);")
if [ "$LANGCHAIN_OPENAI_VERSION" != "1.0.1" ]; then if [ "$LANGCHAIN_OPENAI_VERSION" != "0.3.0" ]; 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 exit 1
fi fi
- name: Build and test prerelease reqs fail service - name: Build and test prerelease reqs fail service
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }} if: steps.changed-files.outputs.all
working-directory: libs/cli/examples/graph_prerelease_reqs_fail working-directory: libs/cli/examples/graph_prerelease_reqs_fail
run: | run: |
langgraph build -t langgraph-test-i || [ $? -eq 1 ] langgraph build -t langgraph-test-i || [ $? -eq 1 ]
+3 -3
View File
@@ -39,7 +39,7 @@ jobs:
filter: "${{ inputs.working-directory }}/**" filter: "${{ inputs.working-directory }}/**"
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
if: steps.changed-files.outputs.all if: steps.changed-files.outputs.all
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
enable-cache: true enable-cache: true
@@ -48,7 +48,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
if: steps.changed-files.outputs.all if: steps.changed-files.outputs.all
working-directory: ${{ inputs.working-directory }} 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 - name: Get .mypy_cache to speed up mypy
if: steps.changed-files.outputs.all if: steps.changed-files.outputs.all
@@ -74,7 +74,7 @@ jobs:
- name: Install test dependencies - name: Install test dependencies
if: steps.changed-files.outputs.all if: steps.changed-files.outputs.all
working-directory: ${{ inputs.working-directory }} working-directory: ${{ inputs.working-directory }}
run: uv sync --group lint run: uv sync --group dev
- name: Get .mypy_cache_test to speed up mypy - name: Get .mypy_cache_test to speed up mypy
if: steps.changed-files.outputs.all if: steps.changed-files.outputs.all
+3 -3
View File
@@ -17,17 +17,17 @@ jobs:
strategy: strategy:
matrix: matrix:
python-version: python-version:
- "3.9"
- "3.10" - "3.10"
- "3.11" - "3.11"
- "3.12" - "3.12"
- "3.13" - "3.13"
- "3.14"
name: "test #${{ matrix.python-version }}" name: "test #${{ matrix.python-version }}"
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
enable-cache: true enable-cache: true
@@ -42,7 +42,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
shell: bash shell: bash
working-directory: ${{ inputs.working-directory }} working-directory: ${{ inputs.working-directory }}
run: uv sync --frozen --group test --no-dev run: uv sync --frozen --group dev
- name: Run tests - name: Run tests
shell: bash shell: bash
+3 -3
View File
@@ -12,11 +12,11 @@ jobs:
strategy: strategy:
matrix: matrix:
python-version: python-version:
- "3.9"
- "3.10" - "3.10"
- "3.11" - "3.11"
- "3.12" - "3.12"
- "3.13" - "3.13"
- "3.14"
defaults: defaults:
run: run:
@@ -25,7 +25,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
enable-cache: true enable-cache: true
@@ -39,7 +39,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
shell: bash shell: bash
run: uv sync --frozen --group test --no-dev run: uv sync --frozen --group dev
- name: Run tests - name: Run tests
shell: bash shell: bash
+4 -3
View File
@@ -16,6 +16,7 @@ permissions:
jobs: jobs:
build: build:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
@@ -26,7 +27,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Set up Python $${ env.PYTHON_VERSION }} - name: Set up Python $${ env.PYTHON_VERSION }}
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: ${{ env.PYTHON_VERSION }} python-version: ${{ env.PYTHON_VERSION }}
enable-cache: true enable-cache: true
@@ -48,7 +49,7 @@ jobs:
working-directory: ${{ inputs.working-directory }} working-directory: ${{ inputs.working-directory }}
- name: Upload build - name: Upload build
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: test-dist name: test-dist
path: ${{ inputs.working-directory }}/dist/ path: ${{ inputs.working-directory }}/dist/
@@ -76,7 +77,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- uses: actions/download-artifact@v6 - uses: actions/download-artifact@v5
with: with:
name: test-dist name: test-dist
path: ${{ inputs.working-directory }}/dist/ path: ${{ inputs.working-directory }}/dist/
+2 -2
View File
@@ -20,13 +20,13 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- run: SHA=$(git rev-parse HEAD) && echo "SHA=$SHA" >> $GITHUB_ENV - run: SHA=$(git rev-parse HEAD) && echo "SHA=$SHA" >> $GITHUB_ENV
- name: Set up Python 3.11 - name: Set up Python 3.11
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: "3.11" python-version: "3.11"
enable-cache: true enable-cache: true
cache-suffix: "bench" cache-suffix: "bench"
- name: Install dependencies - name: Install dependencies
run: uv sync --group test run: uv sync --group dev
- name: Run benchmarks - name: Run benchmarks
run: OUTPUT=out/benchmark-baseline.json make -s benchmark run: OUTPUT=out/benchmark-baseline.json make -s benchmark
- name: Save outputs - name: Save outputs
+2 -2
View File
@@ -22,13 +22,13 @@ jobs:
with: with:
format: json format: json
- name: Set up Python 3.11 - name: Set up Python 3.11
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: "3.11" python-version: "3.11"
enable-cache: true enable-cache: true
cache-suffix: "bench" cache-suffix: "bench"
- name: Install dependencies - name: Install dependencies
run: uv sync --group test run: uv sync --group dev
- name: Download baseline - name: Download baseline
uses: actions/cache/restore@v4 uses: actions/cache/restore@v4
with: with:
+1 -1
View File
@@ -120,7 +120,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: "3.11" python-version: "3.11"
enable-cache: true enable-cache: true
+84 -6
View File
@@ -1,9 +1,12 @@
name: Deploy Docs Redirects name: Deploy Docs
on: on:
push: push:
branches: branches:
- main - main
pull_request:
branches:
- main
workflow_dispatch: workflow_dispatch:
permissions: permissions:
@@ -20,6 +23,18 @@ defaults:
working-directory: docs working-directory: docs
jobs: jobs:
get-changed-files:
runs-on: ubuntu-latest
outputs:
changed-files: ${{ steps.changed-files.outputs.added_modified }}
steps:
- uses: actions/checkout@v5
- name: Get changed files
id: changed-files
uses: Ana06/get-changed-files@v2.3.0
with:
filter: "docs/docs/**"
deploy: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 10 # Job will be cancelled if it runs for more than 10 minutes timeout-minutes: 10 # Job will be cancelled if it runs for more than 10 minutes
@@ -31,7 +46,7 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: Set up Python - name: Set up Python
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: "3.12" python-version: "3.12"
enable-cache: true enable-cache: true
@@ -47,21 +62,84 @@ jobs:
uv run pip install "git+https://${GITHUB_TOKEN}@github.com/langchain-ai/mkdocs-material-insiders.git" uv run pip install "git+https://${GITHUB_TOKEN}@github.com/langchain-ai/mkdocs-material-insiders.git"
fi 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 - name: Build llms-text
run: make llms-text run: make llms-text
- name: Build site
- name: Build site (redirects only) run: |
run: make build-docs # 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: env:
MKDOCS_GIT_COMMITTERS_APIKEY: ${{ secrets.MKDOCS_GIT_COMMITTERS_APIKEY }}
OPENAI_API_KEY: sf-proj-1234567890 # fake placeholder, shouldn't actually be used 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 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 - name: Configure GitHub Pages
if: github.ref == 'refs/heads/main' if: github.ref == 'refs/heads/main'
uses: actions/configure-pages@v5 uses: actions/configure-pages@v5
- name: Upload Pages Artifact - name: Upload Pages Artifact
if: github.ref == 'refs/heads/main' # if: github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@v4 uses: actions/upload-pages-artifact@v4
with: with:
path: ./docs/site/ path: ./docs/site/
+9 -8
View File
@@ -16,6 +16,7 @@ env:
jobs: jobs:
build: build:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
@@ -28,7 +29,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Set up Python - name: Set up Python
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: ${{ env.PYTHON_VERSION }} python-version: ${{ env.PYTHON_VERSION }}
enable-cache: true enable-cache: true
@@ -50,7 +51,7 @@ jobs:
working-directory: ${{ inputs.working-directory }} working-directory: ${{ inputs.working-directory }}
- name: Upload build - name: Upload build
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: dist name: dist
path: ${{ inputs.working-directory }}/dist/ path: ${{ inputs.working-directory }}/dist/
@@ -173,7 +174,7 @@ jobs:
# used in the real world. # used in the real world.
- name: Set up Python - name: Set up Python
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: ${{ env.PYTHON_VERSION }} python-version: ${{ env.PYTHON_VERSION }}
enable-cache: true enable-cache: true
@@ -221,7 +222,7 @@ jobs:
uv run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))" uv run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))"
- name: Import test dependencies - name: Import test dependencies
run: uv sync --group test run: uv sync --group dev
working-directory: ${{ inputs.working-directory }} working-directory: ${{ inputs.working-directory }}
# Overwrite the local version of the package with the test PyPI version. # Overwrite the local version of the package with the test PyPI version.
@@ -263,13 +264,13 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Set up Python - name: Set up Python
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: ${{ env.PYTHON_VERSION }} python-version: ${{ env.PYTHON_VERSION }}
enable-cache: true enable-cache: true
cache-suffix: "release" cache-suffix: "release"
- uses: actions/download-artifact@v6 - uses: actions/download-artifact@v5
with: with:
name: dist name: dist
path: ${{ inputs.working-directory }}/dist/ path: ${{ inputs.working-directory }}/dist/
@@ -304,13 +305,13 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Set up Python - name: Set up Python
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: ${{ env.PYTHON_VERSION }} python-version: ${{ env.PYTHON_VERSION }}
enable-cache: true enable-cache: true
cache-suffix: "release" cache-suffix: "release"
- uses: actions/download-artifact@v6 - uses: actions/download-artifact@v5
with: with:
name: dist name: dist
path: ${{ inputs.working-directory }}/dist/ path: ${{ inputs.working-directory }}/dist/
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Set up Python + Poetry - name: Set up Python + Poetry
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
python-version: "3.11" python-version: "3.11"
enable-cache: true enable-cache: true
+2 -2
View File
@@ -19,10 +19,10 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- name: Set up uv - name: Set up uv
uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@v6
with: with:
# use minimum supported Python version # use minimum supported Python version
python-version: "3.10" python-version: "3.9"
enable-cache: true enable-cache: true
cache-suffix: "uv-lock-upgrade" cache-suffix: "uv-lock-upgrade"
+1 -1
View File
@@ -28,7 +28,7 @@ Below is a high-level overview:
- **langgraph** core framework for building stateful, multi-actor agents. - **langgraph** core framework for building stateful, multi-actor agents.
- **prebuilt** high-level APIs for creating and running agents and tools. - **prebuilt** high-level APIs for creating and running agents and tools.
- **sdk-js** JS/TS SDK for interacting with the LangGraph REST API. - **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 ### Dependency map
+2 -2
View File
@@ -63,8 +63,8 @@ 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: 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](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/). - [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://docs.langchain.com/oss/python/langchain/overview) Provides integrations and composable components to streamline LLM application development. - [LangChain](https://python.langchain.com/docs/introduction/) Provides integrations and composable components to streamline LLM application development.
> [!NOTE] > [!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/). > 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/).
+3 -9
View File
@@ -29,11 +29,7 @@ logger = logging.getLogger(__name__)
def _transform_link( def _transform_link(
link_name: str, link_name: str, scope: str, file_path: str, line_number: int, custom_title: Optional[str] = None
scope: str,
file_path: str,
line_number: int,
custom_title: Optional[str] = None,
) -> Optional[str]: ) -> Optional[str]:
"""Transform a cross-reference link based on the current scope. """Transform a cross-reference link based on the current scope.
@@ -42,7 +38,7 @@ def _transform_link(
scope: The current scope context ("global", "python", "js", etc.). scope: The current scope context ("global", "python", "js", etc.).
file_path: The file path for error reporting. file_path: The file path for error reporting.
line_number: The line number for error reporting. line_number: The line number for error reporting.
custom_title: Optional custom title for the link. If `None`, uses link_name. custom_title: Optional custom title for the link. If None, uses link_name.
Returns: Returns:
A formatted markdown link if the link is found in the scope mapping, A formatted markdown link if the link is found in the scope mapping,
@@ -121,9 +117,7 @@ CROSS_REFERENCE_PATTERN = re.compile(
) )
def _replace_autolinks( def _replace_autolinks(markdown: str, file_path: str, *, default_scope: str = "python") -> str:
markdown: str, file_path: str, *, default_scope: str = "python"
) -> str:
"""Preprocess markdown lines to handle @[links] with conditional fence scopes. """Preprocess markdown lines to handle @[links] with conditional fence scopes.
This function processes markdown content to transform @[link_name] references This function processes markdown content to transform @[link_name] references
@@ -2108,9 +2108,9 @@ __metadata:
linkType: hard linkType: hard
"hono@npm:^4.5.4": "hono@npm:^4.5.4":
version: 4.10.3 version: 4.9.7
resolution: "hono@npm:4.10.3" resolution: "hono@npm:4.9.7"
checksum: 10c0/bdcc4c7066c74ba7cfa63ed6550768a0f43a420286c8f8f74b7012ea4901b8b06778fa8e98264b46f1a86920f056b7ede1f07814da4934912f9945def4977c29 checksum: 10c0/089184660a9211ea216ab95bafa45260e371651cb019db49828064b7982b0ae61cc3c4715324bfeb9037aa2460c39ffa2c91d84ad0c8d500fa77cbcc7fc07a8f
languageName: node languageName: node
linkType: hard linkType: hard
+166 -490
View File
@@ -27,430 +27,185 @@ DISABLED = os.getenv("DISABLE_NOTEBOOK_CONVERT") in ("1", "true", "True")
REDIRECT_MAP = { REDIRECT_MAP = {
# lib redirects # lib redirects
"how-tos/stream-values.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": "https://docs.langchain.com/oss/python/langgraph/streaming", "how-tos/stream-updates.ipynb": "how-tos/streaming.md#stream-graph-state",
"how-tos/streaming-content.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming", "how-tos/streaming-content.ipynb": "how-tos/streaming.md",
"how-tos/stream-multiple.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming", "how-tos/stream-multiple.ipynb": "how-tos/streaming.md#stream-multiple-nodes",
"how-tos/streaming-tokens-without-langchain.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming", "how-tos/streaming-tokens-without-langchain.ipynb": "how-tos/streaming.md#use-with-any-llm",
"how-tos/streaming-from-final-node.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming", "how-tos/streaming-from-final-node.ipynb": "how-tos/streaming-specific-nodes.ipynb",
"how-tos/streaming-events-from-within-tools-without-langchain.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming", "how-tos/streaming-events-from-within-tools-without-langchain.ipynb": "how-tos/streaming-events-from-within-tools.ipynb#example-without-langchain",
# graph-api # graph-api
"how-tos/state-reducers.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#define-and-update-state", "how-tos/state-reducers.ipynb": "how-tos/graph-api.md#define-and-update-state",
"how-tos/sequence.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#create-a-sequence-of-steps", "how-tos/sequence.ipynb": "how-tos/graph-api.md#create-a-sequence-of-steps",
"how-tos/branching.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#create-branches", "how-tos/branching.ipynb": "how-tos/graph-api.md#create-branches",
"how-tos/recursion-limit.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#create-and-control-loops", "how-tos/recursion-limit.ipynb": "how-tos/graph-api.md#create-and-control-loops",
"how-tos/visualization.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#visualize-your-graph", "how-tos/visualization.ipynb": "how-tos/graph-api.md#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/input_output_schema.ipynb": "how-tos/graph-api.md#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/pass_private_state.ipynb": "how-tos/graph-api.md#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/state-model.ipynb": "how-tos/graph-api.md#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/map-reduce.ipynb": "how-tos/graph-api.md#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/command.ipynb": "how-tos/graph-api.md#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/configuration.ipynb": "how-tos/graph-api.md#add-runtime-configuration",
"how-tos/node-retries.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#add-retry-policies", "how-tos/node-retries.ipynb": "how-tos/graph-api.md#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/return-when-recursion-limit-hits.ipynb": "how-tos/graph-api.md#impose-a-recursion-limit",
"how-tos/async.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#async", "how-tos/async.ipynb": "how-tos/graph-api.md#async",
# memory how-tos # memory how-tos
"how-tos/memory/manage-conversation-history.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": "https://docs.langchain.com/oss/python/langgraph/add-memory#delete-messages", "how-tos/memory/delete-messages.ipynb": "how-tos/memory/add-memory.md#delete-messages",
"how-tos/memory/add-summary-conversation-history.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#summarize-messages", "how-tos/memory/add-summary-conversation-history.ipynb": "how-tos/memory/add-memory.md#summarize-messages",
"how-tos/memory.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory", "how-tos/memory.ipynb": "how-tos/memory/add-memory.md",
"agents/memory.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory", "agents/memory.ipynb": "how-tos/memory/add-memory.md",
# subgraph how-tos # subgraph how-tos
"how-tos/subgraph-transform-state.ipynb": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs#different-state-schemas", "how-tos/subgraph-transform-state.ipynb": "how-tos/subgraph.md#different-state-schemas",
"how-tos/subgraphs-manage-state.ipynb": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs#add-persistence", "how-tos/subgraphs-manage-state.ipynb": "how-tos/subgraph.md#add-persistence",
# persistence how-tos # persistence how-tos
"how-tos/persistence_postgres.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-in-production", "how-tos/persistence_postgres.ipynb": "how-tos/memory/add-memory.md#use-in-production",
"how-tos/persistence_mongodb.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-in-production", "how-tos/persistence_mongodb.ipynb": "how-tos/memory/add-memory.md#use-in-production",
"how-tos/persistence_redis.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-in-production", "how-tos/persistence_redis.ipynb": "how-tos/memory/add-memory.md#use-in-production",
"how-tos/subgraph-persistence.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-with-subgraphs", "how-tos/subgraph-persistence.ipynb": "how-tos/memory/add-memory.md#use-with-subgraphs",
"how-tos/cross-thread-persistence.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#add-long-term-memory", "how-tos/cross-thread-persistence.ipynb": "how-tos/memory/add-memory.md#add-long-term-memory",
"cloud/how-tos/copy_threads": "https://docs.langchain.com/langsmith/use-threads", "cloud/how-tos/copy_threads": "cloud/how-tos/use_threads",
"cloud/how-tos/check-thread-status": "https://docs.langchain.com/langsmith/use-threads", "cloud/how-tos/check-thread-status": "cloud/how-tos/use_threads",
"cloud/concepts/threads.md": "https://docs.langchain.com/oss/python/langgraph/persistence#threads", "cloud/concepts/threads.md": "concepts/persistence.md#threads",
"how-tos/persistence.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory", "how-tos/persistence.ipynb": "how-tos/memory/add-memory.md",
# tool calling how-tos # tool calling how-tos
"how-tos/tool-calling-errors.ipynb": "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": "https://docs.langchain.com/oss/python/langgraph/workflows-agents", "how-tos/pass-config-to-tools.ipynb": "how-tos/tool-calling.ipynb#access-config",
"how-tos/pass-run-time-values-to-tools.ipynb": "https://docs.langchain.com/oss/python/langgraph/workflows-agents", "how-tos/pass-run-time-values-to-tools.ipynb": "how-tos/tool-calling.ipynb#read-state",
"how-tos/update-state-from-tools.ipynb": "https://docs.langchain.com/oss/python/langgraph/workflows-agents", "how-tos/update-state-from-tools.ipynb": "how-tos/tool-calling.ipynb#update-state",
"agents/tools.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents", "agents/tools.md": "how-tos/tool-calling.md",
# multi-agent how-tos # multi-agent how-tos
"how-tos/agent-handoffs.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api", "how-tos/agent-handoffs.ipynb": "how-tos/multi_agent.md#handoffs",
"how-tos/multi-agent-network.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api", "how-tos/multi-agent-network.ipynb": "how-tos/multi_agent.md#use-in-a-multi-agent-system",
"how-tos/multi-agent-multi-turn-convo.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api", "how-tos/multi-agent-multi-turn-convo.ipynb": "how-tos/multi_agent.md#multi-turn-conversation",
# cloud redirects # cloud redirects
"cloud/index.md": "https://docs.langchain.com/oss/python/langgraph/overview", "cloud/index.md": "index.md",
"cloud/how-tos/index.md": "https://docs.langchain.com/langsmith/home", "cloud/how-tos/index.md": "concepts/langgraph_platform",
"cloud/concepts/api.md": "https://docs.langchain.com/langsmith/agent-server", "cloud/concepts/api.md": "concepts/langgraph_server.md",
"cloud/concepts/cloud.md": "https://docs.langchain.com/langsmith/cloud", "cloud/concepts/cloud.md": "concepts/langgraph_cloud.md",
"cloud/faq/studio.md": "https://docs.langchain.com/langsmith/studio", "cloud/faq/studio.md": "concepts/langgraph_studio.md#studio-faqs",
"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_edit_state.md": "cloud/how-tos/add-human-in-the-loop.md",
"cloud/how-tos/human_in_the_loop_user_input.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop", "cloud/how-tos/human_in_the_loop_user_input.md": "cloud/how-tos/add-human-in-the-loop.md",
"concepts/platform_architecture.md": "https://docs.langchain.com/langsmith/cloud#architecture", "concepts/platform_architecture.md": "concepts/langgraph_cloud#architecture",
# cloud streaming redirects # cloud streaming redirects
"cloud/how-tos/stream_values.md": "https://docs.langchain.com/langsmith/streaming", "cloud/how-tos/stream_values.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/how-tos/stream_updates.md": "https://docs.langchain.com/langsmith/streaming", "cloud/how-tos/stream_updates.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/how-tos/stream_messages.md": "https://docs.langchain.com/langsmith/streaming", "cloud/how-tos/stream_messages.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/how-tos/stream_events.md": "https://docs.langchain.com/langsmith/streaming", "cloud/how-tos/stream_events.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/how-tos/stream_debug.md": "https://docs.langchain.com/langsmith/streaming", "cloud/how-tos/stream_debug.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/how-tos/stream_multiple.md": "https://docs.langchain.com/langsmith/streaming", "cloud/how-tos/stream_multiple.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/concepts/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming", "cloud/concepts/streaming.md": "concepts/streaming.md",
"agents/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming", "agents/streaming.md": "how-tos/streaming.md",
# prebuilt redirects # prebuilt redirects
"how-tos/create-react-agent.ipynb": "https://docs.langchain.com/oss/python/langchain/agents#basic-configuration", "how-tos/create-react-agent.ipynb": "agents/agents.md#basic-configuration",
"how-tos/create-react-agent-memory.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory", "how-tos/create-react-agent-memory.ipynb": "agents/memory.md",
"how-tos/create-react-agent-system-prompt.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory", "how-tos/create-react-agent-system-prompt.ipynb": "agents/context.md#prompts",
"how-tos/create-react-agent-structured-output.ipynb": "https://docs.langchain.com/oss/python/langchain/agents#structured-output", "how-tos/create-react-agent-structured-output.ipynb": "agents/agents.md#structured-output",
# misc # misc
"prebuilt.md": "https://docs.langchain.com/oss/python/langchain/agents", "prebuilt.md": "agents/prebuilt.md",
"reference/prebuilt.md": "https://reference.langchain.com/python/langgraph/agents/", "reference/prebuilt.md": "reference/agents.md",
"concepts/high_level.md": "https://docs.langchain.com/oss/python/langgraph/overview", "concepts/high_level.md": "index.md",
"concepts/index.md": "https://docs.langchain.com/oss/python/langgraph/overview", "concepts/index.md": "index.md",
"concepts/v0-human-in-the-loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts", "concepts/v0-human-in-the-loop.md": "concepts/human-in-the-loop.md",
"how-tos/index.md": "https://docs.langchain.com/oss/python/langgraph/overview", "how-tos/index.md": "index.md",
"tutorials/introduction.ipynb": "https://docs.langchain.com/oss/python/langgraph/overview", "tutorials/introduction.ipynb": "concepts/why-langgraph.md",
"agents/deployment.md": "https://docs.langchain.com/oss/python/langgraph/local-server", "agents/deployment.md": "tutorials/langgraph-platform/local-server.md",
# deployment redirects # deployment redirects
"how-tos/deploy-self-hosted.md": "https://docs.langchain.com/langsmith/platform-setup", "how-tos/deploy-self-hosted.md": "cloud/deployment/self_hosted_data_plane.md",
"concepts/self_hosted.md": "https://docs.langchain.com/langsmith/platform-setup", "concepts/self_hosted.md": "concepts/langgraph_self_hosted_data_plane.md",
"tutorials/deployment.md": "https://docs.langchain.com/langsmith/deployments", "tutorials/deployment.md": "concepts/deployment_options.md",
# assistant redirects # assistant redirects
"cloud/how-tos/assistant_versioning.md": "https://docs.langchain.com/langsmith/configuration-cloud", "cloud/how-tos/assistant_versioning.md": "cloud/how-tos/configuration_cloud.md",
"cloud/concepts/runs.md": "https://docs.langchain.com/langsmith/assistants#execution", "cloud/concepts/runs.md": "concepts/assistants.md#execution",
# hitl redirects # hitl redirects
"how-tos/wait-user-input-functional.ipynb": "https://docs.langchain.com/oss/python/langgraph/functional-api", "how-tos/wait-user-input-functional.ipynb": "how-tos/use-functional-api.md",
"how-tos/review-tool-calls-functional.ipynb": "https://docs.langchain.com/oss/python/langgraph/functional-api", "how-tos/review-tool-calls-functional.ipynb": "how-tos/use-functional-api.md",
"how-tos/create-react-agent-hitl.ipynb": "https://docs.langchain.com/oss/python/langgraph/interrupts", "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": "https://docs.langchain.com/oss/python/langgraph/interrupts", "agents/human-in-the-loop.md": "how-tos/human_in_the_loop/add-human-in-the-loop.md",
"how-tos/human_in_the_loop/dynamic_breakpoints.ipynb": "https://docs.langchain.com/oss/python/langgraph/interrupts", "how-tos/human_in_the_loop/dynamic_breakpoints.ipynb": "how-tos/human_in_the_loop/breakpoints.md",
"concepts/breakpoints.md": "https://docs.langchain.com/oss/python/langgraph/interrupts", "concepts/breakpoints.md": "concepts/human_in_the_loop.md",
"how-tos/human_in_the_loop/breakpoints.md": "https://docs.langchain.com/oss/python/langgraph/interrupts", "how-tos/human_in_the_loop/breakpoints.md": "how-tos/human_in_the_loop/add-human-in-the-loop.md",
"cloud/how-tos/human_in_the_loop_breakpoint.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop", "cloud/how-tos/human_in_the_loop_breakpoint.md": "cloud/how-tos/add-human-in-the-loop.md",
"how-tos/human_in_the_loop/edit-graph-state.ipynb": "https://docs.langchain.com/oss/python/langgraph/use-time-travel", "how-tos/human_in_the_loop/edit-graph-state.ipynb": "how-tos/human_in_the_loop/time-travel.md",
# LGP mintlify migration redirects # LGP mintlify migration redirects
"examples/index.md": "https://docs.langchain.com/oss/python/learn", "tutorials/auth/getting_started.md": "https://docs.langchain.com/langgraph-platform/auth",
"guides/index.md": "https://docs.langchain.com/oss/python/langgraph/overview", "tutorials/auth/resource_auth.md": "https://docs.langchain.com/langgraph-platform/resource-auth",
"concepts/index.md": "https://docs.langchain.com/oss/python/langgraph/overview", "tutorials/auth/add_auth_server.md": "https://docs.langchain.com/langgraph-platform/add-auth-server",
"tutorials/index.md": "https://docs.langchain.com/oss/python/learn", "how-tos/use-remote-graph.md": "https://docs.langchain.com/langgraph-platform/use-remote-graph",
"llms-txt-overview.md": "https://docs.langchain.com/llms.txt", "how-tos/autogen-integration.md": "https://docs.langchain.com/langgraph-platform/autogen-integration",
"tutorials/rag/langgraph_adaptive_rag.md": "https://docs.langchain.com/oss/python/langgraph/agentic-rag", "cloud/how-tos/use_stream_react.md": "https://docs.langchain.com/langgraph-platform/use-stream-react",
"tutorials/multi_agent/multi-agent-collaboration.ipynb": "https://docs.langchain.com/oss/python/langchain/multi-agent", "cloud/how-tos/generative_ui_react.md": "https://docs.langchain.com/langgraph-platform/generative-ui-react",
"how-tos/create-react-agent-manage-message-history.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory", "concepts/langgraph_platform.md": "https://docs.langchain.com/langgraph-platform/index",
"how-tos/many-tools.ipynb": "https://docs.langchain.com/oss/python/langchain/tools", "concepts/langgraph_components.md": "https://docs.langchain.com/langgraph-platform/components",
"tutorials/customer-support/customer-support.ipynb": "https://docs.langchain.com/oss/python/langgraph/agentic-rag", "concepts/langgraph_server.md": "https://docs.langchain.com/langgraph-platform/langgraph-server",
"how-tos/react-agent-structured-output.ipynb": "https://docs.langchain.com/oss/python/langchain/agents#structured-output", "concepts/langgraph_data_plane.md": "https://docs.langchain.com/langgraph-platform/data-plane",
"tutorials/code_assistant/langgraph_code_assistant.ipynb": "https://docs.langchain.com/oss/python/langgraph/agentic-rag", "concepts/langgraph_control_plane.md": "https://docs.langchain.com/langgraph-platform/control-plane",
"tutorials/multi_agent/hierarchical_agent_teams.ipynb": "https://docs.langchain.com/oss/python/langchain/supervisor", "concepts/langgraph_cli.md": "https://docs.langchain.com/langgraph-platform/langgraph-cli",
"tutorials/auth/getting_started.md": "https://docs.langchain.com/langsmith/auth", "concepts/langgraph_studio.md": "https://docs.langchain.com/langgraph-platform/langgraph-studio",
"tutorials/auth/resource_auth.md": "https://docs.langchain.com/langsmith/resource-auth", "cloud/how-tos/studio/quick_start.md": "https://docs.langchain.com/langgraph-platform/quick-start-studio",
"tutorials/auth/add_auth_server.md": "https://docs.langchain.com/langsmith/add-auth-server", "cloud/how-tos/invoke_studio.md": "https://docs.langchain.com/langgraph-platform/use-studio#run-application",
"how-tos/use-remote-graph.md": "https://docs.langchain.com/langsmith/use-remote-graph", "cloud/how-tos/studio/manage_assistants.md": "https://docs.langchain.com/langgraph-platform/use-studio#manage-assistants",
"how-tos/autogen-integration.md": "https://docs.langchain.com/langsmith/autogen-integration", "cloud/how-tos/threads_studio.md": "https://docs.langchain.com/langgraph-platform/use-studio#manage-threads",
"how-tos/human_in_the_loop/wait-user-input.ipynb": "https://docs.langchain.com/oss/python/langgraph/interrupts", "cloud/how-tos/iterate_graph_studio.md": "https://docs.langchain.com/langgraph-platform/observability-studio#iterate-on-prompts",
"cloud/how-tos/use_stream_react.md": "https://docs.langchain.com/langsmith/use-stream-react", "cloud/how-tos/studio/run_evals.md": "https://docs.langchain.com/langgraph-platform/observability-studio#run-experiments-over-a-dataset",
"cloud/how-tos/generative_ui_react.md": "https://docs.langchain.com/langsmith/generative-ui-react", "cloud/how-tos/clone_traces_studio.md": "https://docs.langchain.com/langgraph-platform/observability-studio#debug-langsmith-traces",
"concepts/langgraph_platform.md": "https://docs.langchain.com/langsmith/deployments", "cloud/how-tos/datasets_studio.md": "https://docs.langchain.com/langgraph-platform/observability-studio#add-node-to-dataset",
"concepts/langgraph_components.md": "https://docs.langchain.com/langsmith/components", "concepts/sdk.md": "https://docs.langchain.com/langgraph-platform/sdk",
"concepts/langgraph_server.md": "https://docs.langchain.com/langsmith/agent-server", "concepts/plans.md": "https://docs.langchain.com/langgraph-platform/plans",
"concepts/langgraph_data_plane.md": "https://docs.langchain.com/langsmith/data-plane", "concepts/application_structure.md": "https://docs.langchain.com/langgraph-platform/application-structure",
"concepts/langgraph_control_plane.md": "https://docs.langchain.com/langsmith/control-plane", "concepts/scalability_and_resilience.md": "https://docs.langchain.com/langgraph-platform/scalability-and-resilience",
"concepts/langgraph_cli.md": "https://docs.langchain.com/langsmith/cli", "concepts/auth.md": "https://docs.langchain.com/langgraph-platform/auth",
"concepts/langgraph_studio.md": "https://docs.langchain.com/langsmith/studio", "how-tos/auth/custom_auth.md": "https://docs.langchain.com/langgraph-platform/custom-auth",
"cloud/how-tos/studio/quick_start.md": "https://docs.langchain.com/langsmith/quick-start-studio", "how-tos/auth/openapi_security.md": "https://docs.langchain.com/langgraph-platform/openapi-security",
"cloud/how-tos/invoke_studio.md": "https://docs.langchain.com/langsmith/use-studio#run-application", "concepts/assistants.md": "https://docs.langchain.com/langgraph-platform/assistants",
"cloud/how-tos/studio/manage_assistants.md": "https://docs.langchain.com/langsmith/use-studio#manage-assistants", "cloud/how-tos/configuration_cloud.md": "https://docs.langchain.com/langgraph-platform/configuration-cloud",
"cloud/how-tos/threads_studio.md": "https://docs.langchain.com/langsmith/use-studio#manage-threads", "cloud/how-tos/use_threads.md": "https://docs.langchain.com/langgraph-platform/use-threads",
"cloud/how-tos/iterate_graph_studio.md": "https://docs.langchain.com/langsmith/observability-studio#iterate-on-prompts", "cloud/how-tos/background_run.md": "https://docs.langchain.com/langgraph-platform/background-run",
"cloud/how-tos/studio/run_evals.md": "https://docs.langchain.com/langsmith/observability-studio#run-experiments-over-a-dataset", "cloud/how-tos/same-thread.md": "https://docs.langchain.com/langgraph-platform/same-thread",
"cloud/how-tos/clone_traces_studio.md": "https://docs.langchain.com/langsmith/observability-studio#debug-langsmith-traces", "cloud/how-tos/stateless_runs.md": "https://docs.langchain.com/langgraph-platform/stateless-runs",
"cloud/how-tos/datasets_studio.md": "https://docs.langchain.com/langsmith/observability-studio#add-node-to-dataset", "cloud/how-tos/configurable_headers.md": "https://docs.langchain.com/langgraph-platform/configurable-headers",
"concepts/sdk.md": "https://docs.langchain.com/langsmith/sdk", "concepts/double_texting.md": "https://docs.langchain.com/langgraph-platform/double-texting",
"concepts/plans.md": "https://langchain.com/pricing", "cloud/how-tos/interrupt_concurrent.md": "https://docs.langchain.com/langgraph-platform/interrupt-concurrent",
"concepts/application_structure.md": "https://docs.langchain.com/langsmith/application-structure", "cloud/how-tos/rollback_concurrent.md": "https://docs.langchain.com/langgraph-platform/rollback-concurrent",
"concepts/scalability_and_resilience.md": "https://docs.langchain.com/langsmith/scalability-and-resilience", "cloud/how-tos/reject_concurrent.md": "https://docs.langchain.com/langgraph-platform/reject-concurrent",
"concepts/auth.md": "https://docs.langchain.com/langsmith/authentication-methods", "cloud/how-tos/enqueue_concurrent.md": "https://docs.langchain.com/langgraph-platform/enqueue-concurrent",
"how-tos/auth/custom_auth.md": "https://docs.langchain.com/langsmith/custom-auth", "cloud/concepts/webhooks.md": "https://docs.langchain.com/langgraph-platform/use-webhooks",
"how-tos/auth/openapi_security.md": "https://docs.langchain.com/langsmith/openapi-security", "cloud/how-tos/webhooks.md": "https://docs.langchain.com/langgraph-platform/use-webhooks",
"concepts/assistants.md": "https://docs.langchain.com/langsmith/assistants", "cloud/concepts/cron_jobs.md": "https://docs.langchain.com/langgraph-platform/cron-jobs",
"cloud/how-tos/configuration_cloud.md": "https://docs.langchain.com/langsmith/cloud", "cloud/how-tos/cron_jobs.md": "https://docs.langchain.com/langgraph-platform/cron-jobs",
"cloud/how-tos/use_threads.md": "https://docs.langchain.com/langsmith/use-threads", "how-tos/http/custom_lifespan.md": "https://docs.langchain.com/langgraph-platform/custom-lifespan",
"cloud/how-tos/background_run.md": "https://docs.langchain.com/langsmith/background-run", "how-tos/http/custom_middleware.md": "https://docs.langchain.com/langgraph-platform/custom-middleware",
"cloud/how-tos/same-thread.md": "https://docs.langchain.com/langsmith/same-thread", "how-tos/http/custom_routes.md": "https://docs.langchain.com/langgraph-platform/custom-routes",
"cloud/how-tos/stateless_runs.md": "https://docs.langchain.com/langsmith/stateless-runs", "cloud/concepts/data_storage_and_privacy.md": "https://docs.langchain.com/langgraph-platform/data-storage-and-privacy",
"cloud/how-tos/configurable_headers.md": "https://docs.langchain.com/langsmith/configurable-headers", "cloud/deployment/semantic_search.md": "https://docs.langchain.com/langgraph-platform/semantic-search",
"concepts/double_texting.md": "https://docs.langchain.com/langsmith/double-texting", "how-tos/ttl/configure_ttl.md": "https://docs.langchain.com/langgraph-platform/configure-ttl",
"cloud/how-tos/interrupt_concurrent.md": "https://docs.langchain.com/langsmith/interrupt-concurrent", "concepts/deployment_options.md": "https://docs.langchain.com/langgraph-platform/deployment-options",
"cloud/how-tos/rollback_concurrent.md": "https://docs.langchain.com/langsmith/rollback-concurrent", "cloud/quick_start.md": "https://docs.langchain.com/langgraph-platform/deployment-quickstart",
"cloud/how-tos/reject_concurrent.md": "https://docs.langchain.com/langsmith/reject-concurrent", "cloud/deployment/setup.md": "https://docs.langchain.com/langgraph-platform/setup-app-requirements-txt",
"cloud/how-tos/enqueue_concurrent.md": "https://docs.langchain.com/langsmith/enqueue-concurrent", "cloud/deployment/setup_pyproject.md": "https://docs.langchain.com/langgraph-platform/setup-pyproject",
"cloud/concepts/webhooks.md": "https://docs.langchain.com/langsmith/use-webhooks", "cloud/deployment/setup_javascript.md": "https://docs.langchain.com/langgraph-platform/setup-javascript",
"cloud/how-tos/webhooks.md": "https://docs.langchain.com/langsmith/use-webhooks", "cloud/deployment/custom_docker.md": "https://docs.langchain.com/langgraph-platform/custom-docker",
"cloud/concepts/cron_jobs.md": "https://docs.langchain.com/langsmith/cron-jobs", "cloud/deployment/graph_rebuild.md": "https://docs.langchain.com/langgraph-platform/graph-rebuild",
"cloud/how-tos/cron_jobs.md": "https://docs.langchain.com/langsmith/cron-jobs", "concepts/langgraph_cloud.md": "https://docs.langchain.com/langgraph-platform/cloud",
"how-tos/http/custom_lifespan.md": "https://docs.langchain.com/langsmith/custom-lifespan", "concepts/langgraph_self_hosted_data_plane.md": "https://docs.langchain.com/langgraph-platform/hybrid",
"how-tos/http/custom_middleware.md": "https://docs.langchain.com/langsmith/custom-middleware", "concepts/langgraph_self_hosted_control_plane.md": "https://docs.langchain.com/langgraph-platform/self-hosted",
"how-tos/http/custom_routes.md": "https://docs.langchain.com/langsmith/custom-routes", "concepts/langgraph_standalone_container.md": "https://docs.langchain.com/langgraph-platform/self-hosted#standalone-server",
"cloud/concepts/data_storage_and_privacy.md": "https://docs.langchain.com/langsmith/data-storage-and-privacy", "cloud/deployment/cloud.md": "https://docs.langchain.com/langgraph-platform/cloud",
"cloud/deployment/semantic_search.md": "https://docs.langchain.com/langsmith/semantic-search", "cloud/deployment/self_hosted_data_plane.md": "https://docs.langchain.com/langgraph-platform/deploy-hybrid",
"how-tos/ttl/configure_ttl.md": "https://docs.langchain.com/langsmith/configure-ttl", "cloud/deployment/self_hosted_control_plane.md": "https://docs.langchain.com/langgraph-platform/deploy-self-hosted-full-platform",
"concepts/deployment_options.md": "https://docs.langchain.com/langsmith/platform-setup", "cloud/deployment/standalone_container.md": "https://docs.langchain.com/langgraph-platform/deploy-standalone-server",
"cloud/quick_start.md": "https://docs.langchain.com/langsmith/deployment-quickstart", "concepts/server-mcp.md": "https://docs.langchain.com/langgraph-platform/server-mcp",
"cloud/deployment/setup.md": "https://docs.langchain.com/langsmith/setup-app-requirements-txt", "cloud/how-tos/human_in_the_loop_time_travel.md": "https://docs.langchain.com/langgraph-platform/human-in-the-loop-time-travel",
"cloud/deployment/setup_pyproject.md": "https://docs.langchain.com/langsmith/setup-pyproject", "cloud/how-tos/add-human-in-the-loop.md": "https://docs.langchain.com/langgraph-platform/add-human-in-the-loop",
"cloud/deployment/setup_javascript.md": "https://docs.langchain.com/langsmith/setup-javascript", "cloud/deployment/egress.md": "https://docs.langchain.com/langgraph-platform/env-var",
"cloud/deployment/custom_docker.md": "https://docs.langchain.com/langsmith/custom-docker", "cloud/how-tos/streaming.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/deployment/graph_rebuild.md": "https://docs.langchain.com/langsmith/graph-rebuild", "cloud/reference/api/api_ref.md": "https://docs.langchain.com/langgraph-platform/server-api-ref",
"concepts/langgraph_cloud.md": "https://docs.langchain.com/langsmith/cloud", "cloud/reference/langgraph_server_changelog.md": "https://docs.langchain.com/langgraph-platform/langgraph-server-changelog",
"concepts/langgraph_self_hosted_data_plane.md": "https://docs.langchain.com/langsmith/hybrid", "cloud/reference/api/api_ref_control_plane.md": "https://docs.langchain.com/langgraph-platform/api-ref-control-plane",
"concepts/langgraph_self_hosted_control_plane.md": "https://docs.langchain.com/langsmith/self-hosted", "cloud/reference/cli.md": "https://docs.langchain.com/langgraph-platform/cli",
"concepts/langgraph_standalone_container.md": "https://docs.langchain.com/langsmith/self-hosted#standalone-server", "cloud/reference/env_var.md": "https://docs.langchain.com/langgraph-platform/env-var",
"cloud/deployment/cloud.md": "https://docs.langchain.com/langsmith/cloud", "troubleshooting/studio.md": "https://docs.langchain.com/langgraph-platform/troubleshooting-studio",
"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",
} }
@@ -805,23 +560,6 @@ def on_post_page(html: str, page: Page, config: MkDocsConfig) -> str:
# Create HTML files for redirects after site dir has been built # Create HTML files for redirects after site dir has been built
def on_post_build(config): def on_post_build(config):
use_directory_urls = config.get("use_directory_urls") 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(): for page_old, page_new in REDIRECT_MAP.items():
# Convert .ipynb to .md for path calculation # Convert .ipynb to .md for path calculation
page_old = page_old.replace(".ipynb", ".md") page_old = page_old.replace(".ipynb", ".md")
@@ -840,12 +578,9 @@ def on_post_build(config):
else: else:
old_html_path = page_old + ".html" 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"): if isinstance(page_new, str) and page_new.startswith("http"):
# Handle external redirects # Handle external redirects
_write_html(site_dir, old_html_path, page_new) _write_html(config["site_dir"], old_html_path, page_new)
else: else:
# Handle internal redirects # Handle internal redirects
page_new = page_new.replace(".ipynb", ".md") page_new = page_new.replace(".ipynb", ".md")
@@ -873,63 +608,4 @@ def on_post_build(config):
new_html_path = page_new_before_hash + ".html" new_html_path = page_new_before_hash + ".html"
new_html_path += hash + suffix new_html_path += hash + suffix
_write_html(site_dir, old_html_path, new_html_path) _write_html(config["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)
@@ -20,19 +20,16 @@ class Package(TypedDict):
description: str description: str
"""A brief description of what the package does.""" """A brief description of what the package does."""
class ResolvedPackage(Package): class ResolvedPackage(Package):
weekly_downloads: int | None weekly_downloads: int | None
"""The weekly download count of the package.""" """The weekly download count of the package."""
language: str language: str
"""The language of the package. (either 'python' or 'js')""" """The language of the package. (either 'python' or 'js')"""
HERE = pathlib.Path(__file__).parent HERE = pathlib.Path(__file__).parent
PACKAGES_FILE = HERE / "packages.yml" PACKAGES_FILE = HERE / "packages.yml"
PACKAGES = yaml.safe_load(PACKAGES_FILE.read_text())["packages"] PACKAGES = yaml.safe_load(PACKAGES_FILE.read_text())["packages"]
def _get_pypi_downloads(package: Package) -> int: def _get_pypi_downloads(package: Package) -> int:
"""Retrieve the weekly download count for a package from PyPIStats.""" """Retrieve the weekly download count for a package from PyPIStats."""
@@ -76,7 +73,6 @@ def _get_pypi_downloads(package: Package) -> int:
else: else:
return None return None
def _get_npm_downloads(package: Package) -> int: def _get_npm_downloads(package: Package) -> int:
"""Retrieve the weekly download count for a package on the npm registry.""" """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 = requests.get(npm_url)
npm_response.raise_for_status() npm_response.raise_for_status()
except requests.exceptions.HTTPError: except requests.exceptions.HTTPError:
raise AssertionError( raise AssertionError(f"Package {package['name']} does not exist on npm registry")
f"Package {package['name']} does not exist on npm registry"
)
npm_data = npm_response.json() npm_data = npm_response.json()
# Retrieve the first publish date using the 'created' timestamp from the 'time' field. # Retrieve the first publish date using the 'created' timestamp from the 'time' field.
created_str = npm_data.get("time", {}).get("created") created_str = npm_data.get("time", {}).get("created")
if created_str is None: if created_str is None:
raise AssertionError( raise AssertionError(f"Package {package['name']} has no creation time in registry data")
f"Package {package['name']} has no creation time in registry data"
)
# Remove the trailing 'Z' if present and parse the ISO format timestamp # Remove the trailing 'Z' if present and parse the ISO format timestamp
first_publish_date = datetime.fromisoformat(created_str.rstrip("Z")) first_publish_date = datetime.fromisoformat(created_str.rstrip("Z"))
@@ -111,10 +103,7 @@ def _get_npm_downloads(package: Package) -> int:
else: else:
return None 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.""" """Retrieve the weekly download count for a dictionary of python or js packages."""
resolved_packages: list[ResolvedPackage] = [] resolved_packages: list[ResolvedPackage] = []
@@ -156,13 +145,12 @@ def _get_weekly_downloads(
return resolved_packages return resolved_packages
def main(output_file: str, fake: bool) -> None: def main(output_file: str, fake: bool) -> None:
"""Main function to generate package download information. """Main function to generate package download information.
Args: Args:
output_file: Path to the output YAML file. 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) resolved_packages: list[ResolvedPackage] = _get_weekly_downloads(PACKAGES, fake)
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"openapi": "3.1.0", "openapi": "3.1.0",
"info": { "info": {
"title": "LangSmith Deployment", "title": "LangGraph Platform",
"version": "0.1.0" "version": "0.1.0"
}, },
"tags": [ "tags": [
+2 -12
View File
@@ -22,15 +22,11 @@ To leverage durable execution in LangGraph, you need to:
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. 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 :::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). 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 :::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). 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).
::: :::
## Determinism and Consistent Replay ## Determinism and Consistent Replay
@@ -65,7 +61,7 @@ LangGraph supports three durability modes that allow you to balance performance
A higher durability mode add more overhead to the workflow execution. A higher durability mode add more overhead to the workflow execution.
!!! version-added "Added in version 0.6.0" !!! version-added "Added in v0.6.0"
Use the `durability` parameter instead of `checkpoint_during` (deprecated in v0.6.0) for persistence policy management: Use the `durability` parameter instead of `checkpoint_during` (deprecated in v0.6.0) for persistence policy management:
@@ -77,16 +73,14 @@ A higher durability mode add more overhead to the workflow execution.
* `checkpoint_during=True` -> `durability="async"` * `checkpoint_during=True` -> `durability="async"`
* `checkpoint_during=False` -> `durability="exit"` * `checkpoint_during=False` -> `durability="exit"`
### `"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. 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"` ### `"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. 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"` ### `"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. 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: You can specify the durability mode when calling any graph execution method:
@@ -316,14 +310,12 @@ Once you have enabled durable execution in your workflow, you can resume executi
- **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][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.
- **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). - **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 :::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][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.
- **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). - **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 ## Starting Points for Resuming Workflows
@@ -334,7 +326,6 @@ 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. - 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. 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. - If you're using the Functional API, the starting point is the beginning of the [**entrypoint**](./functional_api.md#entrypoint) where execution stopped.
::: :::
:::js :::js
@@ -343,5 +334,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. - 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. 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. - If you're using the Functional API, the starting point is the beginning of the [**entrypoint**](./functional_api.md#entrypoint) where execution stopped.
::: :::
+1 -1
View File
@@ -68,7 +68,7 @@ The server will start and open the studio in your browser:
> - 📚 API Docs: http://127.0.0.1:2024/docs > - 📚 API Docs: http://127.0.0.1:2024/docs
> >
> This in-memory server is designed for development and testing. > This in-memory server is designed for development and testing.
> For production use, please use LangSmith Deployment. > For production use, please use LangGraph Platform.
``` ```
If you were to self-host this on the public internet, anyone could access it! If you were to self-host this on the public internet, anyone could access it!
@@ -294,9 +294,9 @@ Now that you have a LangGraph app running locally, take your journey further by
:::python :::python
- [Python SDK Reference](../../cloud/reference/sdk/python_sdk_ref.md): Explore the Python SDK API Reference. - [Python SDK Reference](../../cloud/reference/sdk/python_sdk_ref.md): Explore the Python SDK API Reference.
::: :::
:::js :::js
- [JS/TS SDK Reference](../../cloud/reference/sdk/js_ts_sdk_ref.md): Explore the JS/TS SDK API Reference. - [JS/TS SDK Reference](../../cloud/reference/sdk/js_ts_sdk_ref.md): Explore the JS/TS SDK API Reference.
::: :::
+97 -61
View File
@@ -149,67 +149,6 @@ plugins:
- tutorials/auth/add_auth_server.md - tutorials/auth/add_auth_server.md
- tutorials/auth/getting_started.md - tutorials/auth/getting_started.md
- tutorials/auth/resource_auth.md - tutorials/auth/resource_auth.md
- agents/agents.md
- concepts/why-langgraph.md
- tutorials/get-started/1-build-basic-chatbot.md
- tutorials/get-started/2-add-tools.md
- tutorials/get-started/3-add-memory.md
- tutorials/get-started/4-human-in-the-loop.md
- tutorials/get-started/5-customize-state.md
- tutorials/get-started/6-time-travel.md
- tutorials/langgraph-platform/local-server.md
- tutorials/workflows.md
- concepts/agentic_concepts.md
- guides/index.md
- agents/overview.md
- agents/run_agents.md
- concepts/low_level.md
- how-tos/graph-api.md
- concepts/functional_api.md
- how-tos/use-functional-api.md
- concepts/pregel.md
- concepts/streaming.md
- how-tos/streaming.md
- concepts/persistence.md
- concepts/durable_execution.md
- concepts/memory.md
- how-tos/memory/add-memory.md
- agents/context.md
- agents/models.md
- concepts/tools.md
- how-tos/tool-calling.md
- concepts/human_in_the_loop.md
- how-tos/human_in_the_loop/add-human-in-the-loop.md
- concepts/time-travel.md
- how-tos/human_in_the_loop/time-travel.md
- concepts/subgraphs.md
- how-tos/subgraph.md
- concepts/multi_agent.md
- agents/multi-agent.md
- how-tos/multi_agent.md
- concepts/mcp.md
- agents/mcp.md
- concepts/tracing.md
- how-tos/enable-tracing.md
- agents/evals.md
- examples/index.md
- concepts/template_applications.md # TODO: make tutorial
- tutorials/rag/langgraph_agentic_rag.md
- tutorials/multi_agent/agent_supervisor.md
- tutorials/sql/sql-agent.md
- agents/ui.md
- how-tos/run-id-langsmith.md
- troubleshooting/errors/index.md
- troubleshooting/errors/GRAPH_RECURSION_LIMIT.md
- troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md
- troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md
- troubleshooting/errors/MULTIPLE_SUBGRAPHS.md
- troubleshooting/errors/INVALID_CHAT_HISTORY.md
- troubleshooting/errors/INVALID_LICENSE.md
- adopters.md
- concepts/faq.md
- agents/prebuilt.md # NOTE: prebuilt.md is auto-generated by `make build-prebuilt`
- tags - tags
- include-markdown - include-markdown
- mkdocstrings: - mkdocstrings:
@@ -247,6 +186,75 @@ plugins:
- "!^_" - "!^_"
nav: nav:
- Get started:
- index.md
- Quickstarts:
- Start with a prebuilt agent: agents/agents.md
- Build a custom workflow:
- concepts/why-langgraph.md
- 1. Build a basic chatbot: tutorials/get-started/1-build-basic-chatbot.md
- 2. Add tools: tutorials/get-started/2-add-tools.md
- 3. Add memory: tutorials/get-started/3-add-memory.md
- 4. Add human-in-the-loop: tutorials/get-started/4-human-in-the-loop.md
- 5. Customize state: tutorials/get-started/5-customize-state.md
- 6. Time travel: tutorials/get-started/6-time-travel.md
- Run a local server: tutorials/langgraph-platform/local-server.md
- General concepts:
- Workflows & agents: tutorials/workflows.md
- Agent architectures: concepts/agentic_concepts.md
- Guides:
- guides/index.md
- Agent development:
- Overview: agents/overview.md
- Run an agent: agents/run_agents.md
- LangGraph APIs:
- Graph API:
- Overview: concepts/low_level.md
- Use the Graph API: how-tos/graph-api.md
- Functional API:
- Overview: concepts/functional_api.md
- Use the Functional API: how-tos/use-functional-api.md
- Runtime: concepts/pregel.md
- Core capabilities:
- Streaming:
- Overview: concepts/streaming.md
- Stream outputs: how-tos/streaming.md
- Persistence:
- Overview: concepts/persistence.md
- Durable execution:
- Overview: concepts/durable_execution.md
- Memory:
- Overview: concepts/memory.md
- Add memory: how-tos/memory/add-memory.md
- Context:
- Add context: agents/context.md
- Models:
- Configure model: agents/models.md
- Tools:
- Overview: concepts/tools.md
- Call tools: how-tos/tool-calling.md
- Human-in-the-loop:
- Overview: concepts/human_in_the_loop.md
- Add human intervention: how-tos/human_in_the_loop/add-human-in-the-loop.md
- Time travel:
- Overview: concepts/time-travel.md
- Use time travel: how-tos/human_in_the_loop/time-travel.md
- Subgraphs:
- Overview: concepts/subgraphs.md
- Use subgraphs: how-tos/subgraph.md
- Multi-agent:
- Overview: concepts/multi_agent.md
- Prebuilt implementation: agents/multi-agent.md
- Custom implementation: how-tos/multi_agent.md
- MCP:
- Overview: concepts/mcp.md
- Use MCP: agents/mcp.md
- Tracing:
- Overview: concepts/tracing.md
- Enable tracing: how-tos/enable-tracing.md
- Evaluate performance: agents/evals.md
- Reference: - Reference:
- reference/index.md - reference/index.md
- LangGraph: - LangGraph:
@@ -272,6 +280,34 @@ nav:
- SDK (JS/TS): https://langchain-ai.github.io/langgraphjs/reference/modules/sdk.html - SDK (JS/TS): https://langchain-ai.github.io/langgraphjs/reference/modules/sdk.html
- RemoteGraph: reference/remote_graph.md - RemoteGraph: reference/remote_graph.md
- Examples:
- examples/index.md
- Template applications: concepts/template_applications.md # TODO: make tutorial
- Agentic RAG: tutorials/rag/langgraph_agentic_rag.md
- Agent Supervisor: tutorials/multi_agent/agent_supervisor.md
- SQL agent: tutorials/sql/sql-agent.md
- Prebuilt chat UI: agents/ui.md
- Graph runs in LangSmith: how-tos/run-id-langsmith.md
- Additional resources:
- additional-resources/index.md
- agents/prebuilt.md # NOTE: prebuilt.md is auto-generated by `make build-prebuilt`
- LangGraph Academy course: https://academy.langchain.com/courses/intro-to-langgraph
- Case studies: adopters.md
- concepts/faq.md
- llms.txt: llms-txt-overview.md
- LangChain Forum: https://forum.langchain.com/
- Troubleshooting:
- Errors:
- troubleshooting/errors/index.md
- troubleshooting/errors/GRAPH_RECURSION_LIMIT.md
- troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md
- troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md
- troubleshooting/errors/MULTIPLE_SUBGRAPHS.md
- troubleshooting/errors/INVALID_CHAT_HISTORY.md
- troubleshooting/errors/INVALID_LICENSE.md
markdown_extensions: markdown_extensions:
- abbr - abbr
- admonition - admonition
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024 LangChain, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -94,10 +94,9 @@ class PostgresSaver(BasePostgresSaver):
for v, migration in zip( for v, migration in zip(
range(version + 1, len(self.MIGRATIONS)), range(version + 1, len(self.MIGRATIONS)),
self.MIGRATIONS[version + 1 :], self.MIGRATIONS[version + 1 :],
strict=False,
): ):
cur.execute(migration) cur.execute(migration)
cur.execute("INSERT INTO checkpoint_migrations (v) VALUES (%s)", (v,)) cur.execute(f"INSERT INTO checkpoint_migrations (v) VALUES ({v})")
if self.pipe: if self.pipe:
self.pipe.sync() self.pipe.sync()
@@ -116,12 +115,12 @@ class PostgresSaver(BasePostgresSaver):
Args: Args:
config: The config to use for listing the checkpoints. config: The config to use for listing the checkpoints.
filter: Additional filtering criteria for metadata. filter: Additional filtering criteria for metadata. Defaults to None.
before: If provided, only checkpoints before the specified checkpoint ID are returned. before: If provided, only checkpoints before the specified checkpoint ID are returned. Defaults to None.
limit: The maximum number of checkpoints to return. limit: The maximum number of checkpoints to return. Defaults to None.
Yields: Yields:
An iterator of checkpoint tuples. Iterator[CheckpointTuple]: An iterator of checkpoint tuples.
Examples: Examples:
>>> from langgraph.checkpoint.postgres import PostgresSaver >>> from langgraph.checkpoint.postgres import PostgresSaver
@@ -183,7 +182,7 @@ class PostgresSaver(BasePostgresSaver):
"""Get a checkpoint tuple from the database. """Get a checkpoint tuple from the database.
This method retrieves a checkpoint tuple from the Postgres database based on the This method retrieves a checkpoint tuple from the Postgres database based on the
provided config. If the config contains a `checkpoint_id` key, the checkpoint with provided config. If the config contains a "checkpoint_id" key, the checkpoint with
the matching thread ID and timestamp is retrieved. Otherwise, the latest checkpoint the matching thread ID and timestamp is retrieved. Otherwise, the latest checkpoint
for the given thread ID is retrieved. for the given thread ID is retrieved.
@@ -191,7 +190,7 @@ class PostgresSaver(BasePostgresSaver):
config: The config to use for retrieving the checkpoint. config: The config to use for retrieving the checkpoint.
Returns: Returns:
The retrieved checkpoint tuple, or None if no matching checkpoint was found. Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.
Examples: Examples:
@@ -2,12 +2,13 @@
from collections.abc import AsyncIterator from collections.abc import AsyncIterator
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from typing import Union
from psycopg import AsyncConnection from psycopg import AsyncConnection
from psycopg.rows import DictRow from psycopg.rows import DictRow
from psycopg_pool import AsyncConnectionPool from psycopg_pool import AsyncConnectionPool
Conn = AsyncConnection[DictRow] | AsyncConnectionPool[AsyncConnection[DictRow]] Conn = Union[AsyncConnection[DictRow], AsyncConnectionPool[AsyncConnection[DictRow]]]
@asynccontextmanager @asynccontextmanager
@@ -2,12 +2,13 @@
from collections.abc import Iterator from collections.abc import Iterator
from contextlib import contextmanager from contextlib import contextmanager
from typing import Union
from psycopg import Connection from psycopg import Connection
from psycopg.rows import DictRow from psycopg.rows import DictRow
from psycopg_pool import ConnectionPool from psycopg_pool import ConnectionPool
Conn = Connection[DictRow] | ConnectionPool[Connection[DictRow]] Conn = Union[Connection[DictRow], ConnectionPool[Connection[DictRow]]]
@contextmanager @contextmanager
@@ -99,12 +99,9 @@ class AsyncPostgresSaver(BasePostgresSaver):
for v, migration in zip( for v, migration in zip(
range(version + 1, len(self.MIGRATIONS)), range(version + 1, len(self.MIGRATIONS)),
self.MIGRATIONS[version + 1 :], self.MIGRATIONS[version + 1 :],
strict=False,
): ):
await cur.execute(migration) await cur.execute(migration)
await cur.execute( await cur.execute(f"INSERT INTO checkpoint_migrations (v) VALUES ({v})")
"INSERT INTO checkpoint_migrations (v) VALUES (%s)", (v,)
)
if self.pipe: if self.pipe:
await self.pipe.sync() await self.pipe.sync()
@@ -124,11 +121,11 @@ class AsyncPostgresSaver(BasePostgresSaver):
Args: Args:
config: Base configuration for filtering checkpoints. config: Base configuration for filtering checkpoints.
filter: Additional filtering criteria for metadata. filter: Additional filtering criteria for metadata.
before: If provided, only checkpoints before the specified checkpoint ID are returned. before: If provided, only checkpoints before the specified checkpoint ID are returned. Defaults to None.
limit: Maximum number of checkpoints to return. limit: Maximum number of checkpoints to return.
Yields: Yields:
An asynchronous iterator of matching checkpoint tuples. AsyncIterator[CheckpointTuple]: An asynchronous iterator of matching checkpoint tuples.
""" """
where, args = self._search_where(config, filter, before) where, args = self._search_where(config, filter, before)
query = self.SELECT_SQL + where + " ORDER BY checkpoint_id DESC" query = self.SELECT_SQL + where + " ORDER BY checkpoint_id DESC"
@@ -172,7 +169,7 @@ class AsyncPostgresSaver(BasePostgresSaver):
"""Get a checkpoint tuple from the database asynchronously. """Get a checkpoint tuple from the database asynchronously.
This method retrieves a checkpoint tuple from the Postgres database based on the This method retrieves a checkpoint tuple from the Postgres database based on the
provided config. If the config contains a `checkpoint_id` key, the checkpoint with provided config. If the config contains a "checkpoint_id" key, the checkpoint with
the matching thread ID and "checkpoint_id" is retrieved. Otherwise, the latest checkpoint the matching thread ID and "checkpoint_id" is retrieved. Otherwise, the latest checkpoint
for the given thread ID is retrieved. for the given thread ID is retrieved.
@@ -180,7 +177,7 @@ class AsyncPostgresSaver(BasePostgresSaver):
config: The config to use for retrieving the checkpoint. config: The config to use for retrieving the checkpoint.
Returns: Returns:
The retrieved checkpoint tuple, or None if no matching checkpoint was found. Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.
""" """
thread_id = config["configurable"]["thread_id"] thread_id = config["configurable"]["thread_id"]
checkpoint_id = get_checkpoint_id(config) checkpoint_id = get_checkpoint_id(config)
@@ -447,11 +444,11 @@ class AsyncPostgresSaver(BasePostgresSaver):
Args: Args:
config: Base configuration for filtering checkpoints. config: Base configuration for filtering checkpoints.
filter: Additional filtering criteria for metadata. filter: Additional filtering criteria for metadata.
before: If provided, only checkpoints before the specified checkpoint ID are returned. before: If provided, only checkpoints before the specified checkpoint ID are returned. Defaults to None.
limit: Maximum number of checkpoints to return. limit: Maximum number of checkpoints to return.
Yields: Yields:
An iterator of matching checkpoint tuples. Iterator[CheckpointTuple]: An iterator of matching checkpoint tuples.
""" """
try: try:
# check if we are in the main thread, only bg threads can block # check if we are in the main thread, only bg threads can block
@@ -479,7 +476,7 @@ class AsyncPostgresSaver(BasePostgresSaver):
"""Get a checkpoint tuple from the database. """Get a checkpoint tuple from the database.
This method retrieves a checkpoint tuple from the Postgres database based on the This method retrieves a checkpoint tuple from the Postgres database based on the
provided config. If the config contains a `checkpoint_id` key, the checkpoint with provided config. If the config contains a "checkpoint_id" key, the checkpoint with
the matching thread ID and "checkpoint_id" is retrieved. Otherwise, the latest checkpoint the matching thread ID and "checkpoint_id" is retrieved. Otherwise, the latest checkpoint
for the given thread ID is retrieved. for the given thread ID is retrieved.
@@ -487,7 +484,7 @@ class AsyncPostgresSaver(BasePostgresSaver):
config: The config to use for retrieving the checkpoint. config: The config to use for retrieving the checkpoint.
Returns: Returns:
The retrieved checkpoint tuple, or None if no matching checkpoint was found. Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.
""" """
try: try:
# check if we are in the main thread, only bg threads can block # check if we are in the main thread, only bg threads can block
@@ -4,7 +4,7 @@ import random
import warnings import warnings
from collections.abc import Sequence from collections.abc import Sequence
from importlib.metadata import version as get_version from importlib.metadata import version as get_version
from typing import Any, cast from typing import Any, Optional, cast
from langchain_core.runnables import RunnableConfig from langchain_core.runnables import RunnableConfig
from langgraph.checkpoint.base import ( from langgraph.checkpoint.base import (
@@ -16,7 +16,7 @@ from langgraph.checkpoint.base import (
from langgraph.checkpoint.serde.types import TASKS from langgraph.checkpoint.serde.types import TASKS
from psycopg.types.json import Jsonb from psycopg.types.json import Jsonb
MetadataInput = dict[str, Any] | None MetadataInput = Optional[dict[str, Any]]
try: try:
major, minor = get_version("langgraph").split(".")[:2] major, minor = get_version("langgraph").split(".")[:2]
@@ -81,7 +81,7 @@ MIGRATIONS = [
""" """
CREATE INDEX CONCURRENTLY IF NOT EXISTS checkpoint_writes_thread_id_idx ON checkpoint_writes(thread_id); CREATE INDEX CONCURRENTLY IF NOT EXISTS checkpoint_writes_thread_id_idx ON checkpoint_writes(thread_id);
""", """,
"""ALTER TABLE checkpoint_writes ADD COLUMN IF NOT EXISTS task_path TEXT NOT NULL DEFAULT '';""", """ALTER TABLE checkpoint_writes ADD COLUMN task_path TEXT NOT NULL DEFAULT '';""",
] ]
SELECT_SQL = """ SELECT_SQL = """
@@ -3,7 +3,7 @@ import threading
import warnings import warnings
from collections.abc import AsyncIterator, Iterator, Sequence from collections.abc import AsyncIterator, Iterator, Sequence
from contextlib import asynccontextmanager, contextmanager from contextlib import asynccontextmanager, contextmanager
from typing import Any from typing import Any, Optional
from langchain_core.runnables import RunnableConfig from langchain_core.runnables import RunnableConfig
from langgraph.checkpoint.base import ( from langgraph.checkpoint.base import (
@@ -77,7 +77,7 @@ MIGRATIONS = [
CREATE INDEX CONCURRENTLY IF NOT EXISTS checkpoint_writes_thread_id_idx ON checkpoint_writes(thread_id); CREATE INDEX CONCURRENTLY IF NOT EXISTS checkpoint_writes_thread_id_idx ON checkpoint_writes(thread_id);
""", """,
""" """
ALTER TABLE checkpoint_writes ADD COLUMN IF NOT EXISTS task_path TEXT NOT NULL DEFAULT ''; ALTER TABLE checkpoint_writes ADD COLUMN task_path TEXT NOT NULL DEFAULT '';
""", """,
] ]
@@ -151,7 +151,7 @@ def _dump_blobs(
checkpoint_ns: str, checkpoint_ns: str,
values: dict[str, Any], values: dict[str, Any],
versions: ChannelVersions, versions: ChannelVersions,
) -> list[tuple[str, str, str, str, bytes | None]]: ) -> list[tuple[str, str, str, str, Optional[bytes]]]:
if not versions: if not versions:
return [] return []
@@ -186,8 +186,8 @@ class ShallowPostgresSaver(BasePostgresSaver):
def __init__( def __init__(
self, self,
conn: _internal.Conn, conn: _internal.Conn,
pipe: Pipeline | None = None, pipe: Optional[Pipeline] = None,
serde: SerializerProtocol | None = None, serde: Optional[SerializerProtocol] = None,
) -> None: ) -> None:
warnings.warn( warnings.warn(
"ShallowPostgresSaver is deprecated as of version 2.0.20 and will be removed in 3.0.0. " "ShallowPostgresSaver is deprecated as of version 2.0.20 and will be removed in 3.0.0. "
@@ -249,20 +249,19 @@ class ShallowPostgresSaver(BasePostgresSaver):
for v, migration in zip( for v, migration in zip(
range(version + 1, len(self.MIGRATIONS)), range(version + 1, len(self.MIGRATIONS)),
self.MIGRATIONS[version + 1 :], self.MIGRATIONS[version + 1 :],
strict=False,
): ):
cur.execute(migration) cur.execute(migration)
cur.execute("INSERT INTO checkpoint_migrations (v) VALUES (%s)", (v,)) cur.execute(f"INSERT INTO checkpoint_migrations (v) VALUES ({v})")
if self.pipe: if self.pipe:
self.pipe.sync() self.pipe.sync()
def list( def list(
self, self,
config: RunnableConfig | None, config: Optional[RunnableConfig],
*, *,
filter: dict[str, Any] | None = None, filter: Optional[dict[str, Any]] = None,
before: RunnableConfig | None = None, before: Optional[RunnableConfig] = None,
limit: int | None = None, limit: Optional[int] = None,
) -> Iterator[CheckpointTuple]: ) -> Iterator[CheckpointTuple]:
"""List checkpoints from the database. """List checkpoints from the database.
@@ -300,7 +299,7 @@ class ShallowPostgresSaver(BasePostgresSaver):
pending_writes=self._load_writes(value["pending_writes"]), pending_writes=self._load_writes(value["pending_writes"]),
) )
def get_tuple(self, config: RunnableConfig) -> CheckpointTuple | None: def get_tuple(self, config: RunnableConfig) -> Optional[CheckpointTuple]:
"""Get a checkpoint tuple from the database. """Get a checkpoint tuple from the database.
This method retrieves a checkpoint tuple from the Postgres database based on the This method retrieves a checkpoint tuple from the Postgres database based on the
@@ -310,7 +309,7 @@ class ShallowPostgresSaver(BasePostgresSaver):
config: The config to use for retrieving the checkpoint. config: The config to use for retrieving the checkpoint.
Returns: Returns:
The retrieved checkpoint tuple, or None if no matching checkpoint was found. Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.
Examples: Examples:
@@ -543,8 +542,8 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
def __init__( def __init__(
self, self,
conn: _ainternal.Conn, conn: _ainternal.Conn,
pipe: AsyncPipeline | None = None, pipe: Optional[AsyncPipeline] = None,
serde: SerializerProtocol | None = None, serde: Optional[SerializerProtocol] = None,
) -> None: ) -> None:
warnings.warn( warnings.warn(
"AsyncShallowPostgresSaver is deprecated as of version 2.0.20 and will be removed in 3.0.0. " "AsyncShallowPostgresSaver is deprecated as of version 2.0.20 and will be removed in 3.0.0. "
@@ -571,7 +570,7 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
conn_string: str, conn_string: str,
*, *,
pipeline: bool = False, pipeline: bool = False,
serde: SerializerProtocol | None = None, serde: Optional[SerializerProtocol] = None,
) -> AsyncIterator["AsyncShallowPostgresSaver"]: ) -> AsyncIterator["AsyncShallowPostgresSaver"]:
"""Create a new AsyncShallowPostgresSaver instance from a connection string. """Create a new AsyncShallowPostgresSaver instance from a connection string.
@@ -611,22 +610,19 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
for v, migration in zip( for v, migration in zip(
range(version + 1, len(self.MIGRATIONS)), range(version + 1, len(self.MIGRATIONS)),
self.MIGRATIONS[version + 1 :], self.MIGRATIONS[version + 1 :],
strict=False,
): ):
await cur.execute(migration) await cur.execute(migration)
await cur.execute( await cur.execute(f"INSERT INTO checkpoint_migrations (v) VALUES ({v})")
"INSERT INTO checkpoint_migrations (v) VALUES (%s)", (v,)
)
if self.pipe: if self.pipe:
await self.pipe.sync() await self.pipe.sync()
async def alist( async def alist(
self, self,
config: RunnableConfig | None, config: Optional[RunnableConfig],
*, *,
filter: dict[str, Any] | None = None, filter: Optional[dict[str, Any]] = None,
before: RunnableConfig | None = None, before: Optional[RunnableConfig] = None,
limit: int | None = None, limit: Optional[int] = None,
) -> AsyncIterator[CheckpointTuple]: ) -> AsyncIterator[CheckpointTuple]:
"""List checkpoints from the database asynchronously. """List checkpoints from the database asynchronously.
@@ -666,7 +662,7 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
), ),
) )
async def aget_tuple(self, config: RunnableConfig) -> CheckpointTuple | None: async def aget_tuple(self, config: RunnableConfig) -> Optional[CheckpointTuple]:
"""Get a checkpoint tuple from the database asynchronously. """Get a checkpoint tuple from the database asynchronously.
This method retrieves a checkpoint tuple from the Postgres database based on the This method retrieves a checkpoint tuple from the Postgres database based on the
@@ -676,7 +672,7 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
config: The config to use for retrieving the checkpoint. config: The config to use for retrieving the checkpoint.
Returns: Returns:
The retrieved checkpoint tuple, or None if no matching checkpoint was found. Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.
""" """
thread_id = config["configurable"]["thread_id"] thread_id = config["configurable"]["thread_id"]
checkpoint_ns = config["configurable"].get("checkpoint_ns", "") checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
@@ -865,11 +861,11 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
def list( def list(
self, self,
config: RunnableConfig | None, config: Optional[RunnableConfig],
*, *,
filter: dict[str, Any] | None = None, filter: Optional[dict[str, Any]] = None,
before: RunnableConfig | None = None, before: Optional[RunnableConfig] = None,
limit: int | None = None, limit: Optional[int] = None,
) -> Iterator[CheckpointTuple]: ) -> Iterator[CheckpointTuple]:
"""List checkpoints from the database. """List checkpoints from the database.
@@ -887,7 +883,7 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
except StopAsyncIteration: except StopAsyncIteration:
break break
def get_tuple(self, config: RunnableConfig) -> CheckpointTuple | None: def get_tuple(self, config: RunnableConfig) -> Optional[CheckpointTuple]:
"""Get a checkpoint tuple from the database. """Get a checkpoint tuple from the database.
This method retrieves a checkpoint tuple from the Postgres database based on the This method retrieves a checkpoint tuple from the Postgres database based on the
@@ -897,7 +893,7 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
config: The config to use for retrieving the checkpoint. config: The config to use for retrieving the checkpoint.
Returns: Returns:
The retrieved checkpoint tuple, or None if no matching checkpoint was found. Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.
""" """
try: try:
# check if we are in the main thread, only bg threads can block # check if we are in the main thread, only bg threads can block
@@ -2,10 +2,10 @@ from __future__ import annotations
import asyncio import asyncio
import logging import logging
from collections.abc import AsyncIterator, Callable, Iterable, Sequence from collections.abc import AsyncIterator, Iterable, Sequence
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from types import TracebackType from types import TracebackType
from typing import Any, cast from typing import Any, Callable, cast
import orjson import orjson
from langgraph.store.base import ( from langgraph.store.base import (
@@ -339,7 +339,7 @@ class AsyncPostgresStore(AsyncBatchedBaseStore, BasePostgresStore[_ainternal.Con
Args: Args:
timeout: Maximum time to wait for the task to stop, in seconds. timeout: Maximum time to wait for the task to stop, in seconds.
If `None`, wait indefinitely. If None, wait indefinitely.
Returns: Returns:
bool: True if the task was successfully stopped or wasn't running, bool: True if the task was successfully stopped or wasn't running,
@@ -465,9 +465,7 @@ class AsyncPostgresStore(AsyncBatchedBaseStore, BasePostgresStore[_ainternal.Con
query, query,
[ [
p p
for (ns, k, pathname, _), vector in zip( for (ns, k, pathname, _), vector in zip(txt_params, vectors)
txt_params, vectors, strict=False
)
for p in (ns, k, pathname, vector) for p in (ns, k, pathname, vector)
], ],
) )
@@ -488,13 +486,13 @@ class AsyncPostgresStore(AsyncBatchedBaseStore, BasePostgresStore[_ainternal.Con
vectors = await self.embeddings.aembed_documents( vectors = await self.embeddings.aembed_documents(
[query for _, query in embedding_requests] [query for _, query in embedding_requests]
) )
for (idx, _), vector in zip(embedding_requests, vectors, strict=False): for (idx, _), vector in zip(embedding_requests, vectors):
_paramslist = queries[idx][1] _paramslist = queries[idx][1]
for i in range(len(_paramslist)): for i in range(len(_paramslist)):
if _paramslist[i] is PLACEHOLDER: if _paramslist[i] is PLACEHOLDER:
_paramslist[i] = vector _paramslist[i] = vector
for (idx, _), (query, params) in zip(search_ops, queries, strict=False): for (idx, _), (query, params) in zip(search_ops, queries):
await cur.execute(query, params) await cur.execute(query, params)
rows = cast(list[Row], await cur.fetchall()) rows = cast(list[Row], await cur.fetchall())
items = [ items = [
@@ -512,7 +510,7 @@ class AsyncPostgresStore(AsyncBatchedBaseStore, BasePostgresStore[_ainternal.Con
cur: AsyncCursor[DictRow], cur: AsyncCursor[DictRow],
) -> None: ) -> None:
queries = self._get_batch_list_namespaces_queries(list_ops) queries = self._get_batch_list_namespaces_queries(list_ops)
for (query, params), (idx, _) in zip(queries, list_ops, strict=False): for (query, params), (idx, _) in zip(queries, list_ops):
await cur.execute(query, params) await cur.execute(query, params)
rows = cast(list[dict], await cur.fetchall()) rows = cast(list[dict], await cur.fetchall())
namespaces = [_decode_ns_bytes(row["truncated_prefix"]) for row in rows] namespaces = [_decode_ns_bytes(row["truncated_prefix"]) for row in rows]
@@ -6,16 +6,18 @@ import json
import logging import logging
import threading import threading
from collections import defaultdict from collections import defaultdict
from collections.abc import Callable, Iterable, Iterator, Sequence from collections.abc import Iterable, Iterator, Sequence
from contextlib import contextmanager from contextlib import contextmanager
from datetime import datetime from datetime import datetime
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any, Any,
Callable,
Generic, Generic,
Literal, Literal,
NamedTuple, NamedTuple,
TypeVar, TypeVar,
Union,
cast, cast,
) )
@@ -91,12 +93,7 @@ WHERE expires_at IS NOT NULL;
VECTOR_MIGRATIONS: Sequence[Migration] = [ VECTOR_MIGRATIONS: Sequence[Migration] = [
Migration( Migration(
""" """
DO $$ CREATE EXTENSION IF NOT EXISTS vector;
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'vector') THEN
CREATE EXTENSION vector;
END IF;
END $$;
""", """,
), ),
Migration( Migration(
@@ -144,7 +141,7 @@ CREATE INDEX CONCURRENTLY IF NOT EXISTS store_vectors_embedding_idx ON store_vec
] ]
C = TypeVar("C", bound=_pg_internal.Conn | _ainternal.Conn) C = TypeVar("C", bound=Union[_pg_internal.Conn, _ainternal.Conn])
class PoolConfig(TypedDict, total=False): class PoolConfig(TypedDict, total=False):
@@ -258,7 +255,7 @@ class BasePostgresStore(Generic[C]):
results = [] results = []
for namespace, items in namespace_groups.items(): for namespace, items in namespace_groups.items():
_, keys = zip(*items, strict=False) _, keys = zip(*items)
this_refresh_ttls = refresh_ttls[namespace] this_refresh_ttls = refresh_ttls[namespace]
query = """ query = """
@@ -871,7 +868,7 @@ class PostgresStore(BaseStore, BasePostgresStore[_pg_internal.Conn]):
Args: Args:
timeout: Maximum time to wait for the thread to stop, in seconds. timeout: Maximum time to wait for the thread to stop, in seconds.
If `None`, wait indefinitely. If None, wait indefinitely.
Returns: Returns:
bool: True if the thread was successfully stopped or wasn't running, bool: True if the thread was successfully stopped or wasn't running,
@@ -1017,9 +1014,7 @@ class PostgresStore(BaseStore, BasePostgresStore[_pg_internal.Conn]):
query, query,
[ [
p p
for (ns, k, pathname, _), vector in zip( for (ns, k, pathname, _), vector in zip(txt_params, vectors)
txt_params, vectors, strict=False
)
for p in (ns, k, pathname, vector) for p in (ns, k, pathname, vector)
], ],
) )
@@ -1040,15 +1035,13 @@ class PostgresStore(BaseStore, BasePostgresStore[_pg_internal.Conn]):
embeddings = self.embeddings.embed_documents( embeddings = self.embeddings.embed_documents(
[query for _, query in embedding_requests] [query for _, query in embedding_requests]
) )
for (idx, _), embedding in zip( for (idx, _), embedding in zip(embedding_requests, embeddings):
embedding_requests, embeddings, strict=False
):
_paramslist = queries[idx][1] _paramslist = queries[idx][1]
for i in range(len(_paramslist)): for i in range(len(_paramslist)):
if _paramslist[i] is PLACEHOLDER: if _paramslist[i] is PLACEHOLDER:
_paramslist[i] = embedding _paramslist[i] = embedding
for (idx, _), (query, params) in zip(search_ops, queries, strict=False): for (idx, _), (query, params) in zip(search_ops, queries):
cur.execute(query, params) cur.execute(query, params)
rows = cast(list[Row], cur.fetchall()) rows = cast(list[Row], cur.fetchall())
results[idx] = [ results[idx] = [
@@ -1065,7 +1058,7 @@ class PostgresStore(BaseStore, BasePostgresStore[_pg_internal.Conn]):
cur: Cursor[DictRow], cur: Cursor[DictRow],
) -> None: ) -> None:
for (query, params), (idx, _) in zip( for (query, params), (idx, _) in zip(
self._get_batch_list_namespaces_queries(list_ops), list_ops, strict=False self._get_batch_list_namespaces_queries(list_ops), list_ops
): ):
cur.execute(query, params) cur.execute(query, params)
results[idx] = [_decode_ns_bytes(row["truncated_prefix"]) for row in cur] results[idx] = [_decode_ns_bytes(row["truncated_prefix"]) for row in cur]
+8 -19
View File
@@ -4,45 +4,36 @@ build-backend = "hatchling.build"
[project] [project]
name = "langgraph-checkpoint-postgres" name = "langgraph-checkpoint-postgres"
version = "3.0.1" version = "2.0.25"
description = "Library with a Postgres implementation of LangGraph checkpoint saver." description = "Library with a Postgres implementation of LangGraph checkpoint saver."
authors = [] authors = []
requires-python = ">=3.10" requires-python = ">=3.9"
readme = "README.md" readme = "README.md"
license = "MIT" license = "MIT"
license-files = ['LICENSE'] license-files = ['LICENSE']
dependencies = [ dependencies = [
"langgraph-checkpoint>=2.1.2,<4.0.0", "langgraph-checkpoint>=2.1.2,<3.0.0",
"orjson>=3.10.1", "orjson>=3.10.1",
"psycopg>=3.2.0", "psycopg>=3.2.0",
"psycopg-pool>=3.2.0", "psycopg-pool>=3.2.0",
] ]
[project.urls] [project.urls]
Source = "https://github.com/langchain-ai/langgraph/tree/main/libs/checkpoint-postgres" Repository = "https://www.github.com/langchain-ai/langgraph"
Twitter = "https://x.com/LangChainAI"
Slack = "https://www.langchain.com/join-community"
Reddit = "https://www.reddit.com/r/LangChain/"
[dependency-groups] [dependency-groups]
test = [ dev = [
"ruff",
"codespell",
"pytest", "pytest",
"anyio", "anyio",
"pytest-asyncio", "pytest-asyncio",
"pytest-mock", "pytest-mock",
"mypy",
"psycopg[binary]", "psycopg[binary]",
"langgraph-checkpoint", "langgraph-checkpoint",
"pytest-watcher", "pytest-watcher",
] ]
lint = [
"ruff",
"codespell",
"mypy",
]
dev = [
{include-group = "test"},
{include-group = "lint"},
]
[tool.uv] [tool.uv]
default-groups = ['dev'] default-groups = ['dev']
@@ -64,10 +55,8 @@ lint.select = [
"UP", # pyupgrade "UP", # pyupgrade
"B", # flake8-bugbear "B", # flake8-bugbear
"I", # isort "I", # isort
"UP", # pyupgrade
] ]
lint.ignore = ["E501", "B008"] lint.ignore = ["E501", "B008"]
target-version = "py310"
[tool.mypy] [tool.mypy]
# https://mypy.readthedocs.io/en/stable/config_file.html # https://mypy.readthedocs.io/en/stable/config_file.html
@@ -3,6 +3,7 @@ from __future__ import annotations
import asyncio import asyncio
import itertools import itertools
import sys
import uuid import uuid
from collections.abc import AsyncIterator from collections.abc import AsyncIterator
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
@@ -33,6 +34,9 @@ TTL_MINUTES = TTL_SECONDS / 60
@pytest.fixture(scope="function", params=["default", "pipe", "pool"]) @pytest.fixture(scope="function", params=["default", "pipe", "pool"])
async def store(request) -> AsyncIterator[AsyncPostgresStore]: async def store(request) -> AsyncIterator[AsyncPostgresStore]:
if sys.version_info < (3, 10):
pytest.skip("Async Postgres tests require Python 3.10+")
database = f"test_{uuid.uuid4().hex[:16]}" database = f"test_{uuid.uuid4().hex[:16]}"
uri_parts = DEFAULT_URI.split("/") uri_parts = DEFAULT_URI.split("/")
uri_base = "/".join(uri_parts[:-1]) uri_base = "/".join(uri_parts[:-1])
@@ -354,6 +358,8 @@ async def _create_vector_store(
text_fields: list[str] | None = None, text_fields: list[str] | None = None,
) -> AsyncIterator[AsyncPostgresStore]: ) -> AsyncIterator[AsyncPostgresStore]:
"""Create a store with vector search enabled.""" """Create a store with vector search enabled."""
if sys.version_info < (3, 10):
pytest.skip("Async Postgres tests require Python 3.10+")
database = f"test_{uuid.uuid4().hex[:16]}" database = f"test_{uuid.uuid4().hex[:16]}"
uri_parts = DEFAULT_URI.split("/") uri_parts = DEFAULT_URI.split("/")
+3 -3
View File
@@ -754,7 +754,7 @@ def _cosine_similarity(X: list[float], Y: list[list[float]]) -> list[float]:
similarities = [] similarities = []
for y in Y: for y in Y:
dot_product = sum(a * b for a, b in zip(X, y, strict=False)) dot_product = sum(a * b for a, b in zip(X, y))
norm1 = sum(a * a for a in X) ** 0.5 norm1 = sum(a * a for a in X) ** 0.5
norm2 = sum(a * a for a in y) ** 0.5 norm2 = sum(a * a for a in y) ** 0.5
similarity = dot_product / (norm1 * norm2) if norm1 > 0 and norm2 > 0 else 0.0 similarity = dot_product / (norm1 * norm2) if norm1 > 0 and norm2 > 0 else 0.0
@@ -771,7 +771,7 @@ def _inner_product(X: list[float], Y: list[list[float]]) -> list[float]:
similarities = [] similarities = []
for y in Y: for y in Y:
similarity = sum(a * b for a, b in zip(X, y, strict=False)) similarity = sum(a * b for a, b in zip(X, y))
similarities.append(similarity) similarities.append(similarity)
return similarities return similarities
@@ -785,7 +785,7 @@ def _neg_l2_distance(X: list[float], Y: list[list[float]]) -> list[float]:
similarities = [] similarities = []
for y in Y: for y in Y:
similarity = sum((a - b) ** 2 for a, b in zip(X, y, strict=False)) ** 0.5 similarity = sum((a - b) ** 2 for a, b in zip(X, y)) ** 0.5
similarities.append(-similarity) similarities.append(-similarity)
return similarities return similarities
+221 -208
View File
@@ -1,6 +1,6 @@
version = 1 version = 1
revision = 3 revision = 3
requires-python = ">=3.10" requires-python = ">=3.9"
[[package]] [[package]]
name = "annotated-types" name = "annotated-types"
@@ -105,6 +105,17 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" },
{ url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" },
{ url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" },
{ url = "https://files.pythonhosted.org/packages/c2/ca/9a0983dd5c8e9733565cf3db4df2b0a2e9a82659fd8aa2a868ac6e4a991f/charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05", size = 207520, upload-time = "2025-08-09T07:57:11.026Z" },
{ url = "https://files.pythonhosted.org/packages/39/c6/99271dc37243a4f925b09090493fb96c9333d7992c6187f5cfe5312008d2/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e", size = 147307, upload-time = "2025-08-09T07:57:12.4Z" },
{ url = "https://files.pythonhosted.org/packages/e4/69/132eab043356bba06eb333cc2cc60c6340857d0a2e4ca6dc2b51312886b3/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99", size = 160448, upload-time = "2025-08-09T07:57:13.712Z" },
{ url = "https://files.pythonhosted.org/packages/04/9a/914d294daa4809c57667b77470533e65def9c0be1ef8b4c1183a99170e9d/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7", size = 157758, upload-time = "2025-08-09T07:57:14.979Z" },
{ url = "https://files.pythonhosted.org/packages/b0/a8/6f5bcf1bcf63cb45625f7c5cadca026121ff8a6c8a3256d8d8cd59302663/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7", size = 152487, upload-time = "2025-08-09T07:57:16.332Z" },
{ url = "https://files.pythonhosted.org/packages/c4/72/d3d0e9592f4e504f9dea08b8db270821c909558c353dc3b457ed2509f2fb/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19", size = 150054, upload-time = "2025-08-09T07:57:17.576Z" },
{ url = "https://files.pythonhosted.org/packages/20/30/5f64fe3981677fe63fa987b80e6c01042eb5ff653ff7cec1b7bd9268e54e/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312", size = 161703, upload-time = "2025-08-09T07:57:20.012Z" },
{ url = "https://files.pythonhosted.org/packages/e1/ef/dd08b2cac9284fd59e70f7d97382c33a3d0a926e45b15fc21b3308324ffd/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc", size = 159096, upload-time = "2025-08-09T07:57:21.329Z" },
{ url = "https://files.pythonhosted.org/packages/45/8c/dcef87cfc2b3f002a6478f38906f9040302c68aebe21468090e39cde1445/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34", size = 153852, upload-time = "2025-08-09T07:57:22.608Z" },
{ url = "https://files.pythonhosted.org/packages/63/86/9cbd533bd37883d467fcd1bd491b3547a3532d0fbb46de2b99feeebf185e/charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432", size = 99840, upload-time = "2025-08-09T07:57:23.883Z" },
{ url = "https://files.pythonhosted.org/packages/ce/d6/7e805c8e5c46ff9729c49950acc4ee0aeb55efb8b3a56687658ad10c3216/charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca", size = 107438, upload-time = "2025-08-09T07:57:25.287Z" },
{ url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" },
] ]
@@ -234,7 +245,7 @@ wheels = [
[[package]] [[package]]
name = "langgraph-checkpoint" name = "langgraph-checkpoint"
version = "3.0.1" version = "2.1.2"
source = { editable = "../checkpoint" } source = { editable = "../checkpoint" }
dependencies = [ dependencies = [
{ name = "langchain-core" }, { name = "langchain-core" },
@@ -244,7 +255,7 @@ dependencies = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "langchain-core", specifier = ">=0.2.38" }, { name = "langchain-core", specifier = ">=0.2.38" },
{ name = "ormsgpack", specifier = ">=1.12.0" }, { name = "ormsgpack", specifier = ">=1.10.0" },
] ]
[package.metadata.requires-dev] [package.metadata.requires-dev]
@@ -262,26 +273,10 @@ dev = [
{ name = "redis" }, { name = "redis" },
{ name = "ruff" }, { name = "ruff" },
] ]
lint = [
{ name = "codespell" },
{ name = "mypy" },
{ name = "ruff" },
]
test = [
{ name = "dataclasses-json" },
{ name = "numpy" },
{ name = "pandas" },
{ name = "pandas-stubs", specifier = ">=2.2.2.240807" },
{ name = "pytest" },
{ name = "pytest-asyncio" },
{ name = "pytest-mock" },
{ name = "pytest-watcher" },
{ name = "redis" },
]
[[package]] [[package]]
name = "langgraph-checkpoint-postgres" name = "langgraph-checkpoint-postgres"
version = "3.0.1" version = "2.0.25"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "langgraph-checkpoint" }, { name = "langgraph-checkpoint" },
@@ -303,20 +298,6 @@ dev = [
{ name = "pytest-watcher" }, { name = "pytest-watcher" },
{ name = "ruff" }, { name = "ruff" },
] ]
lint = [
{ name = "codespell" },
{ name = "mypy" },
{ name = "ruff" },
]
test = [
{ name = "anyio" },
{ name = "langgraph-checkpoint" },
{ name = "psycopg", extra = ["binary"] },
{ name = "pytest" },
{ name = "pytest-asyncio" },
{ name = "pytest-mock" },
{ name = "pytest-watcher" },
]
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
@@ -339,20 +320,6 @@ dev = [
{ name = "pytest-watcher" }, { name = "pytest-watcher" },
{ name = "ruff" }, { name = "ruff" },
] ]
lint = [
{ name = "codespell" },
{ name = "mypy" },
{ name = "ruff" },
]
test = [
{ name = "anyio" },
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
{ name = "psycopg", extras = ["binary"] },
{ name = "pytest" },
{ name = "pytest-asyncio" },
{ name = "pytest-mock" },
{ name = "pytest-watcher" },
]
[[package]] [[package]]
name = "langsmith" name = "langsmith"
@@ -414,6 +381,12 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/5b/11/040983fad5132d85914c874a2836252bbc57832065548885b5bb5b0d4359/mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb", size = 13326683, upload-time = "2025-09-19T00:09:55.572Z" }, { url = "https://files.pythonhosted.org/packages/5b/11/040983fad5132d85914c874a2836252bbc57832065548885b5bb5b0d4359/mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb", size = 13326683, upload-time = "2025-09-19T00:09:55.572Z" },
{ url = "https://files.pythonhosted.org/packages/e9/ba/89b2901dd77414dd7a8c8729985832a5735053be15b744c18e4586e506ef/mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075", size = 13514749, upload-time = "2025-09-19T00:10:44.827Z" }, { url = "https://files.pythonhosted.org/packages/e9/ba/89b2901dd77414dd7a8c8729985832a5735053be15b744c18e4586e506ef/mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075", size = 13514749, upload-time = "2025-09-19T00:10:44.827Z" },
{ url = "https://files.pythonhosted.org/packages/25/bc/cc98767cffd6b2928ba680f3e5bc969c4152bf7c2d83f92f5a504b92b0eb/mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf", size = 9982959, upload-time = "2025-09-19T00:10:37.344Z" }, { url = "https://files.pythonhosted.org/packages/25/bc/cc98767cffd6b2928ba680f3e5bc969c4152bf7c2d83f92f5a504b92b0eb/mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf", size = 9982959, upload-time = "2025-09-19T00:10:37.344Z" },
{ url = "https://files.pythonhosted.org/packages/3f/a6/490ff491d8ecddf8ab91762d4f67635040202f76a44171420bcbe38ceee5/mypy-1.18.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25a9c8fb67b00599f839cf472713f54249a62efd53a54b565eb61956a7e3296b", size = 12807230, upload-time = "2025-09-19T00:09:49.471Z" },
{ url = "https://files.pythonhosted.org/packages/eb/2e/60076fc829645d167ece9e80db9e8375648d210dab44cc98beb5b322a826/mypy-1.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2b9c7e284ee20e7598d6f42e13ca40b4928e6957ed6813d1ab6348aa3f47133", size = 11895666, upload-time = "2025-09-19T00:10:53.678Z" },
{ url = "https://files.pythonhosted.org/packages/97/4a/1e2880a2a5dda4dc8d9ecd1a7e7606bc0b0e14813637eeda40c38624e037/mypy-1.18.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6985ed057513e344e43a26cc1cd815c7a94602fb6a3130a34798625bc2f07b6", size = 12499608, upload-time = "2025-09-19T00:09:36.204Z" },
{ url = "https://files.pythonhosted.org/packages/00/81/a117f1b73a3015b076b20246b1f341c34a578ebd9662848c6b80ad5c4138/mypy-1.18.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f27105f1525ec024b5c630c0b9f36d5c1cc4d447d61fe51ff4bd60633f47ac", size = 13244551, upload-time = "2025-09-19T00:10:17.531Z" },
{ url = "https://files.pythonhosted.org/packages/9b/61/b9f48e1714ce87c7bf0358eb93f60663740ebb08f9ea886ffc670cea7933/mypy-1.18.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:030c52d0ea8144e721e49b1f68391e39553d7451f0c3f8a7565b59e19fcb608b", size = 13491552, upload-time = "2025-09-19T00:10:13.753Z" },
{ url = "https://files.pythonhosted.org/packages/c9/66/b2c0af3b684fa80d1b27501a8bdd3d2daa467ea3992a8aa612f5ca17c2db/mypy-1.18.2-cp39-cp39-win_amd64.whl", hash = "sha256:aa5e07ac1a60a253445797e42b8b2963c9675563a94f11291ab40718b016a7a0", size = 9765635, upload-time = "2025-09-19T00:10:30.993Z" },
{ url = "https://files.pythonhosted.org/packages/87/e3/be76d87158ebafa0309946c4a73831974d4d6ab4f4ef40c3b53a385a66fd/mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e", size = 2352367, upload-time = "2025-09-19T00:10:15.489Z" }, { url = "https://files.pythonhosted.org/packages/87/e3/be76d87158ebafa0309946c4a73831974d4d6ab4f4ef40c3b53a385a66fd/mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e", size = 2352367, upload-time = "2025-09-19T00:10:15.489Z" },
] ]
@@ -501,61 +474,67 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/da/09/17d9d2b60592890ff7382e591aa1d9afb202a266b180c3d4049b1ec70e4a/orjson-3.11.3-cp314-cp314-win32.whl", hash = "sha256:0c6d7328c200c349e3a4c6d8c83e0a5ad029bdc2d417f234152bf34842d0fc8d", size = 136266, upload-time = "2025-08-26T17:46:13.853Z" }, { url = "https://files.pythonhosted.org/packages/da/09/17d9d2b60592890ff7382e591aa1d9afb202a266b180c3d4049b1ec70e4a/orjson-3.11.3-cp314-cp314-win32.whl", hash = "sha256:0c6d7328c200c349e3a4c6d8c83e0a5ad029bdc2d417f234152bf34842d0fc8d", size = 136266, upload-time = "2025-08-26T17:46:13.853Z" },
{ url = "https://files.pythonhosted.org/packages/15/58/358f6846410a6b4958b74734727e582ed971e13d335d6c7ce3e47730493e/orjson-3.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:317bbe2c069bbc757b1a2e4105b64aacd3bc78279b66a6b9e51e846e4809f804", size = 131351, upload-time = "2025-08-26T17:46:15.27Z" }, { url = "https://files.pythonhosted.org/packages/15/58/358f6846410a6b4958b74734727e582ed971e13d335d6c7ce3e47730493e/orjson-3.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:317bbe2c069bbc757b1a2e4105b64aacd3bc78279b66a6b9e51e846e4809f804", size = 131351, upload-time = "2025-08-26T17:46:15.27Z" },
{ url = "https://files.pythonhosted.org/packages/28/01/d6b274a0635be0468d4dbd9cafe80c47105937a0d42434e805e67cd2ed8b/orjson-3.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:e8f6a7a27d7b7bec81bd5924163e9af03d49bbb63013f107b48eb5d16db711bc", size = 125985, upload-time = "2025-08-26T17:46:16.67Z" }, { url = "https://files.pythonhosted.org/packages/28/01/d6b274a0635be0468d4dbd9cafe80c47105937a0d42434e805e67cd2ed8b/orjson-3.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:e8f6a7a27d7b7bec81bd5924163e9af03d49bbb63013f107b48eb5d16db711bc", size = 125985, upload-time = "2025-08-26T17:46:16.67Z" },
{ url = "https://files.pythonhosted.org/packages/99/a6/18d88ccf8e5d8f711310eba9b4f6562f4aa9d594258efdc4dcf8c1550090/orjson-3.11.3-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:56afaf1e9b02302ba636151cfc49929c1bb66b98794291afd0e5f20fecaf757c", size = 238221, upload-time = "2025-08-26T17:46:18.113Z" },
{ url = "https://files.pythonhosted.org/packages/ee/18/e210365a17bf984c89db40c8be65da164b4ce6a866a2a0ae1d6407c2630b/orjson-3.11.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:913f629adef31d2d350d41c051ce7e33cf0fd06a5d1cb28d49b1899b23b903aa", size = 123209, upload-time = "2025-08-26T17:46:19.688Z" },
{ url = "https://files.pythonhosted.org/packages/26/43/6b3f8ec15fa910726ed94bd2e618f86313ad1cae7c3c8c6b9b8a3a161814/orjson-3.11.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0a23b41f8f98b4e61150a03f83e4f0d566880fe53519d445a962929a4d21045", size = 127881, upload-time = "2025-08-26T17:46:21.502Z" },
{ url = "https://files.pythonhosted.org/packages/4a/ed/f41d2406355ce67efdd4ab504732b27bea37b7dbdab3eb86314fe764f1b9/orjson-3.11.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d721fee37380a44f9d9ce6c701b3960239f4fb3d5ceea7f31cbd43882edaa2f", size = 130306, upload-time = "2025-08-26T17:46:22.914Z" },
{ url = "https://files.pythonhosted.org/packages/3e/a1/1be02950f92c82e64602d3d284bd76d9fc82a6b92c9ce2a387e57a825a11/orjson-3.11.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73b92a5b69f31b1a58c0c7e31080aeaec49c6e01b9522e71ff38d08f15aa56de", size = 132383, upload-time = "2025-08-26T17:46:24.33Z" },
{ url = "https://files.pythonhosted.org/packages/39/49/46766ac00c68192b516a15ffc44c2a9789ca3468b8dc8a500422d99bf0dd/orjson-3.11.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2489b241c19582b3f1430cc5d732caefc1aaf378d97e7fb95b9e56bed11725f", size = 135159, upload-time = "2025-08-26T17:46:25.741Z" },
{ url = "https://files.pythonhosted.org/packages/47/e1/27fd5e7600fdd82996329d48ee56f6e9e9ae4d31eadbc7f93fd2ff0d8214/orjson-3.11.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5189a5dab8b0312eadaf9d58d3049b6a52c454256493a557405e77a3d67ab7f", size = 132690, upload-time = "2025-08-26T17:46:27.271Z" },
{ url = "https://files.pythonhosted.org/packages/d8/21/f57ef08799a68c36ef96fe561101afeef735caa80814636b2e18c234e405/orjson-3.11.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9d8787bdfbb65a85ea76d0e96a3b1bed7bf0fbcb16d40408dc1172ad784a49d2", size = 131086, upload-time = "2025-08-26T17:46:33.067Z" },
{ url = "https://files.pythonhosted.org/packages/cd/84/a3a24306a9dc482e929232c65f5b8c69188136edd6005441d8cc4754f7ea/orjson-3.11.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:8e531abd745f51f8035e207e75e049553a86823d189a51809c078412cefb399a", size = 403884, upload-time = "2025-08-26T17:46:34.55Z" },
{ url = "https://files.pythonhosted.org/packages/11/98/fdae5b2c28bc358e6868e54c8eca7398c93d6a511f0436b61436ad1b04dc/orjson-3.11.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8ab962931015f170b97a3dd7bd933399c1bae8ed8ad0fb2a7151a5654b6941c7", size = 145837, upload-time = "2025-08-26T17:46:36.46Z" },
{ url = "https://files.pythonhosted.org/packages/7d/a9/2fe5cd69ed231f3ed88b1ad36a6957e3d2c876eb4b2c6b17b8ae0a6681fc/orjson-3.11.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:124d5ba71fee9c9902c4a7baa9425e663f7f0aecf73d31d54fe3dd357d62c1a7", size = 135325, upload-time = "2025-08-26T17:46:38.03Z" },
{ url = "https://files.pythonhosted.org/packages/ac/a4/7d4c8aefb45f6c8d7d527d84559a3a7e394b9fd1d424a2b5bcaf75fa68e7/orjson-3.11.3-cp39-cp39-win32.whl", hash = "sha256:22724d80ee5a815a44fc76274bb7ba2e7464f5564aacb6ecddaa9970a83e3225", size = 136184, upload-time = "2025-08-26T17:46:39.542Z" },
{ url = "https://files.pythonhosted.org/packages/9a/1f/1d6a24d22001e96c0afcf1806b6eabee1109aebd2ef20ec6698f6a6012d7/orjson-3.11.3-cp39-cp39-win_amd64.whl", hash = "sha256:215c595c792a87d4407cb72dd5e0f6ee8e694ceeb7f9102b533c5a9bf2a916bb", size = 131373, upload-time = "2025-08-26T17:46:41.227Z" },
] ]
[[package]] [[package]]
name = "ormsgpack" name = "ormsgpack"
version = "1.12.0" version = "1.10.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/6c/67/d5ef41c3b4a94400be801984ef7c7fc9623e1a82b643e74eeec367e7462b/ormsgpack-1.12.0.tar.gz", hash = "sha256:94be818fdbb0285945839b88763b269987787cb2f7ef280cad5d6ec815b7e608", size = 49959, upload-time = "2025-11-04T18:30:10.083Z" } sdist = { url = "https://files.pythonhosted.org/packages/92/36/44eed5ef8ce93cded76a576780bab16425ce7876f10d3e2e6265e46c21ea/ormsgpack-1.10.0.tar.gz", hash = "sha256:7f7a27efd67ef22d7182ec3b7fa7e9d147c3ad9be2a24656b23c989077e08b16", size = 58629, upload-time = "2025-05-24T19:07:53.944Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/4d/0c/8f45fcd22c95190b05d4fba71375d8f783a9e3b0b6aaf476812b693e3868/ormsgpack-1.12.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e08904c232358b94a682ccfbb680bc47d3fd5c424bb7dccb65974dd20c95e8e1", size = 369156, upload-time = "2025-11-04T18:29:17.629Z" }, { url = "https://files.pythonhosted.org/packages/fc/74/c2dd5daf069e3798d09d5746000f9b210de04df83834e5cb47f0ace51892/ormsgpack-1.10.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8a52c7ce7659459f3dc8dec9fd6a6c76f855a0a7e2b61f26090982ac10b95216", size = 376280, upload-time = "2025-05-24T19:06:51.3Z" },
{ url = "https://files.pythonhosted.org/packages/d2/f8/c7adc093d4ceb05e38786906815f868210f808326c27f8124b4d9466a26b/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9ed7a4b0037d69c8ba7e670e03ee65ae8d5c5114a409e73c5770d7fb5e4b895", size = 195743, upload-time = "2025-11-04T18:29:18.964Z" }, { url = "https://files.pythonhosted.org/packages/78/7b/30ff4bffb709e8a242005a8c4d65714fd96308ad640d31cff1b85c0d8cc4/ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:060f67fe927582f4f63a1260726d019204b72f460cf20930e6c925a1d129f373", size = 204335, upload-time = "2025-05-24T19:06:53.442Z" },
{ url = "https://files.pythonhosted.org/packages/fe/b8/bf002648fa6c150ed6157837b00303edafb35f65c352429463f83214de18/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:db2928525b684f3f2af0367aef7ae8d20cde37fc5349c700017129d493a755aa", size = 206472, upload-time = "2025-11-04T18:29:19.951Z" }, { url = "https://files.pythonhosted.org/packages/8f/3f/c95b7d142819f801a0acdbd04280e8132e43b6e5a8920173e8eb92ea0e6a/ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7058ef6092f995561bf9f71d6c9a4da867b6cc69d2e94cb80184f579a3ceed5", size = 215373, upload-time = "2025-05-24T19:06:55.153Z" },
{ url = "https://files.pythonhosted.org/packages/23/d6/1f445947c95a931bb189b7864a3f9dcbeebe7dcbc1b3c7387427b3779228/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45f911d9c5b23d11e49ff03fc8f9566745a2b1a7d9033733a1c0a2fa9301cd60", size = 207959, upload-time = "2025-11-04T18:29:21.282Z" }, { url = "https://files.pythonhosted.org/packages/ef/1a/e30f4bcf386db2015d1686d1da6110c95110294d8ea04f86091dd5eb3361/ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6f3509c1b0e51b15552d314b1d409321718122e90653122ce4b997f01453a", size = 216469, upload-time = "2025-05-24T19:06:56.555Z" },
{ url = "https://files.pythonhosted.org/packages/5c/9c/dd8ccd7553a5c1d0b4b69a0541611983a2f9bc2e8c5708a4bfffc0100468/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:98c54ae6fd682b2aceb264505af9b2255f3df9d84e6e4369bc44d2110f1f311d", size = 377659, upload-time = "2025-11-04T18:29:22.561Z" }, { url = "https://files.pythonhosted.org/packages/96/fc/7e44aeade22b91883586f45b7278c118fd210834c069774891447f444fc9/ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:51c1edafd5c72b863b1f875ec31c529f09c872a5ff6fe473b9dfaf188ccc3227", size = 384590, upload-time = "2025-05-24T19:06:58.286Z" },
{ url = "https://files.pythonhosted.org/packages/3d/08/3282d8f6330e742d4cdbcfbe2c100b403ae5526ae82a1c1b6a11b7967e37/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:857ab987c3502de08258cc4baf0e87267cb2c80931601084e13df3c355b1ab9d", size = 471391, upload-time = "2025-11-04T18:29:23.663Z" }, { url = "https://files.pythonhosted.org/packages/ec/78/f92c24e8446697caa83c122f10b6cf5e155eddf81ce63905c8223a260482/ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c780b44107a547a9e9327270f802fa4d6b0f6667c9c03c3338c0ce812259a0f7", size = 478891, upload-time = "2025-05-24T19:07:00.126Z" },
{ url = "https://files.pythonhosted.org/packages/18/d4/94a2fbfd4837754bda7a099b6a23b9d40aba9e76e1af8b8fb8133612eb54/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27579d45dc502ee736238e1024559cb0a01aa72a3b68827448b8edf6a2dcdc9c", size = 381501, upload-time = "2025-11-04T18:29:24.771Z" }, { url = "https://files.pythonhosted.org/packages/5a/75/87449690253c64bea2b663c7c8f2dbc9ad39d73d0b38db74bdb0f3947b16/ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:137aab0d5cdb6df702da950a80405eb2b7038509585e32b4e16289604ac7cb84", size = 390121, upload-time = "2025-05-24T19:07:01.777Z" },
{ url = "https://files.pythonhosted.org/packages/d8/c6/1a9fa122cb5deb10b067bbaa43165b12291a914cc0ce364988ff17bbf405/ormsgpack-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c78379d054760875540cf2e81f28da1bb78d09fda3eabdbeb6c53b3e297158cb", size = 112715, upload-time = "2025-11-04T18:29:26.016Z" }, { url = "https://files.pythonhosted.org/packages/69/cc/c83257faf3a5169ec29dd87121317a25711da9412ee8c1e82f2e1a00c0be/ormsgpack-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:3e666cb63030538fa5cd74b1e40cb55b6fdb6e2981f024997a288bf138ebad07", size = 121196, upload-time = "2025-05-24T19:07:03.47Z" },
{ url = "https://files.pythonhosted.org/packages/1a/ba/3cae83cf36420c1c8dd294f16c852c03313aafe2439a165c4c6ac611b1d0/ormsgpack-1.12.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c40d86d77391b18dd34de5295e3de2b8ad818bcab9c9def4121c8ec5c9714ae4", size = 369159, upload-time = "2025-11-04T18:29:27.057Z" }, { url = "https://files.pythonhosted.org/packages/30/27/7da748bc0d7d567950a378dee5a32477ed5d15462ab186918b5f25cac1ad/ormsgpack-1.10.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4bb7df307e17b36cbf7959cd642c47a7f2046ae19408c564e437f0ec323a7775", size = 376275, upload-time = "2025-05-24T19:07:05.128Z" },
{ url = "https://files.pythonhosted.org/packages/97/d4/5e176309e01a8b9098d80201aac1eb7db9336c3b5b4fa6254a2bbb0d0fa0/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:777b7fab364dc0f200bb382a98a385c8222ffa6a2333d627d763797326202c86", size = 195744, upload-time = "2025-11-04T18:29:28.069Z" }, { url = "https://files.pythonhosted.org/packages/7b/65/c082cc8c74a914dbd05af0341c761c73c3d9960b7432bbf9b8e1e20811af/ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8817ae439c671779e1127ee62f0ac67afdeaeeacb5f0db45703168aa74a2e4af", size = 204335, upload-time = "2025-05-24T19:07:06.423Z" },
{ url = "https://files.pythonhosted.org/packages/4f/83/6d80c8c5571639c000a39f38f77752dfaf9d9e552d775331e8d280f66a4e/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b5089ad9dd5b3d3013b245a55e4abaea2f8ad70f4a78e1b002127b02340004", size = 206474, upload-time = "2025-11-04T18:29:29.034Z" }, { url = "https://files.pythonhosted.org/packages/46/62/17ef7e5d9766c79355b9c594cc9328c204f1677bc35da0595cc4e46449f0/ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f345f81e852035d80232e64374d3a104139d60f8f43c6c5eade35c4bac5590e", size = 215372, upload-time = "2025-05-24T19:07:08.149Z" },
{ url = "https://files.pythonhosted.org/packages/5e/e6/940311e48dc0cfc3e212bd7007a21ed0825158638057687d804f2c5c2cca/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:deaf0c87cace7bc08fbf68c5cc66605b593df6427e9f4de235b2da358787e008", size = 207959, upload-time = "2025-11-04T18:29:30.315Z" }, { url = "https://files.pythonhosted.org/packages/4e/92/7c91e8115fc37e88d1a35e13200fda3054ff5d2e5adf017345e58cea4834/ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21de648a1c7ef692bdd287fb08f047bd5371d7462504c0a7ae1553c39fee35e3", size = 216470, upload-time = "2025-05-24T19:07:09.903Z" },
{ url = "https://files.pythonhosted.org/packages/1a/e3/fbe94b0a311815343b86a95a0627e4901b11ff6fd522679ca29a2a88c99b/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f62d476fe28bc5675d9aff30341bfa9f41d7de332c5b63fbbe9aaf6bb7ec74d4", size = 377666, upload-time = "2025-11-04T18:29:31.38Z" }, { url = "https://files.pythonhosted.org/packages/2c/86/ce053c52e2517b90e390792d83e926a7a523c1bce5cc63d0a7cd05ce6cf6/ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3a7d844ae9cbf2112c16086dd931b2acefce14cefd163c57db161170c2bfa22b", size = 384591, upload-time = "2025-05-24T19:07:11.24Z" },
{ url = "https://files.pythonhosted.org/packages/a3/3b/229cfa28076798ffb619aaa854b842de3f2ed5ea4e6509bf34d14c038c4d/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ded7810095b887e28434f32f5a345d354e88cf851bab3c5435aeb86a718618d2", size = 471394, upload-time = "2025-11-04T18:29:32.521Z" }, { url = "https://files.pythonhosted.org/packages/07/e8/2ad59f2ab222c6029e500bc966bfd2fe5cb099f8ab6b7ebeb50ddb1a6fe5/ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e4d80585403d86d7f800cf3d0aafac1189b403941e84e90dd5102bb2b92bf9d5", size = 478892, upload-time = "2025-05-24T19:07:13.147Z" },
{ url = "https://files.pythonhosted.org/packages/6b/bd/4eae4ab35586e4175c07acb5f98aec83aa9d8987f71ea0443aa900191bdf/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f72a1dea0c4ae7c4101dcfbe8133f274a9d769d0b87fe5188db4fab07ffabaee", size = 381506, upload-time = "2025-11-04T18:29:33.533Z" }, { url = "https://files.pythonhosted.org/packages/f4/73/f55e4b47b7b18fd8e7789680051bf830f1e39c03f1d9ed993cd0c3e97215/ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:da1de515a87e339e78a3ccf60e39f5fb740edac3e9e82d3c3d209e217a13ac08", size = 390122, upload-time = "2025-05-24T19:07:14.557Z" },
{ url = "https://files.pythonhosted.org/packages/dd/51/f9d56d6d015cbfa1ce9a4358ca30a41744644f0cf606e060d7203efe5af8/ormsgpack-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:8f479bfef847255d7d0b12c7a198f6a21490155da2da3062e082ba370893d4a1", size = 112707, upload-time = "2025-11-04T18:29:34.898Z" }, { url = "https://files.pythonhosted.org/packages/f7/87/073251cdb93d4c6241748568b3ad1b2a76281fb2002eed16a3a4043d61cf/ormsgpack-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:57c4601812684024132cbb32c17a7d4bb46ffc7daf2fddf5b697391c2c4f142a", size = 121197, upload-time = "2025-05-24T19:07:15.981Z" },
{ url = "https://files.pythonhosted.org/packages/f4/07/bb189ef7072979f2f96e8716e952172efdce9c54930aa0814bec73aee19b/ormsgpack-1.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:3583ca410e4502144b2594170542e4bbef7b15643fd1208703ae820f11029036", size = 106533, upload-time = "2025-11-04T18:29:36.112Z" }, { url = "https://files.pythonhosted.org/packages/99/95/f3ab1a7638f6aa9362e87916bb96087fbbc5909db57e19f12ad127560e1e/ormsgpack-1.10.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4e159d50cd4064d7540e2bc6a0ab66eab70b0cc40c618b485324ee17037527c0", size = 376806, upload-time = "2025-05-24T19:07:17.221Z" },
{ url = "https://files.pythonhosted.org/packages/a2/f2/c1036b2775fcc0cfa5fd618c53bcd3b862ee07298fb627f03af4c7982f84/ormsgpack-1.12.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e0c1e08b64d99076fee155276097489b82cc56e8d5951c03c721a65a32f44494", size = 369538, upload-time = "2025-11-04T18:29:37.125Z" }, { url = "https://files.pythonhosted.org/packages/6c/2b/42f559f13c0b0f647b09d749682851d47c1a7e48308c43612ae6833499c8/ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb47c85f3a866e29279d801115b554af0fefc409e2ed8aa90aabfa77efe5cc6", size = 204433, upload-time = "2025-05-24T19:07:18.569Z" },
{ url = "https://files.pythonhosted.org/packages/d9/ca/526c4ae02f3cb34621af91bf8282a10d666757c2e0c6ff391ff5d403d607/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd43bcb299131690b8e0677af172020b2ada8e625169034b42ac0c13adf84aa", size = 195872, upload-time = "2025-11-04T18:29:38.34Z" }, { url = "https://files.pythonhosted.org/packages/45/42/1ca0cb4d8c80340a89a4af9e6d8951fb8ba0d076a899d2084eadf536f677/ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c28249574934534c9bd5dce5485c52f21bcea0ee44d13ece3def6e3d2c3798b5", size = 215547, upload-time = "2025-05-24T19:07:20.245Z" },
{ url = "https://files.pythonhosted.org/packages/7f/0f/83bb7968e9715f6a85be53d041b1e6324a05428f56b8b980dac866886871/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0149d595341e22ead340bf281b2995c4cc7dc8d522a6b5f575fe17aa407604", size = 206469, upload-time = "2025-11-04T18:29:39.749Z" }, { url = "https://files.pythonhosted.org/packages/0a/38/184a570d7c44c0260bc576d1daaac35b2bfd465a50a08189518505748b9a/ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1957dcadbb16e6a981cd3f9caef9faf4c2df1125e2a1b702ee8236a55837ce07", size = 216746, upload-time = "2025-05-24T19:07:21.83Z" },
{ url = "https://files.pythonhosted.org/packages/02/e3/9e93ca1065f2d4af035804a842b1ff3025bab580c7918239bb225cd1fee2/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f19a1b27d169deb553c80fd10b589fc2be1fc14cee779fae79fcaf40db04de2b", size = 208273, upload-time = "2025-11-04T18:29:40.769Z" }, { url = "https://files.pythonhosted.org/packages/69/2f/1aaffd08f6b7fdc2a57336a80bdfb8df24e6a65ada5aa769afecfcbc6cc6/ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3b29412558c740bf6bac156727aa85ac67f9952cd6f071318f29ee72e1a76044", size = 384783, upload-time = "2025-05-24T19:07:23.674Z" },
{ url = "https://files.pythonhosted.org/packages/b3/d8/6d6ef901b3a8b8f3ab8836b135a56eb7f66c559003e251d9530bedb12627/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f28896942d655064940dfe06118b7ce1e3468d051483148bf02c99ec157483a", size = 377839, upload-time = "2025-11-04T18:29:42.092Z" }, { url = "https://files.pythonhosted.org/packages/a9/63/3e53d6f43bb35e00c98f2b8ab2006d5138089ad254bc405614fbf0213502/ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6933f350c2041ec189fe739f0ba7d6117c8772f5bc81f45b97697a84d03020dd", size = 479076, upload-time = "2025-05-24T19:07:25.047Z" },
{ url = "https://files.pythonhosted.org/packages/4c/72/fcb704bfa4c2c3a37b647d597cc45a13cffc9d50baac635a9ad620731d29/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9396efcfa48b4abbc06e44c5dbc3c4574a8381a80cb4cd01eea15d28b38c554e", size = 471446, upload-time = "2025-11-04T18:29:43.133Z" }, { url = "https://files.pythonhosted.org/packages/b8/19/fa1121b03b61402bb4d04e35d164e2320ef73dfb001b57748110319dd014/ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a86de06d368fcc2e58b79dece527dc8ca831e0e8b9cec5d6e633d2777ec93d0", size = 390447, upload-time = "2025-05-24T19:07:26.568Z" },
{ url = "https://files.pythonhosted.org/packages/84/f8/402e4e3eb997c2ee534c99bec4b5bb359c2a1f9edadf043e254a71e11378/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:96586ed537a5fb386a162c4f9f7d8e6f76e07b38a990d50c73f11131e00ff040", size = 381783, upload-time = "2025-11-04T18:29:44.466Z" }, { url = "https://files.pythonhosted.org/packages/b0/0d/73143ecb94ac4a5dcba223402139240a75dee0cc6ba8a543788a5646407a/ormsgpack-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:35fa9f81e5b9a0dab42e09a73f7339ecffdb978d6dbf9deb2ecf1e9fc7808722", size = 121401, upload-time = "2025-05-24T19:07:28.308Z" },
{ url = "https://files.pythonhosted.org/packages/f0/8d/5897b700360bc00911b70ae5ef1134ee7abf5baa81a92a4be005917d3dfd/ormsgpack-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e70387112fb3870e4844de090014212cdcf1342f5022047aecca01ec7de05d7a", size = 112943, upload-time = "2025-11-04T18:29:45.468Z" }, { url = "https://files.pythonhosted.org/packages/61/f8/ec5f4e03268d0097545efaab2893aa63f171cf2959cb0ea678a5690e16a1/ormsgpack-1.10.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d816d45175a878993b7372bd5408e0f3ec5a40f48e2d5b9d8f1cc5d31b61f1f", size = 376806, upload-time = "2025-05-24T19:07:29.555Z" },
{ url = "https://files.pythonhosted.org/packages/5b/44/1e73649f79bb96d6cf9e5bcbac68b6216d238bba80af351c4c0cbcf7ee15/ormsgpack-1.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:d71290a23de5d4829610c42665d816c661ecad8979883f3f06b2e3ab9639962e", size = 106688, upload-time = "2025-11-04T18:29:46.411Z" }, { url = "https://files.pythonhosted.org/packages/c1/19/b3c53284aad1e90d4d7ed8c881a373d218e16675b8b38e3569d5b40cc9b8/ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90345ccb058de0f35262893751c603b6376b05f02be2b6f6b7e05d9dd6d5643", size = 204433, upload-time = "2025-05-24T19:07:30.977Z" },
{ url = "https://files.pythonhosted.org/packages/2e/e8/35f11ce9313111488b26b3035e4cbe55caa27909c0b6c8b5b5cd59f9661e/ormsgpack-1.12.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:766f2f3b512d85cd375b26a8b1329b99843560b50b93d3880718e634ad4a5de5", size = 369574, upload-time = "2025-11-04T18:29:47.431Z" }, { url = "https://files.pythonhosted.org/packages/09/0b/845c258f59df974a20a536c06cace593698491defdd3d026a8a5f9b6e745/ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:144b5e88f1999433e54db9d637bae6fe21e935888be4e3ac3daecd8260bd454e", size = 215549, upload-time = "2025-05-24T19:07:32.345Z" },
{ url = "https://files.pythonhosted.org/packages/61/b0/77461587f412d4e598d3687bafe23455ed0f26269f44be20252eddaa624e/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84b285b1f3f185aad7da45641b873b30acfd13084cf829cf668c4c6480a81583", size = 195893, upload-time = "2025-11-04T18:29:48.735Z" }, { url = "https://files.pythonhosted.org/packages/61/56/57fce8fb34ca6c9543c026ebebf08344c64dbb7b6643d6ddd5355d37e724/ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2190b352509d012915921cca76267db136cd026ddee42f1b0d9624613cc7058c", size = 216747, upload-time = "2025-05-24T19:07:34.075Z" },
{ url = "https://files.pythonhosted.org/packages/c6/67/e197ceb04c3b550589e5407fc9fdae10f4e2e2eba5fdac921a269e02e974/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e23604fc79fe110292cb365f4c8232e64e63a34f470538be320feae3921f271b", size = 206503, upload-time = "2025-11-04T18:29:49.99Z" }, { url = "https://files.pythonhosted.org/packages/b8/3f/655b5f6a2475c8d209f5348cfbaaf73ce26237b92d79ef2ad439407dd0fa/ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:86fd9c1737eaba43d3bb2730add9c9e8b5fbed85282433705dd1b1e88ea7e6fb", size = 384785, upload-time = "2025-05-24T19:07:35.83Z" },
{ url = "https://files.pythonhosted.org/packages/0b/b1/7fa8ba82a25cef678983c7976f85edeef5014f5c26495f338258e6a3cf1c/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc32b156c113a0fae2975051417d8d9a7a5247c34b2d7239410c46b75ce9348a", size = 208257, upload-time = "2025-11-04T18:29:51.007Z" }, { url = "https://files.pythonhosted.org/packages/4b/94/687a0ad8afd17e4bce1892145d6a1111e58987ddb176810d02a1f3f18686/ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:33afe143a7b61ad21bb60109a86bb4e87fec70ef35db76b89c65b17e32da7935", size = 479076, upload-time = "2025-05-24T19:07:37.533Z" },
{ url = "https://files.pythonhosted.org/packages/ce/b1/759e999390000d2589e6d0797f7265e6ec28378547075d28d3736248ab63/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:94ac500dd10c20fa8b8a23bc55606250bfe711bf9716828d9f3d44dfd1f25668", size = 377852, upload-time = "2025-11-04T18:29:52.103Z" }, { url = "https://files.pythonhosted.org/packages/c8/34/68925232e81e0e062a2f0ac678f62aa3b6f7009d6a759e19324dbbaebae7/ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f23d45080846a7b90feabec0d330a9cc1863dc956728412e4f7986c80ab3a668", size = 390446, upload-time = "2025-05-24T19:07:39.469Z" },
{ url = "https://files.pythonhosted.org/packages/51/e7/0af737c94272494d9d84a3c29cc42c973ef7fd2342917020906596db863c/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c5201ff7ec24f721f813a182885a17064cffdbe46b2412685a52e6374a872c8f", size = 471456, upload-time = "2025-11-04T18:29:53.336Z" }, { url = "https://files.pythonhosted.org/packages/12/ad/f4e1a36a6d1714afb7ffb74b3ababdcb96529cf4e7a216f9f7c8eda837b6/ormsgpack-1.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:534d18acb805c75e5fba09598bf40abe1851c853247e61dda0c01f772234da69", size = 121399, upload-time = "2025-05-24T19:07:40.854Z" },
{ url = "https://files.pythonhosted.org/packages/f4/ba/c81f0aa4f19fbf457213395945b672e6fde3ce777e3587456e7f0fca2147/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a9740bb3839c9368aacae1cbcfc474ee6976458f41cc135372b7255d5206c953", size = 381813, upload-time = "2025-11-04T18:29:54.394Z" }, { url = "https://files.pythonhosted.org/packages/75/8f/bb80469db9d5b10708cba6997463d140486ca7053a5d18f99b5739cfecf7/ormsgpack-1.10.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:efdb25cf6d54085f7ae557268d59fd2d956f1a09a340856e282d2960fe929f32", size = 376272, upload-time = "2025-05-24T19:07:42.16Z" },
{ url = "https://files.pythonhosted.org/packages/ce/15/429c72d64323503fd42cc4ca8398930ded8aa8b3470df8a86b3bbae7a35c/ormsgpack-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ed37f29772432048b58174e920a1d4c4cde0404a5d448d3d8bbcc95d86a6918", size = 112949, upload-time = "2025-11-04T18:29:55.371Z" }, { url = "https://files.pythonhosted.org/packages/08/9c/48f714ed3d5a153f25e3b490496e6ba214aee265a82be1b61e39019ea146/ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddfcb30d4b1be2439836249d675f297947f4fb8efcd3eeb6fd83021d773cadc4", size = 204314, upload-time = "2025-05-24T19:07:43.444Z" },
{ url = "https://files.pythonhosted.org/packages/55/b9/e72c451a40f8c57bfc229e0b8e536ecea7203c8f0a839676df2ffb605c62/ormsgpack-1.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:b03994bbec5d6d42e03d6604e327863f885bde67aa61e06107ce1fa5bdd3e71d", size = 106689, upload-time = "2025-11-04T18:29:56.262Z" }, { url = "https://files.pythonhosted.org/packages/27/42/7f9edf6e5511120b5304c76c5d3a8b4719ff927555a6dba41b6f9d041b30/ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee0944b6ccfd880beb1ca29f9442a774683c366f17f4207f8b81c5e24cadb453", size = 215386, upload-time = "2025-05-24T19:07:45.232Z" },
{ url = "https://files.pythonhosted.org/packages/13/16/13eab1a75da531b359105fdee90dda0b6bd1ca0a09880250cf91d8bdfdea/ormsgpack-1.12.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0f3981ba3cba80656012090337e548e597799e14b41e3d0b595ab5ab05a23d7f", size = 369620, upload-time = "2025-11-04T18:29:57.255Z" }, { url = "https://files.pythonhosted.org/packages/40/87/41e14485857fbe4ed5a530677fe60dd6910a254825c0b1cb5b04baaa4be0/ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35cdff6a0d3ba04e40a751129763c3b9b57a602c02944138e4b760ec99ae80a1", size = 216466, upload-time = "2025-05-24T19:07:46.548Z" },
{ url = "https://files.pythonhosted.org/packages/a0/c1/cbcc38b7af4ce58d8893e56d3595c0c8dcd117093bf048f889cf351bdba0/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:901f6f55184d6776dbd5183cbce14caf05bf7f467eef52faf9b094686980bf71", size = 195925, upload-time = "2025-11-04T18:29:58.34Z" }, { url = "https://files.pythonhosted.org/packages/cb/68/769fa1c721d8aa6799c0ce98b1711ae57de3e6379b554ebf9a11be4c62ff/ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:599ccdabc19c618ef5de6e6f2e7f5d48c1f531a625fa6772313b8515bc710681", size = 384600, upload-time = "2025-05-24T19:07:47.945Z" },
{ url = "https://files.pythonhosted.org/packages/5c/59/4fa4dc0681490e12b75333440a1c0fd9741b0ebff272b1db4a29d35c2021/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e13b15412571422b711b40f45e3fe6d993ea3314b5e97d1a853fe99226c5effc", size = 206594, upload-time = "2025-11-04T18:29:59.329Z" }, { url = "https://files.pythonhosted.org/packages/4e/f9/b57fd387fe16753783a3cea0ed2471c727bbed4356d8a08e3f0340251870/ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:bf46f57da9364bd5eefd92365c1b78797f56c6f780581eecd60cd7b367f9b4d3", size = 478888, upload-time = "2025-05-24T19:07:49.801Z" },
{ url = "https://files.pythonhosted.org/packages/39/67/249770896bc32bb91b22c30256961f935d0915cbcf6e289a7fc961d9b14c/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91fa8a452553a62e5fb3fbab471e7faf7b3bec3c87a2f355ebf3d7aab290fe4f", size = 208307, upload-time = "2025-11-04T18:30:00.377Z" }, { url = "https://files.pythonhosted.org/packages/3e/0f/464cdfa7f9ee817c2d94485880b6c3c4b9f22df9fcbf21c303bbfebcb3ed/ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b796f64fdf823dedb1e35436a4a6f889cf78b1aa42d3097c66e5adfd8c3bd72d", size = 390118, upload-time = "2025-05-24T19:07:51.193Z" },
{ url = "https://files.pythonhosted.org/packages/07/0a/e041a248cd72f2f4c07e155913e0a3ede4c86cf21a40ae6cd79f135f2847/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74ec101f69624695eec4ce7c953192d97748254abe78fb01b591f06d529e1952", size = 377844, upload-time = "2025-11-04T18:30:01.389Z" }, { url = "https://files.pythonhosted.org/packages/ad/03/b9146dff5458def4c0a2b1e35c1c24e4d5e8083899aa0718b6eccba39317/ormsgpack-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:106253ac9dc08520951e556b3c270220fcb8b4fef0d30b71eedac4befa4de749", size = 121199, upload-time = "2025-05-24T19:07:52.639Z" },
{ url = "https://files.pythonhosted.org/packages/d8/71/6f7773e4ffda73a358ce4bba69b3e8bee9d40a7a06315e4c1cd7a3ea9d02/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9bbf7896580848326c1f9bd7531f264e561f98db7e08e15aa75963d83832c717", size = 471572, upload-time = "2025-11-04T18:30:02.486Z" },
{ url = "https://files.pythonhosted.org/packages/65/29/af6769a4289c07acc71e7bda1d64fb31800563147d73142686e185e82348/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7567917da613b8f8d591c1674e411fd3404bea41ef2b9a0e0a1e049c0f9406d7", size = 381842, upload-time = "2025-11-04T18:30:03.799Z" },
{ url = "https://files.pythonhosted.org/packages/0b/dd/0a86195ee7a1a96c088aefc8504385e881cf56f4563ed81bafe21cbf1fb0/ormsgpack-1.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e418256c5d8622b8bc92861936f7c6a0131355e7bcad88a42102ae8227f8a1c", size = 113008, upload-time = "2025-11-04T18:30:04.777Z" },
{ url = "https://files.pythonhosted.org/packages/4c/57/fafc79e32f3087f6f26f509d80b8167516326bfea38d30502627c01617e0/ormsgpack-1.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:433ace29aa02713554f714c62a4e4dcad0c9e32674ba4f66742c91a4c3b1b969", size = 106648, upload-time = "2025-11-04T18:30:05.708Z" },
{ url = "https://files.pythonhosted.org/packages/b3/cf/5d58d9b132128d2fe5d586355dde76af386554abef00d608f66b913bff1f/ormsgpack-1.12.0-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e57164be4ca34b64e210ec515059193280ac84df4d6f31a6fcbfb2fc8436de55", size = 369803, upload-time = "2025-11-04T18:30:06.728Z" },
{ url = "https://files.pythonhosted.org/packages/67/42/968a2da361eaff2e4cbb17c82c7599787babf16684110ad70409646cc1e4/ormsgpack-1.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:904f96289deaa92fc6440b122edc27c5bdc28234edd63717f6d853d88c823a83", size = 195991, upload-time = "2025-11-04T18:30:07.713Z" },
{ url = "https://files.pythonhosted.org/packages/03/f0/9696c6c6cf8ad35170f0be8d0ef3523cc258083535f6c8071cb8235ebb8b/ormsgpack-1.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b291d086e524a1062d57d1b7b5a8bcaaf29caebf0212fec12fd86240bd33633", size = 208316, upload-time = "2025-11-04T18:30:08.663Z" },
] ]
[[package]] [[package]]
@@ -653,6 +632,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/6b/8c/9446e3a84187220a98657ef778518f9b44eba55b1f6c3e8300d229ec9930/psycopg_binary-3.2.10-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:1f6982609b8ff8fcd67299b67cd5787da1876f3bb28fedd547262cfa8ddedf94", size = 3535121, upload-time = "2025-09-08T09:11:53.887Z" }, { url = "https://files.pythonhosted.org/packages/6b/8c/9446e3a84187220a98657ef778518f9b44eba55b1f6c3e8300d229ec9930/psycopg_binary-3.2.10-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:1f6982609b8ff8fcd67299b67cd5787da1876f3bb28fedd547262cfa8ddedf94", size = 3535121, upload-time = "2025-09-08T09:11:53.887Z" },
{ url = "https://files.pythonhosted.org/packages/b4/e1/f0382c956bfaa951a0dbd4d5a354acf093ef7e5219996958143dfd2bf37d/psycopg_binary-3.2.10-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bf30dcf6aaaa8d4779a20d2158bdf81cc8e84ce8eee595d748a7671c70c7b890", size = 3584235, upload-time = "2025-09-08T09:12:01.118Z" }, { url = "https://files.pythonhosted.org/packages/b4/e1/f0382c956bfaa951a0dbd4d5a354acf093ef7e5219996958143dfd2bf37d/psycopg_binary-3.2.10-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bf30dcf6aaaa8d4779a20d2158bdf81cc8e84ce8eee595d748a7671c70c7b890", size = 3584235, upload-time = "2025-09-08T09:12:01.118Z" },
{ url = "https://files.pythonhosted.org/packages/5a/dd/464bd739bacb3b745a1c93bc15f20f0b1e27f0a64ec693367794b398673b/psycopg_binary-3.2.10-cp314-cp314-win_amd64.whl", hash = "sha256:d5c6a66a76022af41970bf19f51bc6bf87bd10165783dd1d40484bfd87d6b382", size = 2973554, upload-time = "2025-09-08T09:12:05.884Z" }, { url = "https://files.pythonhosted.org/packages/5a/dd/464bd739bacb3b745a1c93bc15f20f0b1e27f0a64ec693367794b398673b/psycopg_binary-3.2.10-cp314-cp314-win_amd64.whl", hash = "sha256:d5c6a66a76022af41970bf19f51bc6bf87bd10165783dd1d40484bfd87d6b382", size = 2973554, upload-time = "2025-09-08T09:12:05.884Z" },
{ url = "https://files.pythonhosted.org/packages/2b/c0/f9fefea225c49b9c4528ce17d93f91d4687a7e619f4cd19818a0481e4066/psycopg_binary-3.2.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0738320a8d405f98743227ff70ed8fac9670870289435f4861dc640cef4a61d3", size = 3996466, upload-time = "2025-09-08T09:12:50.418Z" },
{ url = "https://files.pythonhosted.org/packages/fa/a9/505a7558ed4f0aaa1373f307a7f21cba480ef99063107e8809e0e45c73d1/psycopg_binary-3.2.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:89440355d1b163b11dc661ae64a5667578aab1b80bbf71ced90693d88e9863e1", size = 4067930, upload-time = "2025-09-08T09:12:54.225Z" },
{ url = "https://files.pythonhosted.org/packages/36/d1/b08bba8a017a24dfdd3844d5e1b080bba30fddb6b8d71316387772bcbdd3/psycopg_binary-3.2.10-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3234605839e7d7584bd0a20716395eba34d368a5099dafe7896c943facac98fc", size = 4627622, upload-time = "2025-09-08T09:13:05.429Z" },
{ url = "https://files.pythonhosted.org/packages/9e/27/e4cf67d8e9f9e045ef445832b1dcc6ed6173184d80740e40a7f35c57fa27/psycopg_binary-3.2.10-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:725843fd444075cc6c9989f5b25ca83ac68d8d70b58e1f476fbb4096975e43cc", size = 4722794, upload-time = "2025-09-08T09:13:11.155Z" },
{ url = "https://files.pythonhosted.org/packages/aa/3b/31f7629360d2c36c0bba8897dafdc7482d71170f601bc79358fb3f099f88/psycopg_binary-3.2.10-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:447afc326cbc95ed67c0cd27606c0f81fa933b830061e096dbd37e08501cb3de", size = 4407119, upload-time = "2025-09-08T09:13:16.477Z" },
{ url = "https://files.pythonhosted.org/packages/03/84/9610a633b33d685269318a92428619097d1a9fc0832ee6c4fd3d6ab75fb8/psycopg_binary-3.2.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5334a61a00ccb722f0b28789e265c7a273cfd10d5a1ed6bf062686fbb71e7032", size = 3880897, upload-time = "2025-09-08T09:13:20.716Z" },
{ url = "https://files.pythonhosted.org/packages/af/0d/af7ba9bcb035454d19f88992a5cdd03313500a78f55d47f474b561ecf996/psycopg_binary-3.2.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:183a59cbdcd7e156669577fd73a9e917b1ee664e620f1e31ae138d24c7714693", size = 3563882, upload-time = "2025-09-08T09:13:25.919Z" },
{ url = "https://files.pythonhosted.org/packages/d2/b2/b6ba55c253208f03271b2c3d890fe5cbb8ef8f54551e6579a76f3978188f/psycopg_binary-3.2.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8fa2efaf5e2f8c289a185c91c80a624a8f97aa17fbedcbc68f373d089b332afd", size = 3604543, upload-time = "2025-09-08T09:13:31.075Z" },
{ url = "https://files.pythonhosted.org/packages/b7/3d/90ac8893003ed16eb2709d755bd8c53eb6330fc7f34774df166b2e00eed4/psycopg_binary-3.2.10-cp39-cp39-win_amd64.whl", hash = "sha256:6220d6efd6e2df7b67d70ed60d653106cd3b70c5cb8cbe4e9f0a142a5db14015", size = 2888394, upload-time = "2025-09-08T09:13:35.73Z" },
] ]
[[package]] [[package]]
@@ -669,7 +657,7 @@ wheels = [
[[package]] [[package]]
name = "pydantic" name = "pydantic"
version = "2.12.2" version = "2.11.9"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "annotated-types" }, { name = "annotated-types" },
@@ -677,123 +665,118 @@ dependencies = [
{ name = "typing-extensions" }, { name = "typing-extensions" },
{ name = "typing-inspection" }, { name = "typing-inspection" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/8d/35/d319ed522433215526689bad428a94058b6dd12190ce7ddd78618ac14b28/pydantic-2.12.2.tar.gz", hash = "sha256:7b8fa15b831a4bbde9d5b84028641ac3080a4ca2cbd4a621a661687e741624fd", size = 816358, upload-time = "2025-10-14T15:02:21.842Z" } sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/6c/98/468cb649f208a6f1279448e6e5247b37ae79cf5e4041186f1e2ef3d16345/pydantic-2.12.2-py3-none-any.whl", hash = "sha256:25ff718ee909acd82f1ff9b1a4acfd781bb23ab3739adaa7144f19a6a4e231ae", size = 460628, upload-time = "2025-10-14T15:02:19.623Z" }, { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" },
] ]
[[package]] [[package]]
name = "pydantic-core" name = "pydantic-core"
version = "2.41.4" version = "2.33.2"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "typing-extensions" }, { name = "typing-extensions" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/df/18/d0944e8eaaa3efd0a91b0f1fc537d3be55ad35091b6a87638211ba691964/pydantic_core-2.41.4.tar.gz", hash = "sha256:70e47929a9d4a1905a67e4b687d5946026390568a8e952b92824118063cee4d5", size = 457557, upload-time = "2025-10-14T10:23:47.909Z" } sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/3d/9b8ca77b0f76fcdbf8bc6b72474e264283f461284ca84ac3fde570c6c49a/pydantic_core-2.41.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2442d9a4d38f3411f22eb9dd0912b7cbf4b7d5b6c92c4173b75d3e1ccd84e36e", size = 2111197, upload-time = "2025-10-14T10:19:43.303Z" }, { url = "https://files.pythonhosted.org/packages/e5/92/b31726561b5dae176c2d2c2dc43a9c5bfba5d32f96f8b4c0a600dd492447/pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8", size = 2028817, upload-time = "2025-04-23T18:30:43.919Z" },
{ url = "https://files.pythonhosted.org/packages/59/92/b7b0fe6ed4781642232755cb7e56a86e2041e1292f16d9ae410a0ccee5ac/pydantic_core-2.41.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:30a9876226dda131a741afeab2702e2d127209bde3c65a2b8133f428bc5d006b", size = 1917909, upload-time = "2025-10-14T10:19:45.194Z" }, { url = "https://files.pythonhosted.org/packages/a3/44/3f0b95fafdaca04a483c4e685fe437c6891001bf3ce8b2fded82b9ea3aa1/pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d", size = 1861357, upload-time = "2025-04-23T18:30:46.372Z" },
{ url = "https://files.pythonhosted.org/packages/52/8c/3eb872009274ffa4fb6a9585114e161aa1a0915af2896e2d441642929fe4/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d55bbac04711e2980645af68b97d445cdbcce70e5216de444a6c4b6943ebcccd", size = 1969905, upload-time = "2025-10-14T10:19:46.567Z" }, { url = "https://files.pythonhosted.org/packages/30/97/e8f13b55766234caae05372826e8e4b3b96e7b248be3157f53237682e43c/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d", size = 1898011, upload-time = "2025-04-23T18:30:47.591Z" },
{ url = "https://files.pythonhosted.org/packages/f4/21/35adf4a753bcfaea22d925214a0c5b880792e3244731b3f3e6fec0d124f7/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e1d778fb7849a42d0ee5927ab0f7453bf9f85eef8887a546ec87db5ddb178945", size = 2051938, upload-time = "2025-10-14T10:19:48.237Z" }, { url = "https://files.pythonhosted.org/packages/9b/a3/99c48cf7bafc991cc3ee66fd544c0aae8dc907b752f1dad2d79b1b5a471f/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572", size = 1982730, upload-time = "2025-04-23T18:30:49.328Z" },
{ url = "https://files.pythonhosted.org/packages/7d/d0/cdf7d126825e36d6e3f1eccf257da8954452934ede275a8f390eac775e89/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b65077a4693a98b90ec5ad8f203ad65802a1b9b6d4a7e48066925a7e1606706", size = 2250710, upload-time = "2025-10-14T10:19:49.619Z" }, { url = "https://files.pythonhosted.org/packages/de/8e/a5b882ec4307010a840fb8b58bd9bf65d1840c92eae7534c7441709bf54b/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02", size = 2136178, upload-time = "2025-04-23T18:30:50.907Z" },
{ url = "https://files.pythonhosted.org/packages/2e/1c/af1e6fd5ea596327308f9c8d1654e1285cc3d8de0d584a3c9d7705bf8a7c/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62637c769dee16eddb7686bf421be48dfc2fae93832c25e25bc7242e698361ba", size = 2367445, upload-time = "2025-10-14T10:19:51.269Z" }, { url = "https://files.pythonhosted.org/packages/e4/bb/71e35fc3ed05af6834e890edb75968e2802fe98778971ab5cba20a162315/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b", size = 2736462, upload-time = "2025-04-23T18:30:52.083Z" },
{ url = "https://files.pythonhosted.org/packages/d3/81/8cece29a6ef1b3a92f956ea6da6250d5b2d2e7e4d513dd3b4f0c7a83dfea/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfe3aa529c8f501babf6e502936b9e8d4698502b2cfab41e17a028d91b1ac7b", size = 2072875, upload-time = "2025-10-14T10:19:52.671Z" }, { url = "https://files.pythonhosted.org/packages/31/0d/c8f7593e6bc7066289bbc366f2235701dcbebcd1ff0ef8e64f6f239fb47d/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2", size = 2005652, upload-time = "2025-04-23T18:30:53.389Z" },
{ url = "https://files.pythonhosted.org/packages/e3/37/a6a579f5fc2cd4d5521284a0ab6a426cc6463a7b3897aeb95b12f1ba607b/pydantic_core-2.41.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca2322da745bf2eeb581fc9ea3bbb31147702163ccbcbf12a3bb630e4bf05e1d", size = 2191329, upload-time = "2025-10-14T10:19:54.214Z" }, { url = "https://files.pythonhosted.org/packages/d2/7a/996d8bd75f3eda405e3dd219ff5ff0a283cd8e34add39d8ef9157e722867/pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a", size = 2113306, upload-time = "2025-04-23T18:30:54.661Z" },
{ url = "https://files.pythonhosted.org/packages/ae/03/505020dc5c54ec75ecba9f41119fd1e48f9e41e4629942494c4a8734ded1/pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e8cd3577c796be7231dcf80badcf2e0835a46665eaafd8ace124d886bab4d700", size = 2151658, upload-time = "2025-10-14T10:19:55.843Z" }, { url = "https://files.pythonhosted.org/packages/ff/84/daf2a6fb2db40ffda6578a7e8c5a6e9c8affb251a05c233ae37098118788/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac", size = 2073720, upload-time = "2025-04-23T18:30:56.11Z" },
{ url = "https://files.pythonhosted.org/packages/cb/5d/2c0d09fb53aa03bbd2a214d89ebfa6304be7df9ed86ee3dc7770257f41ee/pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:1cae8851e174c83633f0833e90636832857297900133705ee158cf79d40f03e6", size = 2316777, upload-time = "2025-10-14T10:19:57.607Z" }, { url = "https://files.pythonhosted.org/packages/77/fb/2258da019f4825128445ae79456a5499c032b55849dbd5bed78c95ccf163/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a", size = 2244915, upload-time = "2025-04-23T18:30:57.501Z" },
{ url = "https://files.pythonhosted.org/packages/ea/4b/c2c9c8f5e1f9c864b57d08539d9d3db160e00491c9f5ee90e1bfd905e644/pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a26d950449aae348afe1ac8be5525a00ae4235309b729ad4d3399623125b43c9", size = 2320705, upload-time = "2025-10-14T10:19:59.016Z" }, { url = "https://files.pythonhosted.org/packages/d8/7a/925ff73756031289468326e355b6fa8316960d0d65f8b5d6b3a3e7866de7/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b", size = 2241884, upload-time = "2025-04-23T18:30:58.867Z" },
{ url = "https://files.pythonhosted.org/packages/28/c3/a74c1c37f49c0a02c89c7340fafc0ba816b29bd495d1a31ce1bdeacc6085/pydantic_core-2.41.4-cp310-cp310-win32.whl", hash = "sha256:0cf2a1f599efe57fa0051312774280ee0f650e11152325e41dfd3018ef2c1b57", size = 1975464, upload-time = "2025-10-14T10:20:00.581Z" }, { url = "https://files.pythonhosted.org/packages/0b/b0/249ee6d2646f1cdadcb813805fe76265745c4010cf20a8eba7b0e639d9b2/pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22", size = 1910496, upload-time = "2025-04-23T18:31:00.078Z" },
{ url = "https://files.pythonhosted.org/packages/d6/23/5dd5c1324ba80303368f7569e2e2e1a721c7d9eb16acb7eb7b7f85cb1be2/pydantic_core-2.41.4-cp310-cp310-win_amd64.whl", hash = "sha256:a8c2e340d7e454dc3340d3d2e8f23558ebe78c98aa8f68851b04dcb7bc37abdc", size = 2024497, upload-time = "2025-10-14T10:20:03.018Z" }, { url = "https://files.pythonhosted.org/packages/66/ff/172ba8f12a42d4b552917aa65d1f2328990d3ccfc01d5b7c943ec084299f/pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640", size = 1955019, upload-time = "2025-04-23T18:31:01.335Z" },
{ url = "https://files.pythonhosted.org/packages/62/4c/f6cbfa1e8efacd00b846764e8484fe173d25b8dab881e277a619177f3384/pydantic_core-2.41.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:28ff11666443a1a8cf2a044d6a545ebffa8382b5f7973f22c36109205e65dc80", size = 2109062, upload-time = "2025-10-14T10:20:04.486Z" }, { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" },
{ url = "https://files.pythonhosted.org/packages/21/f8/40b72d3868896bfcd410e1bd7e516e762d326201c48e5b4a06446f6cf9e8/pydantic_core-2.41.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:61760c3925d4633290292bad462e0f737b840508b4f722247d8729684f6539ae", size = 1916301, upload-time = "2025-10-14T10:20:06.857Z" }, { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" },
{ url = "https://files.pythonhosted.org/packages/94/4d/d203dce8bee7faeca791671c88519969d98d3b4e8f225da5b96dad226fc8/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eae547b7315d055b0de2ec3965643b0ab82ad0106a7ffd29615ee9f266a02827", size = 1968728, upload-time = "2025-10-14T10:20:08.353Z" }, { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" },
{ url = "https://files.pythonhosted.org/packages/65/f5/6a66187775df87c24d526985b3a5d78d861580ca466fbd9d4d0e792fcf6c/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef9ee5471edd58d1fcce1c80ffc8783a650e3e3a193fe90d52e43bb4d87bff1f", size = 2050238, upload-time = "2025-10-14T10:20:09.766Z" }, { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" },
{ url = "https://files.pythonhosted.org/packages/5e/b9/78336345de97298cf53236b2f271912ce11f32c1e59de25a374ce12f9cce/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15dd504af121caaf2c95cb90c0ebf71603c53de98305621b94da0f967e572def", size = 2249424, upload-time = "2025-10-14T10:20:11.732Z" }, { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" },
{ url = "https://files.pythonhosted.org/packages/99/bb/a4584888b70ee594c3d374a71af5075a68654d6c780369df269118af7402/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a926768ea49a8af4d36abd6a8968b8790f7f76dd7cbd5a4c180db2b4ac9a3a2", size = 2366047, upload-time = "2025-10-14T10:20:13.647Z" }, { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" },
{ url = "https://files.pythonhosted.org/packages/5f/8d/17fc5de9d6418e4d2ae8c675f905cdafdc59d3bf3bf9c946b7ab796a992a/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916b9b7d134bff5440098a4deb80e4cb623e68974a87883299de9124126c2a8", size = 2071163, upload-time = "2025-10-14T10:20:15.307Z" }, { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" },
{ url = "https://files.pythonhosted.org/packages/54/e7/03d2c5c0b8ed37a4617430db68ec5e7dbba66358b629cd69e11b4d564367/pydantic_core-2.41.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5cf90535979089df02e6f17ffd076f07237efa55b7343d98760bde8743c4b265", size = 2190585, upload-time = "2025-10-14T10:20:17.3Z" }, { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" },
{ url = "https://files.pythonhosted.org/packages/be/fc/15d1c9fe5ad9266a5897d9b932b7f53d7e5cfc800573917a2c5d6eea56ec/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7533c76fa647fade2d7ec75ac5cc079ab3f34879626dae5689b27790a6cf5a5c", size = 2150109, upload-time = "2025-10-14T10:20:19.143Z" }, { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" },
{ url = "https://files.pythonhosted.org/packages/26/ef/e735dd008808226c83ba56972566138665b71477ad580fa5a21f0851df48/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:37e516bca9264cbf29612539801ca3cd5d1be465f940417b002905e6ed79d38a", size = 2315078, upload-time = "2025-10-14T10:20:20.742Z" }, { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" },
{ url = "https://files.pythonhosted.org/packages/90/00/806efdcf35ff2ac0f938362350cd9827b8afb116cc814b6b75cf23738c7c/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0c19cb355224037c83642429b8ce261ae108e1c5fbf5c028bac63c77b0f8646e", size = 2318737, upload-time = "2025-10-14T10:20:22.306Z" }, { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" },
{ url = "https://files.pythonhosted.org/packages/41/7e/6ac90673fe6cb36621a2283552897838c020db343fa86e513d3f563b196f/pydantic_core-2.41.4-cp311-cp311-win32.whl", hash = "sha256:09c2a60e55b357284b5f31f5ab275ba9f7f70b7525e18a132ec1f9160b4f1f03", size = 1974160, upload-time = "2025-10-14T10:20:23.817Z" }, { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" },
{ url = "https://files.pythonhosted.org/packages/e0/9d/7c5e24ee585c1f8b6356e1d11d40ab807ffde44d2db3b7dfd6d20b09720e/pydantic_core-2.41.4-cp311-cp311-win_amd64.whl", hash = "sha256:711156b6afb5cb1cb7c14a2cc2c4a8b4c717b69046f13c6b332d8a0a8f41ca3e", size = 2021883, upload-time = "2025-10-14T10:20:25.48Z" }, { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" },
{ url = "https://files.pythonhosted.org/packages/33/90/5c172357460fc28b2871eb4a0fb3843b136b429c6fa827e4b588877bf115/pydantic_core-2.41.4-cp311-cp311-win_arm64.whl", hash = "sha256:6cb9cf7e761f4f8a8589a45e49ed3c0d92d1d696a45a6feaee8c904b26efc2db", size = 1968026, upload-time = "2025-10-14T10:20:27.039Z" }, { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" },
{ url = "https://files.pythonhosted.org/packages/e9/81/d3b3e95929c4369d30b2a66a91db63c8ed0a98381ae55a45da2cd1cc1288/pydantic_core-2.41.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ab06d77e053d660a6faaf04894446df7b0a7e7aba70c2797465a0a1af00fc887", size = 2099043, upload-time = "2025-10-14T10:20:28.561Z" }, { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" },
{ url = "https://files.pythonhosted.org/packages/58/da/46fdac49e6717e3a94fc9201403e08d9d61aa7a770fab6190b8740749047/pydantic_core-2.41.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c53ff33e603a9c1179a9364b0a24694f183717b2e0da2b5ad43c316c956901b2", size = 1910699, upload-time = "2025-10-14T10:20:30.217Z" }, { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" },
{ url = "https://files.pythonhosted.org/packages/1e/63/4d948f1b9dd8e991a5a98b77dd66c74641f5f2e5225fee37994b2e07d391/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:304c54176af2c143bd181d82e77c15c41cbacea8872a2225dd37e6544dce9999", size = 1952121, upload-time = "2025-10-14T10:20:32.246Z" }, { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" },
{ url = "https://files.pythonhosted.org/packages/b2/a7/e5fc60a6f781fc634ecaa9ecc3c20171d238794cef69ae0af79ac11b89d7/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:025ba34a4cf4fb32f917d5d188ab5e702223d3ba603be4d8aca2f82bede432a4", size = 2041590, upload-time = "2025-10-14T10:20:34.332Z" }, { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" },
{ url = "https://files.pythonhosted.org/packages/70/69/dce747b1d21d59e85af433428978a1893c6f8a7068fa2bb4a927fba7a5ff/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9f5f30c402ed58f90c70e12eff65547d3ab74685ffe8283c719e6bead8ef53f", size = 2219869, upload-time = "2025-10-14T10:20:35.965Z" }, { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" },
{ url = "https://files.pythonhosted.org/packages/83/6a/c070e30e295403bf29c4df1cb781317b6a9bac7cd07b8d3acc94d501a63c/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd96e5d15385d301733113bcaa324c8bcf111275b7675a9c6e88bfb19fc05e3b", size = 2345169, upload-time = "2025-10-14T10:20:37.627Z" }, { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" },
{ url = "https://files.pythonhosted.org/packages/f0/83/06d001f8043c336baea7fd202a9ac7ad71f87e1c55d8112c50b745c40324/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98f348cbb44fae6e9653c1055db7e29de67ea6a9ca03a5fa2c2e11a47cff0e47", size = 2070165, upload-time = "2025-10-14T10:20:39.246Z" }, { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" },
{ url = "https://files.pythonhosted.org/packages/14/0a/e567c2883588dd12bcbc110232d892cf385356f7c8a9910311ac997ab715/pydantic_core-2.41.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec22626a2d14620a83ca583c6f5a4080fa3155282718b6055c2ea48d3ef35970", size = 2189067, upload-time = "2025-10-14T10:20:41.015Z" }, { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" },
{ url = "https://files.pythonhosted.org/packages/f4/1d/3d9fca34273ba03c9b1c5289f7618bc4bd09c3ad2289b5420481aa051a99/pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a95d4590b1f1a43bf33ca6d647b990a88f4a3824a8c4572c708f0b45a5290ed", size = 2132997, upload-time = "2025-10-14T10:20:43.106Z" }, { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" },
{ url = "https://files.pythonhosted.org/packages/52/70/d702ef7a6cd41a8afc61f3554922b3ed8d19dd54c3bd4bdbfe332e610827/pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:f9672ab4d398e1b602feadcffcdd3af44d5f5e6ddc15bc7d15d376d47e8e19f8", size = 2307187, upload-time = "2025-10-14T10:20:44.849Z" }, { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" },
{ url = "https://files.pythonhosted.org/packages/68/4c/c06be6e27545d08b802127914156f38d10ca287a9e8489342793de8aae3c/pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:84d8854db5f55fead3b579f04bda9a36461dab0730c5d570e1526483e7bb8431", size = 2305204, upload-time = "2025-10-14T10:20:46.781Z" }, { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" },
{ url = "https://files.pythonhosted.org/packages/b0/e5/35ae4919bcd9f18603419e23c5eaf32750224a89d41a8df1a3704b69f77e/pydantic_core-2.41.4-cp312-cp312-win32.whl", hash = "sha256:9be1c01adb2ecc4e464392c36d17f97e9110fbbc906bcbe1c943b5b87a74aabd", size = 1972536, upload-time = "2025-10-14T10:20:48.39Z" }, { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" },
{ url = "https://files.pythonhosted.org/packages/1e/c2/49c5bb6d2a49eb2ee3647a93e3dae7080c6409a8a7558b075027644e879c/pydantic_core-2.41.4-cp312-cp312-win_amd64.whl", hash = "sha256:d682cf1d22bab22a5be08539dca3d1593488a99998f9f412137bc323179067ff", size = 2031132, upload-time = "2025-10-14T10:20:50.421Z" }, { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" },
{ url = "https://files.pythonhosted.org/packages/06/23/936343dbcba6eec93f73e95eb346810fc732f71ba27967b287b66f7b7097/pydantic_core-2.41.4-cp312-cp312-win_arm64.whl", hash = "sha256:833eebfd75a26d17470b58768c1834dfc90141b7afc6eb0429c21fc5a21dcfb8", size = 1969483, upload-time = "2025-10-14T10:20:52.35Z" }, { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" },
{ url = "https://files.pythonhosted.org/packages/13/d0/c20adabd181a029a970738dfe23710b52a31f1258f591874fcdec7359845/pydantic_core-2.41.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:85e050ad9e5f6fe1004eec65c914332e52f429bc0ae12d6fa2092407a462c746", size = 2105688, upload-time = "2025-10-14T10:20:54.448Z" }, { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" },
{ url = "https://files.pythonhosted.org/packages/00/b6/0ce5c03cec5ae94cca220dfecddc453c077d71363b98a4bbdb3c0b22c783/pydantic_core-2.41.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7393f1d64792763a48924ba31d1e44c2cfbc05e3b1c2c9abb4ceeadd912cced", size = 1910807, upload-time = "2025-10-14T10:20:56.115Z" }, { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" },
{ url = "https://files.pythonhosted.org/packages/68/3e/800d3d02c8beb0b5c069c870cbb83799d085debf43499c897bb4b4aaff0d/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94dab0940b0d1fb28bcab847adf887c66a27a40291eedf0b473be58761c9799a", size = 1956669, upload-time = "2025-10-14T10:20:57.874Z" }, { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" },
{ url = "https://files.pythonhosted.org/packages/60/a4/24271cc71a17f64589be49ab8bd0751f6a0a03046c690df60989f2f95c2c/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de7c42f897e689ee6f9e93c4bec72b99ae3b32a2ade1c7e4798e690ff5246e02", size = 2051629, upload-time = "2025-10-14T10:21:00.006Z" }, { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" },
{ url = "https://files.pythonhosted.org/packages/68/de/45af3ca2f175d91b96bfb62e1f2d2f1f9f3b14a734afe0bfeff079f78181/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:664b3199193262277b8b3cd1e754fb07f2c6023289c815a1e1e8fb415cb247b1", size = 2224049, upload-time = "2025-10-14T10:21:01.801Z" }, { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" },
{ url = "https://files.pythonhosted.org/packages/af/8f/ae4e1ff84672bf869d0a77af24fd78387850e9497753c432875066b5d622/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d95b253b88f7d308b1c0b417c4624f44553ba4762816f94e6986819b9c273fb2", size = 2342409, upload-time = "2025-10-14T10:21:03.556Z" }, { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" },
{ url = "https://files.pythonhosted.org/packages/18/62/273dd70b0026a085c7b74b000394e1ef95719ea579c76ea2f0cc8893736d/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1351f5bbdbbabc689727cb91649a00cb9ee7203e0a6e54e9f5ba9e22e384b84", size = 2069635, upload-time = "2025-10-14T10:21:05.385Z" }, { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" },
{ url = "https://files.pythonhosted.org/packages/30/03/cf485fff699b4cdaea469bc481719d3e49f023241b4abb656f8d422189fc/pydantic_core-2.41.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1affa4798520b148d7182da0615d648e752de4ab1a9566b7471bc803d88a062d", size = 2194284, upload-time = "2025-10-14T10:21:07.122Z" }, { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" },
{ url = "https://files.pythonhosted.org/packages/f9/7e/c8e713db32405dfd97211f2fc0a15d6bf8adb7640f3d18544c1f39526619/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7b74e18052fea4aa8dea2fb7dbc23d15439695da6cbe6cfc1b694af1115df09d", size = 2137566, upload-time = "2025-10-14T10:21:08.981Z" }, { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" },
{ url = "https://files.pythonhosted.org/packages/04/f7/db71fd4cdccc8b75990f79ccafbbd66757e19f6d5ee724a6252414483fb4/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:285b643d75c0e30abda9dc1077395624f314a37e3c09ca402d4015ef5979f1a2", size = 2316809, upload-time = "2025-10-14T10:21:10.805Z" }, { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" },
{ url = "https://files.pythonhosted.org/packages/76/63/a54973ddb945f1bca56742b48b144d85c9fc22f819ddeb9f861c249d5464/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:f52679ff4218d713b3b33f88c89ccbf3a5c2c12ba665fb80ccc4192b4608dbab", size = 2311119, upload-time = "2025-10-14T10:21:12.583Z" }, { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" },
{ url = "https://files.pythonhosted.org/packages/f8/03/5d12891e93c19218af74843a27e32b94922195ded2386f7b55382f904d2f/pydantic_core-2.41.4-cp313-cp313-win32.whl", hash = "sha256:ecde6dedd6fff127c273c76821bb754d793be1024bc33314a120f83a3c69460c", size = 1981398, upload-time = "2025-10-14T10:21:14.584Z" }, { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" },
{ url = "https://files.pythonhosted.org/packages/be/d8/fd0de71f39db91135b7a26996160de71c073d8635edfce8b3c3681be0d6d/pydantic_core-2.41.4-cp313-cp313-win_amd64.whl", hash = "sha256:d081a1f3800f05409ed868ebb2d74ac39dd0c1ff6c035b5162356d76030736d4", size = 2030735, upload-time = "2025-10-14T10:21:16.432Z" }, { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" },
{ url = "https://files.pythonhosted.org/packages/72/86/c99921c1cf6650023c08bfab6fe2d7057a5142628ef7ccfa9921f2dda1d5/pydantic_core-2.41.4-cp313-cp313-win_arm64.whl", hash = "sha256:f8e49c9c364a7edcbe2a310f12733aad95b022495ef2a8d653f645e5d20c1564", size = 1973209, upload-time = "2025-10-14T10:21:18.213Z" }, { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" },
{ url = "https://files.pythonhosted.org/packages/36/0d/b5706cacb70a8414396efdda3d72ae0542e050b591119e458e2490baf035/pydantic_core-2.41.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ed97fd56a561f5eb5706cebe94f1ad7c13b84d98312a05546f2ad036bafe87f4", size = 1877324, upload-time = "2025-10-14T10:21:20.363Z" }, { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" },
{ url = "https://files.pythonhosted.org/packages/de/2d/cba1fa02cfdea72dfb3a9babb067c83b9dff0bbcb198368e000a6b756ea7/pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a870c307bf1ee91fc58a9a61338ff780d01bfae45922624816878dce784095d2", size = 1884515, upload-time = "2025-10-14T10:21:22.339Z" }, { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" },
{ url = "https://files.pythonhosted.org/packages/07/ea/3df927c4384ed9b503c9cc2d076cf983b4f2adb0c754578dfb1245c51e46/pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d25e97bc1f5f8f7985bdc2335ef9e73843bb561eb1fa6831fdfc295c1c2061cf", size = 2042819, upload-time = "2025-10-14T10:21:26.683Z" }, { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
{ url = "https://files.pythonhosted.org/packages/6a/ee/df8e871f07074250270a3b1b82aad4cd0026b588acd5d7d3eb2fcb1471a3/pydantic_core-2.41.4-cp313-cp313t-win_amd64.whl", hash = "sha256:d405d14bea042f166512add3091c1af40437c2e7f86988f3915fabd27b1e9cd2", size = 1995866, upload-time = "2025-10-14T10:21:28.951Z" }, { url = "https://files.pythonhosted.org/packages/53/ea/bbe9095cdd771987d13c82d104a9c8559ae9aec1e29f139e286fd2e9256e/pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d", size = 2028677, upload-time = "2025-04-23T18:32:27.227Z" },
{ url = "https://files.pythonhosted.org/packages/fc/de/b20f4ab954d6d399499c33ec4fafc46d9551e11dc1858fb7f5dca0748ceb/pydantic_core-2.41.4-cp313-cp313t-win_arm64.whl", hash = "sha256:19f3684868309db5263a11bace3c45d93f6f24afa2ffe75a647583df22a2ff89", size = 1970034, upload-time = "2025-10-14T10:21:30.869Z" }, { url = "https://files.pythonhosted.org/packages/49/1d/4ac5ed228078737d457a609013e8f7edc64adc37b91d619ea965758369e5/pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954", size = 1864735, upload-time = "2025-04-23T18:32:29.019Z" },
{ url = "https://files.pythonhosted.org/packages/54/28/d3325da57d413b9819365546eb9a6e8b7cbd9373d9380efd5f74326143e6/pydantic_core-2.41.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:e9205d97ed08a82ebb9a307e92914bb30e18cdf6f6b12ca4bedadb1588a0bfe1", size = 2102022, upload-time = "2025-10-14T10:21:32.809Z" }, { url = "https://files.pythonhosted.org/packages/23/9a/2e70d6388d7cda488ae38f57bc2f7b03ee442fbcf0d75d848304ac7e405b/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb", size = 1898467, upload-time = "2025-04-23T18:32:31.119Z" },
{ url = "https://files.pythonhosted.org/packages/9e/24/b58a1bc0d834bf1acc4361e61233ee217169a42efbdc15a60296e13ce438/pydantic_core-2.41.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:82df1f432b37d832709fbcc0e24394bba04a01b6ecf1ee87578145c19cde12ac", size = 1905495, upload-time = "2025-10-14T10:21:34.812Z" }, { url = "https://files.pythonhosted.org/packages/ff/2e/1568934feb43370c1ffb78a77f0baaa5a8b6897513e7a91051af707ffdc4/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7", size = 1983041, upload-time = "2025-04-23T18:32:33.655Z" },
{ url = "https://files.pythonhosted.org/packages/fb/a4/71f759cc41b7043e8ecdaab81b985a9b6cad7cec077e0b92cff8b71ecf6b/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3b4cc4539e055cfa39a3763c939f9d409eb40e85813257dcd761985a108554", size = 1956131, upload-time = "2025-10-14T10:21:36.924Z" }, { url = "https://files.pythonhosted.org/packages/01/1a/1a1118f38ab64eac2f6269eb8c120ab915be30e387bb561e3af904b12499/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4", size = 2136503, upload-time = "2025-04-23T18:32:35.519Z" },
{ url = "https://files.pythonhosted.org/packages/b0/64/1e79ac7aa51f1eec7c4cda8cbe456d5d09f05fdd68b32776d72168d54275/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1eb1754fce47c63d2ff57fdb88c351a6c0150995890088b33767a10218eaa4e", size = 2052236, upload-time = "2025-10-14T10:21:38.927Z" }, { url = "https://files.pythonhosted.org/packages/5c/da/44754d1d7ae0f22d6d3ce6c6b1486fc07ac2c524ed8f6eca636e2e1ee49b/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b", size = 2736079, upload-time = "2025-04-23T18:32:37.659Z" },
{ url = "https://files.pythonhosted.org/packages/e9/e3/a3ffc363bd4287b80f1d43dc1c28ba64831f8dfc237d6fec8f2661138d48/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6ab5ab30ef325b443f379ddb575a34969c333004fca5a1daa0133a6ffaad616", size = 2223573, upload-time = "2025-10-14T10:21:41.574Z" }, { url = "https://files.pythonhosted.org/packages/4d/98/f43cd89172220ec5aa86654967b22d862146bc4d736b1350b4c41e7c9c03/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3", size = 2006508, upload-time = "2025-04-23T18:32:39.637Z" },
{ url = "https://files.pythonhosted.org/packages/28/27/78814089b4d2e684a9088ede3790763c64693c3d1408ddc0a248bc789126/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:31a41030b1d9ca497634092b46481b937ff9397a86f9f51bd41c4767b6fc04af", size = 2342467, upload-time = "2025-10-14T10:21:44.018Z" }, { url = "https://files.pythonhosted.org/packages/2b/cc/f77e8e242171d2158309f830f7d5d07e0531b756106f36bc18712dc439df/pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a", size = 2113693, upload-time = "2025-04-23T18:32:41.818Z" },
{ url = "https://files.pythonhosted.org/packages/92/97/4de0e2a1159cb85ad737e03306717637842c88c7fd6d97973172fb183149/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a44ac1738591472c3d020f61c6df1e4015180d6262ebd39bf2aeb52571b60f12", size = 2063754, upload-time = "2025-10-14T10:21:46.466Z" }, { url = "https://files.pythonhosted.org/packages/54/7a/7be6a7bd43e0a47c147ba7fbf124fe8aaf1200bc587da925509641113b2d/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782", size = 2074224, upload-time = "2025-04-23T18:32:44.033Z" },
{ url = "https://files.pythonhosted.org/packages/0f/50/8cb90ce4b9efcf7ae78130afeb99fd1c86125ccdf9906ef64b9d42f37c25/pydantic_core-2.41.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d72f2b5e6e82ab8f94ea7d0d42f83c487dc159c5240d8f83beae684472864e2d", size = 2196754, upload-time = "2025-10-14T10:21:48.486Z" }, { url = "https://files.pythonhosted.org/packages/2a/07/31cf8fadffbb03be1cb520850e00a8490c0927ec456e8293cafda0726184/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9", size = 2245403, upload-time = "2025-04-23T18:32:45.836Z" },
{ url = "https://files.pythonhosted.org/packages/34/3b/ccdc77af9cd5082723574a1cc1bcae7a6acacc829d7c0a06201f7886a109/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c4d1e854aaf044487d31143f541f7aafe7b482ae72a022c664b2de2e466ed0ad", size = 2137115, upload-time = "2025-10-14T10:21:50.63Z" }, { url = "https://files.pythonhosted.org/packages/b6/8d/bbaf4c6721b668d44f01861f297eb01c9b35f612f6b8e14173cb204e6240/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e", size = 2242331, upload-time = "2025-04-23T18:32:47.618Z" },
{ url = "https://files.pythonhosted.org/packages/ca/ba/e7c7a02651a8f7c52dc2cff2b64a30c313e3b57c7d93703cecea76c09b71/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b568af94267729d76e6ee5ececda4e283d07bbb28e8148bb17adad93d025d25a", size = 2317400, upload-time = "2025-10-14T10:21:52.959Z" }, { url = "https://files.pythonhosted.org/packages/bb/93/3cc157026bca8f5006250e74515119fcaa6d6858aceee8f67ab6dc548c16/pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9", size = 1910571, upload-time = "2025-04-23T18:32:49.401Z" },
{ url = "https://files.pythonhosted.org/packages/2c/ba/6c533a4ee8aec6b812c643c49bb3bd88d3f01e3cebe451bb85512d37f00f/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6d55fb8b1e8929b341cc313a81a26e0d48aa3b519c1dbaadec3a6a2b4fcad025", size = 2312070, upload-time = "2025-10-14T10:21:55.419Z" }, { url = "https://files.pythonhosted.org/packages/5b/90/7edc3b2a0d9f0dda8806c04e511a67b0b7a41d2187e2003673a996fb4310/pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3", size = 1956504, upload-time = "2025-04-23T18:32:51.287Z" },
{ url = "https://files.pythonhosted.org/packages/22/ae/f10524fcc0ab8d7f96cf9a74c880243576fd3e72bd8ce4f81e43d22bcab7/pydantic_core-2.41.4-cp314-cp314-win32.whl", hash = "sha256:5b66584e549e2e32a1398df11da2e0a7eff45d5c2d9db9d5667c5e6ac764d77e", size = 1982277, upload-time = "2025-10-14T10:21:57.474Z" }, { url = "https://files.pythonhosted.org/packages/30/68/373d55e58b7e83ce371691f6eaa7175e3a24b956c44628eb25d7da007917/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa", size = 2023982, upload-time = "2025-04-23T18:32:53.14Z" },
{ url = "https://files.pythonhosted.org/packages/b4/dc/e5aa27aea1ad4638f0c3fb41132f7eb583bd7420ee63204e2d4333a3bbf9/pydantic_core-2.41.4-cp314-cp314-win_amd64.whl", hash = "sha256:557a0aab88664cc552285316809cab897716a372afaf8efdbef756f8b890e894", size = 2024608, upload-time = "2025-10-14T10:21:59.557Z" }, { url = "https://files.pythonhosted.org/packages/a4/16/145f54ac08c96a63d8ed6442f9dec17b2773d19920b627b18d4f10a061ea/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29", size = 1858412, upload-time = "2025-04-23T18:32:55.52Z" },
{ url = "https://files.pythonhosted.org/packages/3e/61/51d89cc2612bd147198e120a13f150afbf0bcb4615cddb049ab10b81b79e/pydantic_core-2.41.4-cp314-cp314-win_arm64.whl", hash = "sha256:3f1ea6f48a045745d0d9f325989d8abd3f1eaf47dd00485912d1a3a63c623a8d", size = 1967614, upload-time = "2025-10-14T10:22:01.847Z" }, { url = "https://files.pythonhosted.org/packages/41/b1/c6dc6c3e2de4516c0bb2c46f6a373b91b5660312342a0cf5826e38ad82fa/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d", size = 1892749, upload-time = "2025-04-23T18:32:57.546Z" },
{ url = "https://files.pythonhosted.org/packages/0d/c2/472f2e31b95eff099961fa050c376ab7156a81da194f9edb9f710f68787b/pydantic_core-2.41.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6c1fe4c5404c448b13188dd8bd2ebc2bdd7e6727fa61ff481bcc2cca894018da", size = 1876904, upload-time = "2025-10-14T10:22:04.062Z" }, { url = "https://files.pythonhosted.org/packages/12/73/8cd57e20afba760b21b742106f9dbdfa6697f1570b189c7457a1af4cd8a0/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e", size = 2067527, upload-time = "2025-04-23T18:32:59.771Z" },
{ url = "https://files.pythonhosted.org/packages/4a/07/ea8eeb91173807ecdae4f4a5f4b150a520085b35454350fc219ba79e66a3/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:523e7da4d43b113bf8e7b49fa4ec0c35bf4fe66b2230bfc5c13cc498f12c6c3e", size = 1882538, upload-time = "2025-10-14T10:22:06.39Z" }, { url = "https://files.pythonhosted.org/packages/e3/d5/0bb5d988cc019b3cba4a78f2d4b3854427fc47ee8ec8e9eaabf787da239c/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c", size = 2108225, upload-time = "2025-04-23T18:33:04.51Z" },
{ url = "https://files.pythonhosted.org/packages/1e/29/b53a9ca6cd366bfc928823679c6a76c7a4c69f8201c0ba7903ad18ebae2f/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5729225de81fb65b70fdb1907fcf08c75d498f4a6f15af005aabb1fdadc19dfa", size = 2041183, upload-time = "2025-10-14T10:22:08.812Z" }, { url = "https://files.pythonhosted.org/packages/f1/c5/00c02d1571913d496aabf146106ad8239dc132485ee22efe08085084ff7c/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec", size = 2069490, upload-time = "2025-04-23T18:33:06.391Z" },
{ url = "https://files.pythonhosted.org/packages/c7/3d/f8c1a371ceebcaf94d6dd2d77c6cf4b1c078e13a5837aee83f760b4f7cfd/pydantic_core-2.41.4-cp314-cp314t-win_amd64.whl", hash = "sha256:de2cfbb09e88f0f795fd90cf955858fc2c691df65b1f21f0aa00b99f3fbc661d", size = 1993542, upload-time = "2025-10-14T10:22:11.332Z" }, { url = "https://files.pythonhosted.org/packages/22/a8/dccc38768274d3ed3a59b5d06f59ccb845778687652daa71df0cab4040d7/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052", size = 2237525, upload-time = "2025-04-23T18:33:08.44Z" },
{ url = "https://files.pythonhosted.org/packages/8a/ac/9fc61b4f9d079482a290afe8d206b8f490e9fd32d4fc03ed4fc698214e01/pydantic_core-2.41.4-cp314-cp314t-win_arm64.whl", hash = "sha256:d34f950ae05a83e0ede899c595f312ca976023ea1db100cd5aa188f7005e3ab0", size = 1973897, upload-time = "2025-10-14T10:22:13.444Z" }, { url = "https://files.pythonhosted.org/packages/d4/e7/4f98c0b125dda7cf7ccd14ba936218397b44f50a56dd8c16a3091df116c3/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c", size = 2238446, upload-time = "2025-04-23T18:33:10.313Z" },
{ url = "https://files.pythonhosted.org/packages/b0/12/5ba58daa7f453454464f92b3ca7b9d7c657d8641c48e370c3ebc9a82dd78/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:a1b2cfec3879afb742a7b0bcfa53e4f22ba96571c9e54d6a3afe1052d17d843b", size = 2122139, upload-time = "2025-10-14T10:22:47.288Z" }, { url = "https://files.pythonhosted.org/packages/ce/91/2ec36480fdb0b783cd9ef6795753c1dea13882f2e68e73bce76ae8c21e6a/pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808", size = 2066678, upload-time = "2025-04-23T18:33:12.224Z" },
{ url = "https://files.pythonhosted.org/packages/21/fb/6860126a77725c3108baecd10fd3d75fec25191d6381b6eb2ac660228eac/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:d175600d975b7c244af6eb9c9041f10059f20b8bbffec9e33fdd5ee3f67cdc42", size = 1936674, upload-time = "2025-10-14T10:22:49.555Z" }, { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" },
{ url = "https://files.pythonhosted.org/packages/de/be/57dcaa3ed595d81f8757e2b44a38240ac5d37628bce25fb20d02c7018776/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f184d657fa4947ae5ec9c47bd7e917730fa1cbb78195037e32dcbab50aca5ee", size = 1956398, upload-time = "2025-10-14T10:22:52.19Z" }, { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" },
{ url = "https://files.pythonhosted.org/packages/2f/1d/679a344fadb9695f1a6a294d739fbd21d71fa023286daeea8c0ed49e7c2b/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed810568aeffed3edc78910af32af911c835cc39ebbfacd1f0ab5dd53028e5c", size = 2138674, upload-time = "2025-10-14T10:22:54.499Z" }, { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" },
{ url = "https://files.pythonhosted.org/packages/c4/48/ae937e5a831b7c0dc646b2ef788c27cd003894882415300ed21927c21efa/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:4f5d640aeebb438517150fdeec097739614421900e4a08db4a3ef38898798537", size = 2112087, upload-time = "2025-10-14T10:22:56.818Z" }, { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" },
{ url = "https://files.pythonhosted.org/packages/5e/db/6db8073e3d32dae017da7e0d16a9ecb897d0a4d92e00634916e486097961/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:4a9ab037b71927babc6d9e7fc01aea9e66dc2a4a34dff06ef0724a4049629f94", size = 1920387, upload-time = "2025-10-14T10:22:59.342Z" }, { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" },
{ url = "https://files.pythonhosted.org/packages/0d/c1/dd3542d072fcc336030d66834872f0328727e3b8de289c662faa04aa270e/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4dab9484ec605c3016df9ad4fd4f9a390bc5d816a3b10c6550f8424bb80b18c", size = 1951495, upload-time = "2025-10-14T10:23:02.089Z" }, { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" },
{ url = "https://files.pythonhosted.org/packages/2b/c6/db8d13a1f8ab3f1eb08c88bd00fd62d44311e3456d1e85c0e59e0a0376e7/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8a5028425820731d8c6c098ab642d7b8b999758e24acae03ed38a66eca8335", size = 2139008, upload-time = "2025-10-14T10:23:04.539Z" }, { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" },
{ url = "https://files.pythonhosted.org/packages/5d/d4/912e976a2dd0b49f31c98a060ca90b353f3b73ee3ea2fd0030412f6ac5ec/pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e5ab4fc177dd41536b3c32b2ea11380dd3d4619a385860621478ac2d25ceb00", size = 2106739, upload-time = "2025-10-14T10:23:06.934Z" }, { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" },
{ url = "https://files.pythonhosted.org/packages/71/f0/66ec5a626c81eba326072d6ee2b127f8c139543f1bf609b4842978d37833/pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3d88d0054d3fa11ce936184896bed3c1c5441d6fa483b498fac6a5d0dd6f64a9", size = 1932549, upload-time = "2025-10-14T10:23:09.24Z" }, { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" },
{ url = "https://files.pythonhosted.org/packages/c4/af/625626278ca801ea0a658c2dcf290dc9f21bb383098e99e7c6a029fccfc0/pydantic_core-2.41.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b2a054a8725f05b4b6503357e0ac1c4e8234ad3b0c2ac130d6ffc66f0e170e2", size = 2135093, upload-time = "2025-10-14T10:23:11.626Z" }, { url = "https://files.pythonhosted.org/packages/08/98/dbf3fdfabaf81cda5622154fda78ea9965ac467e3239078e0dcd6df159e7/pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101", size = 2024034, upload-time = "2025-04-23T18:33:32.843Z" },
{ url = "https://files.pythonhosted.org/packages/20/f6/2fba049f54e0f4975fef66be654c597a1d005320fa141863699180c7697d/pydantic_core-2.41.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0d9db5a161c99375a0c68c058e227bee1d89303300802601d76a3d01f74e258", size = 2187971, upload-time = "2025-10-14T10:23:14.437Z" }, { url = "https://files.pythonhosted.org/packages/8d/99/7810aa9256e7f2ccd492590f86b79d370df1e9292f1f80b000b6a75bd2fb/pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64", size = 1858578, upload-time = "2025-04-23T18:33:34.912Z" },
{ url = "https://files.pythonhosted.org/packages/0e/80/65ab839a2dfcd3b949202f9d920c34f9de5a537c3646662bdf2f7d999680/pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:6273ea2c8ffdac7b7fda2653c49682db815aebf4a89243a6feccf5e36c18c347", size = 2147939, upload-time = "2025-10-14T10:23:16.831Z" }, { url = "https://files.pythonhosted.org/packages/d8/60/bc06fa9027c7006cc6dd21e48dbf39076dc39d9abbaf718a1604973a9670/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d", size = 1892858, upload-time = "2025-04-23T18:33:36.933Z" },
{ url = "https://files.pythonhosted.org/packages/44/58/627565d3d182ce6dfda18b8e1c841eede3629d59c9d7cbc1e12a03aeb328/pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:4c973add636efc61de22530b2ef83a65f39b6d6f656df97f678720e20de26caa", size = 2311400, upload-time = "2025-10-14T10:23:19.234Z" }, { url = "https://files.pythonhosted.org/packages/f2/40/9d03997d9518816c68b4dfccb88969756b9146031b61cd37f781c74c9b6a/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535", size = 2068498, upload-time = "2025-04-23T18:33:38.997Z" },
{ url = "https://files.pythonhosted.org/packages/24/06/8a84711162ad5a5f19a88cead37cca81b4b1f294f46260ef7334ae4f24d3/pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b69d1973354758007f46cf2d44a4f3d0933f10b6dc9bf15cf1356e037f6f731a", size = 2316840, upload-time = "2025-10-14T10:23:21.738Z" }, { url = "https://files.pythonhosted.org/packages/d8/62/d490198d05d2d86672dc269f52579cad7261ced64c2df213d5c16e0aecb1/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d", size = 2108428, upload-time = "2025-04-23T18:33:41.18Z" },
{ url = "https://files.pythonhosted.org/packages/aa/8b/b7bb512a4682a2f7fbfae152a755d37351743900226d29bd953aaf870eaa/pydantic_core-2.41.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3619320641fd212aaf5997b6ca505e97540b7e16418f4a241f44cdf108ffb50d", size = 2149135, upload-time = "2025-10-14T10:23:24.379Z" }, { url = "https://files.pythonhosted.org/packages/9a/ec/4cd215534fd10b8549015f12ea650a1a973da20ce46430b68fc3185573e8/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6", size = 2069854, upload-time = "2025-04-23T18:33:43.446Z" },
{ url = "https://files.pythonhosted.org/packages/7e/7d/138e902ed6399b866f7cfe4435d22445e16fff888a1c00560d9dc79a780f/pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:491535d45cd7ad7e4a2af4a5169b0d07bebf1adfd164b0368da8aa41e19907a5", size = 2104721, upload-time = "2025-10-14T10:23:26.906Z" }, { url = "https://files.pythonhosted.org/packages/1a/1a/abbd63d47e1d9b0d632fee6bb15785d0889c8a6e0a6c3b5a8e28ac1ec5d2/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca", size = 2237859, upload-time = "2025-04-23T18:33:45.56Z" },
{ url = "https://files.pythonhosted.org/packages/47/13/0525623cf94627f7b53b4c2034c81edc8491cbfc7c28d5447fa318791479/pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:54d86c0cada6aba4ec4c047d0e348cbad7063b87ae0f005d9f8c9ad04d4a92a2", size = 1931608, upload-time = "2025-10-14T10:23:29.306Z" }, { url = "https://files.pythonhosted.org/packages/80/1c/fa883643429908b1c90598fd2642af8839efd1d835b65af1f75fba4d94fe/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039", size = 2239059, upload-time = "2025-04-23T18:33:47.735Z" },
{ url = "https://files.pythonhosted.org/packages/d6/f9/744bc98137d6ef0a233f808bfc9b18cf94624bf30836a18d3b05d08bf418/pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca1124aced216b2500dc2609eade086d718e8249cb9696660ab447d50a758bd", size = 2132986, upload-time = "2025-10-14T10:23:32.057Z" }, { url = "https://files.pythonhosted.org/packages/d4/29/3cade8a924a61f60ccfa10842f75eb12787e1440e2b8660ceffeb26685e7/pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27", size = 2066661, upload-time = "2025-04-23T18:33:49.995Z" },
{ url = "https://files.pythonhosted.org/packages/17/c8/629e88920171173f6049386cc71f893dff03209a9ef32b4d2f7e7c264bcf/pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c9024169becccf0cb470ada03ee578d7348c119a0d42af3dcf9eda96e3a247c", size = 2187516, upload-time = "2025-10-14T10:23:34.871Z" },
{ url = "https://files.pythonhosted.org/packages/2e/0f/4f2734688d98488782218ca61bcc118329bf5de05bb7fe3adc7dd79b0b86/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:26895a4268ae5a2849269f4991cdc97236e4b9c010e51137becf25182daac405", size = 2146146, upload-time = "2025-10-14T10:23:37.342Z" },
{ url = "https://files.pythonhosted.org/packages/ed/f2/ab385dbd94a052c62224b99cf99002eee99dbec40e10006c78575aead256/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:ca4df25762cf71308c446e33c9b1fdca2923a3f13de616e2a949f38bf21ff5a8", size = 2311296, upload-time = "2025-10-14T10:23:40.145Z" },
{ url = "https://files.pythonhosted.org/packages/fc/8e/e4f12afe1beeb9823bba5375f8f258df0cc61b056b0195fb1cf9f62a1a58/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5a28fcedd762349519276c36634e71853b4541079cab4acaaac60c4421827308", size = 2315386, upload-time = "2025-10-14T10:23:42.624Z" },
{ url = "https://files.pythonhosted.org/packages/48/f7/925f65d930802e3ea2eb4d5afa4cb8730c8dc0d2cb89a59dc4ed2fcb2d74/pydantic_core-2.41.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c173ddcd86afd2535e2b695217e82191580663a1d1928239f877f5a1649ef39f", size = 2147775, upload-time = "2025-10-14T10:23:45.406Z" },
] ]
[[package]] [[package]]
@@ -924,6 +907,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
{ url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
{ url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
{ url = "https://files.pythonhosted.org/packages/9f/62/67fc8e68a75f738c9200422bf65693fb79a4cd0dc5b23310e5202e978090/pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da", size = 184450, upload-time = "2025-09-25T21:33:00.618Z" },
{ url = "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917", size = 174319, upload-time = "2025-09-25T21:33:02.086Z" },
{ url = "https://files.pythonhosted.org/packages/d0/cd/f0cfc8c74f8a030017a2b9c771b7f47e5dd702c3e28e5b2071374bda2948/pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9", size = 737631, upload-time = "2025-09-25T21:33:03.25Z" },
{ url = "https://files.pythonhosted.org/packages/ef/b2/18f2bd28cd2055a79a46c9b0895c0b3d987ce40ee471cecf58a1a0199805/pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5", size = 836795, upload-time = "2025-09-25T21:33:05.014Z" },
{ url = "https://files.pythonhosted.org/packages/73/b9/793686b2d54b531203c160ef12bec60228a0109c79bae6c1277961026770/pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a", size = 750767, upload-time = "2025-09-25T21:33:06.398Z" },
{ url = "https://files.pythonhosted.org/packages/a9/86/a137b39a611def2ed78b0e66ce2fe13ee701a07c07aebe55c340ed2a050e/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926", size = 727982, upload-time = "2025-09-25T21:33:08.708Z" },
{ url = "https://files.pythonhosted.org/packages/dd/62/71c27c94f457cf4418ef8ccc71735324c549f7e3ea9d34aba50874563561/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7", size = 755677, upload-time = "2025-09-25T21:33:09.876Z" },
{ url = "https://files.pythonhosted.org/packages/29/3d/6f5e0d58bd924fb0d06c3a6bad00effbdae2de5adb5cda5648006ffbd8d3/pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0", size = 142592, upload-time = "2025-09-25T21:33:10.983Z" },
{ url = "https://files.pythonhosted.org/packages/f0/0c/25113e0b5e103d7f1490c0e947e303fe4a696c10b501dea7a9f49d4e876c/pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007", size = 158777, upload-time = "2025-09-25T21:33:15.55Z" },
] ]
[[package]] [[package]]
@@ -1047,14 +1039,14 @@ wheels = [
[[package]] [[package]]
name = "typing-inspection" name = "typing-inspection"
version = "0.4.2" version = "0.4.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "typing-extensions" }, { name = "typing-extensions" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
] ]
[[package]] [[package]]
@@ -1093,8 +1085,13 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" },
{ url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" },
{ url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" },
{ url = "https://files.pythonhosted.org/packages/05/52/7223011bb760fce8ddc53416beb65b83a3ea6d7d13738dde75eeb2c89679/watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8", size = 96390, upload-time = "2024-11-01T14:06:49.325Z" },
{ url = "https://files.pythonhosted.org/packages/9c/62/d2b21bc4e706d3a9d467561f487c2938cbd881c69f3808c43ac1ec242391/watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a", size = 88386, upload-time = "2024-11-01T14:06:50.536Z" },
{ url = "https://files.pythonhosted.org/packages/ea/22/1c90b20eda9f4132e4603a26296108728a8bfe9584b006bd05dd94548853/watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c", size = 89017, upload-time = "2024-11-01T14:06:51.717Z" },
{ url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" }, { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" },
{ url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" }, { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" },
{ url = "https://files.pythonhosted.org/packages/5b/79/69f2b0e8d3f2afd462029031baafb1b75d11bb62703f0e1022b2e54d49ee/watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa", size = 87903, upload-time = "2024-11-01T14:06:57.052Z" },
{ url = "https://files.pythonhosted.org/packages/e2/2b/dc048dd71c2e5f0f7ebc04dd7912981ec45793a03c0dc462438e0591ba5d/watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e", size = 88381, upload-time = "2024-11-01T14:06:58.193Z" },
{ url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" },
{ url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" },
{ url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" },
@@ -1195,4 +1192,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" }, { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" },
{ url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" }, { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" },
{ url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" }, { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" },
{ url = "https://files.pythonhosted.org/packages/14/0d/d0a405dad6ab6f9f759c26d866cca66cb209bff6f8db656074d662a953dd/zstandard-0.25.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b9af1fe743828123e12b41dd8091eca1074d0c1569cc42e6e1eee98027f2bbd0", size = 795263, upload-time = "2025-09-14T22:18:21.683Z" },
{ url = "https://files.pythonhosted.org/packages/ca/aa/ceb8d79cbad6dabd4cb1178ca853f6a4374d791c5e0241a0988173e2a341/zstandard-0.25.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b14abacf83dfb5c25eb4e4a79520de9e7e205f72c9ee7702f91233ae57d33a2", size = 640560, upload-time = "2025-09-14T22:18:22.867Z" },
{ url = "https://files.pythonhosted.org/packages/88/cd/2cf6d476131b509cc122d25d3416a2d0aa17687ddbada7599149f9da620e/zstandard-0.25.0-cp39-cp39-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:a51ff14f8017338e2f2e5dab738ce1ec3b5a851f23b18c1ae1359b1eecbee6df", size = 5344244, upload-time = "2025-09-14T22:18:24.724Z" },
{ url = "https://files.pythonhosted.org/packages/5c/71/e14820b61a1c137966b7667b400b72fa4a45c836257e443f3d77607db268/zstandard-0.25.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3b870ce5a02d4b22286cf4944c628e0f0881b11b3f14667c1d62185a99e04f53", size = 5054550, upload-time = "2025-09-14T22:18:26.445Z" },
{ url = "https://files.pythonhosted.org/packages/f9/ce/26dc5a6fa956be41d0e984909224ed196ee6f91d607f0b3fd84577741a77/zstandard-0.25.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:05353cef599a7b0b98baca9b068dd36810c3ef0f42bf282583f438caf6ddcee3", size = 5401150, upload-time = "2025-09-14T22:18:28.745Z" },
{ url = "https://files.pythonhosted.org/packages/f2/1b/402cab5edcfe867465daf869d5ac2a94930931c0989633bc01d6a7d8bd68/zstandard-0.25.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:19796b39075201d51d5f5f790bf849221e58b48a39a5fc74837675d8bafc7362", size = 5448595, upload-time = "2025-09-14T22:18:30.475Z" },
{ url = "https://files.pythonhosted.org/packages/86/b2/fc50c58271a1ead0e5a0a0e6311f4b221f35954dce438ce62751b3af9b68/zstandard-0.25.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:53e08b2445a6bc241261fea89d065536f00a581f02535f8122eba42db9375530", size = 5555290, upload-time = "2025-09-14T22:18:32.336Z" },
{ url = "https://files.pythonhosted.org/packages/d2/20/5f72d6ba970690df90fdd37195c5caa992e70cb6f203f74cc2bcc0b8cf30/zstandard-0.25.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1f3689581a72eaba9131b1d9bdbfe520ccd169999219b41000ede2fca5c1bfdb", size = 5043898, upload-time = "2025-09-14T22:18:34.215Z" },
{ url = "https://files.pythonhosted.org/packages/e4/f1/131a0382b8b8d11e84690574645f528f5c5b9343e06cefd77f5fd730cd2b/zstandard-0.25.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d8c56bb4e6c795fc77d74d8e8b80846e1fb8292fc0b5060cd8131d522974b751", size = 5571173, upload-time = "2025-09-14T22:18:36.117Z" },
{ url = "https://files.pythonhosted.org/packages/53/f6/2a37931023f737fd849c5c28def57442bbafadb626da60cf9ed58461fe24/zstandard-0.25.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:53f94448fe5b10ee75d246497168e5825135d54325458c4bfffbaafabcc0a577", size = 4958261, upload-time = "2025-09-14T22:18:38.098Z" },
{ url = "https://files.pythonhosted.org/packages/b5/52/ca76ed6dbfd8845a5563d3af4e972da3b9da8a9308ca6b56b0b929d93e23/zstandard-0.25.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c2ba942c94e0691467ab901fc51b6f2085ff48f2eea77b1a48240f011e8247c7", size = 5265680, upload-time = "2025-09-14T22:18:39.834Z" },
{ url = "https://files.pythonhosted.org/packages/7a/59/edd117dedb97a768578b49fb2f1156defb839d1aa5b06200a62be943667f/zstandard-0.25.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:07b527a69c1e1c8b5ab1ab14e2afe0675614a09182213f21a0717b62027b5936", size = 5439747, upload-time = "2025-09-14T22:18:41.647Z" },
{ url = "https://files.pythonhosted.org/packages/75/71/c2e9234643dcfbd6c5e975e9a2b0050e1b2afffda6c3a959e1b87997bc80/zstandard-0.25.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:51526324f1b23229001eb3735bc8c94f9c578b1bd9e867a0a646a3b17109f388", size = 5818805, upload-time = "2025-09-14T22:18:43.602Z" },
{ url = "https://files.pythonhosted.org/packages/f5/93/8ebc19f0a31c44ea0e7348f9b0d4b326ed413b6575a3c6ff4ed50222abb6/zstandard-0.25.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89c4b48479a43f820b749df49cd7ba2dbc2b1b78560ecb5ab52985574fd40b27", size = 5362280, upload-time = "2025-09-14T22:18:45.625Z" },
{ url = "https://files.pythonhosted.org/packages/b8/e9/29cc59d4a9d51b3fd8b477d858d0bd7ab627f700908bf1517f46ddd470ae/zstandard-0.25.0-cp39-cp39-win32.whl", hash = "sha256:1cd5da4d8e8ee0e88be976c294db744773459d51bb32f707a0f166e5ad5c8649", size = 436460, upload-time = "2025-09-14T22:18:49.077Z" },
{ url = "https://files.pythonhosted.org/packages/41/b5/bc7a92c116e2ef32dc8061c209d71e97ff6df37487d7d39adb51a343ee89/zstandard-0.25.0-cp39-cp39-win_amd64.whl", hash = "sha256:37daddd452c0ffb65da00620afb8e17abd4adaae6ce6310702841760c2c26860", size = 506097, upload-time = "2025-09-14T22:18:47.342Z" },
] ]
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024 LangChain, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -1,6 +1,5 @@
from __future__ import annotations from __future__ import annotations
import json
import random import random
import sqlite3 import sqlite3
import threading import threading
@@ -185,7 +184,7 @@ class SqliteSaver(BaseCheckpointSaver[str]):
"""Get a checkpoint tuple from the database. """Get a checkpoint tuple from the database.
This method retrieves a checkpoint tuple from the SQLite database based on the This method retrieves a checkpoint tuple from the SQLite database based on the
provided config. If the config contains a `checkpoint_id` key, the checkpoint with provided config. If the config contains a "checkpoint_id" key, the checkpoint with
the matching thread ID and checkpoint ID is retrieved. Otherwise, the latest checkpoint the matching thread ID and checkpoint ID is retrieved. Otherwise, the latest checkpoint
for the given thread ID is retrieved. for the given thread ID is retrieved.
@@ -193,7 +192,7 @@ class SqliteSaver(BaseCheckpointSaver[str]):
config: The config to use for retrieving the checkpoint. config: The config to use for retrieving the checkpoint.
Returns: Returns:
The retrieved checkpoint tuple, or None if no matching checkpoint was found. Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.
Examples: Examples:
@@ -266,7 +265,9 @@ class SqliteSaver(BaseCheckpointSaver[str]):
self.serde.loads_typed((type, checkpoint)), self.serde.loads_typed((type, checkpoint)),
cast( cast(
CheckpointMetadata, CheckpointMetadata,
json.loads(metadata) if metadata is not None else {}, self.jsonplus_serde.loads(metadata)
if metadata is not None
else {},
), ),
( (
{ {
@@ -300,12 +301,12 @@ class SqliteSaver(BaseCheckpointSaver[str]):
Args: Args:
config: The config to use for listing the checkpoints. config: The config to use for listing the checkpoints.
filter: Additional filtering criteria for metadata. filter: Additional filtering criteria for metadata. Defaults to None.
before: If provided, only checkpoints before the specified checkpoint ID are returned. before: If provided, only checkpoints before the specified checkpoint ID are returned. Defaults to None.
limit: The maximum number of checkpoints to return. limit: The maximum number of checkpoints to return. Defaults to None.
Yields: Yields:
An iterator of checkpoint tuples. Iterator[CheckpointTuple]: An iterator of checkpoint tuples.
Examples: Examples:
>>> from langgraph.checkpoint.sqlite import SqliteSaver >>> from langgraph.checkpoint.sqlite import SqliteSaver
@@ -357,7 +358,9 @@ class SqliteSaver(BaseCheckpointSaver[str]):
self.serde.loads_typed((type, checkpoint)), self.serde.loads_typed((type, checkpoint)),
cast( cast(
CheckpointMetadata, CheckpointMetadata,
json.loads(metadata) if metadata is not None else {}, self.jsonplus_serde.loads(metadata)
if metadata is not None
else {},
), ),
( (
{ {
@@ -410,9 +413,9 @@ class SqliteSaver(BaseCheckpointSaver[str]):
thread_id = config["configurable"]["thread_id"] thread_id = config["configurable"]["thread_id"]
checkpoint_ns = config["configurable"]["checkpoint_ns"] checkpoint_ns = config["configurable"]["checkpoint_ns"]
type_, serialized_checkpoint = self.serde.dumps_typed(checkpoint) type_, serialized_checkpoint = self.serde.dumps_typed(checkpoint)
serialized_metadata = json.dumps( serialized_metadata = self.jsonplus_serde.dumps(
get_checkpoint_metadata(config, metadata), ensure_ascii=False get_checkpoint_metadata(config, metadata)
).encode("utf-8", "ignore") )
with self.cursor() as cur: with self.cursor() as cur:
cur.execute( cur.execute(
"INSERT OR REPLACE INTO checkpoints (thread_id, checkpoint_ns, checkpoint_id, parent_checkpoint_id, type, checkpoint, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)", "INSERT OR REPLACE INTO checkpoints (thread_id, checkpoint_ns, checkpoint_id, parent_checkpoint_id, type, checkpoint, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)",
@@ -1,11 +1,10 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
import json
import random import random
from collections.abc import AsyncIterator, Callable, Iterator, Sequence from collections.abc import AsyncIterator, Iterator, Sequence
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from typing import Any, TypeVar, cast from typing import Any, Callable, TypeVar, cast
import aiosqlite import aiosqlite
from langchain_core.runnables import RunnableConfig from langchain_core.runnables import RunnableConfig
@@ -140,7 +139,7 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
"""Get a checkpoint tuple from the database. """Get a checkpoint tuple from the database.
This method retrieves a checkpoint tuple from the SQLite database based on the This method retrieves a checkpoint tuple from the SQLite database based on the
provided config. If the config contains a `checkpoint_id` key, the checkpoint with provided config. If the config contains a "checkpoint_id" key, the checkpoint with
the matching thread ID and checkpoint ID is retrieved. Otherwise, the latest checkpoint the matching thread ID and checkpoint ID is retrieved. Otherwise, the latest checkpoint
for the given thread ID is retrieved. for the given thread ID is retrieved.
@@ -148,7 +147,7 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
config: The config to use for retrieving the checkpoint. config: The config to use for retrieving the checkpoint.
Returns: Returns:
The retrieved checkpoint tuple, or None if no matching checkpoint was found. Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.
""" """
try: try:
# check if we are in the main thread, only bg threads can block # check if we are in the main thread, only bg threads can block
@@ -182,11 +181,11 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
Args: Args:
config: Base configuration for filtering checkpoints. config: Base configuration for filtering checkpoints.
filter: Additional filtering criteria for metadata. filter: Additional filtering criteria for metadata.
before: If provided, only checkpoints before the specified checkpoint ID are returned. before: If provided, only checkpoints before the specified checkpoint ID are returned. Defaults to None.
limit: Maximum number of checkpoints to return. limit: Maximum number of checkpoints to return.
Yields: Yields:
An iterator of matching checkpoint tuples. Iterator[CheckpointTuple]: An iterator of matching checkpoint tuples.
""" """
try: try:
# check if we are in the main thread, only bg threads can block # check if we are in the main thread, only bg threads can block
@@ -317,7 +316,7 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
"""Get a checkpoint tuple from the database asynchronously. """Get a checkpoint tuple from the database asynchronously.
This method retrieves a checkpoint tuple from the SQLite database based on the This method retrieves a checkpoint tuple from the SQLite database based on the
provided config. If the config contains a `checkpoint_id` key, the checkpoint with provided config. If the config contains a "checkpoint_id" key, the checkpoint with
the matching thread ID and checkpoint ID is retrieved. Otherwise, the latest checkpoint the matching thread ID and checkpoint ID is retrieved. Otherwise, the latest checkpoint
for the given thread ID is retrieved. for the given thread ID is retrieved.
@@ -325,7 +324,7 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
config: The config to use for retrieving the checkpoint. config: The config to use for retrieving the checkpoint.
Returns: Returns:
The retrieved checkpoint tuple, or None if no matching checkpoint was found. Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.
""" """
await self.setup() await self.setup()
checkpoint_ns = config["configurable"].get("checkpoint_ns", "") checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
@@ -378,7 +377,9 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
self.serde.loads_typed((type, checkpoint)), self.serde.loads_typed((type, checkpoint)),
cast( cast(
CheckpointMetadata, CheckpointMetadata,
(json.loads(metadata) if metadata is not None else {}), self.jsonplus_serde.loads(metadata)
if metadata is not None
else {},
), ),
( (
{ {
@@ -413,11 +414,11 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
Args: Args:
config: Base configuration for filtering checkpoints. config: Base configuration for filtering checkpoints.
filter: Additional filtering criteria for metadata. filter: Additional filtering criteria for metadata.
before: If provided, only checkpoints before the specified checkpoint ID are returned. before: If provided, only checkpoints before the specified checkpoint ID are returned. Defaults to None.
limit: Maximum number of checkpoints to return. limit: Maximum number of checkpoints to return.
Yields: Yields:
An asynchronous iterator of matching checkpoint tuples. AsyncIterator[CheckpointTuple]: An asynchronous iterator of matching checkpoint tuples.
""" """
await self.setup() await self.setup()
where, params = search_where(config, filter, before) where, params = search_where(config, filter, before)
@@ -456,7 +457,9 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
self.serde.loads_typed((type, checkpoint)), self.serde.loads_typed((type, checkpoint)),
cast( cast(
CheckpointMetadata, CheckpointMetadata,
(json.loads(metadata) if metadata is not None else {}), self.jsonplus_serde.loads(metadata)
if metadata is not None
else {},
), ),
( (
{ {
@@ -500,9 +503,9 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
thread_id = config["configurable"]["thread_id"] thread_id = config["configurable"]["thread_id"]
checkpoint_ns = config["configurable"]["checkpoint_ns"] checkpoint_ns = config["configurable"]["checkpoint_ns"]
type_, serialized_checkpoint = self.serde.dumps_typed(checkpoint) type_, serialized_checkpoint = self.serde.dumps_typed(checkpoint)
serialized_metadata = json.dumps( serialized_metadata = self.jsonplus_serde.dumps(
get_checkpoint_metadata(config, metadata), ensure_ascii=False get_checkpoint_metadata(config, metadata)
).encode("utf-8", "ignore") )
async with ( async with (
self.lock, self.lock,
self.conn.execute( self.conn.execute(
@@ -3,10 +3,10 @@ from __future__ import annotations
import asyncio import asyncio
import logging import logging
from collections import defaultdict from collections import defaultdict
from collections.abc import AsyncIterator, Callable, Iterable, Sequence from collections.abc import AsyncIterator, Iterable, Sequence
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from types import TracebackType from types import TracebackType
from typing import Any, cast from typing import Any, Callable, cast
import aiosqlite import aiosqlite
import orjson import orjson
@@ -303,7 +303,7 @@ class AsyncSqliteStore(AsyncBatchedBaseStore, BaseSqliteStore):
Args: Args:
timeout: Maximum time to wait for the task to stop, in seconds. timeout: Maximum time to wait for the task to stop, in seconds.
If `None`, wait indefinitely. If None, wait indefinitely.
Returns: Returns:
bool: True if the task was successfully stopped or wasn't running, bool: True if the task was successfully stopped or wasn't running,
@@ -484,7 +484,7 @@ class AsyncSqliteStore(AsyncBatchedBaseStore, BaseSqliteStore):
# Convert vectors to SQLite-friendly format # Convert vectors to SQLite-friendly format
vector_params = [] vector_params = []
for (ns, k, pathname, _), vector in zip(txt_params, vectors, strict=False): for (ns, k, pathname, _), vector in zip(txt_params, vectors):
vector_params.extend( vector_params.extend(
[ns, k, pathname, sqlite_vec.serialize_float32(vector)] [ns, k, pathname, sqlite_vec.serialize_float32(vector)]
) )
@@ -517,9 +517,7 @@ class AsyncSqliteStore(AsyncBatchedBaseStore, BaseSqliteStore):
[query for _, query in embedding_requests] [query for _, query in embedding_requests]
) )
for (embed_req_idx, _), embedding in zip( for (embed_req_idx, _), embedding in zip(embedding_requests, vectors):
embedding_requests, vectors, strict=False
):
# Find the corresponding query in prepared_queries # Find the corresponding query in prepared_queries
# The embed_req_idx is the original index in search_ops, which should map to prepared_queries # The embed_req_idx is the original index in search_ops, which should map to prepared_queries
if embed_req_idx < len(prepared_queries): if embed_req_idx < len(prepared_queries):
@@ -533,7 +531,7 @@ class AsyncSqliteStore(AsyncBatchedBaseStore, BaseSqliteStore):
) )
for (original_op_idx, _), (query, params, needs_refresh) in zip( for (original_op_idx, _), (query, params, needs_refresh) in zip(
search_ops, prepared_queries, strict=False search_ops, prepared_queries
): ):
await cur.execute(query, params) await cur.execute(query, params)
rows = await cur.fetchall() rows = await cur.fetchall()
@@ -616,7 +614,7 @@ class AsyncSqliteStore(AsyncBatchedBaseStore, BaseSqliteStore):
cur: Database cursor. cur: Database cursor.
""" """
queries = self._get_batch_list_namespaces_queries(list_ops) queries = self._get_batch_list_namespaces_queries(list_ops)
for (query, params), (idx, _) in zip(queries, list_ops, strict=False): for (query, params), (idx, _) in zip(queries, list_ops):
await cur.execute(query, params) await cur.execute(query, params)
rows = await cur.fetchall() rows = await cur.fetchall()
@@ -7,9 +7,9 @@ import re
import sqlite3 import sqlite3
import threading import threading
from collections import defaultdict from collections import defaultdict
from collections.abc import Callable, Iterable, Iterator, Sequence from collections.abc import Iterable, Iterator, Sequence
from contextlib import contextmanager from contextlib import contextmanager
from typing import Any, Literal, NamedTuple, cast from typing import Any, Callable, Literal, NamedTuple, cast
import orjson import orjson
import sqlite_vec # type: ignore[import-untyped] import sqlite_vec # type: ignore[import-untyped]
@@ -232,7 +232,7 @@ class BaseSqliteStore:
results = [] results = []
for namespace, items in namespace_groups.items(): for namespace, items in namespace_groups.items():
_, keys = zip(*items, strict=False) _, keys = zip(*items)
this_refresh_ttls = refresh_ttls[namespace] this_refresh_ttls = refresh_ttls[namespace]
refresh_ttl_any = any(this_refresh_ttls) refresh_ttl_any = any(this_refresh_ttls)
@@ -829,7 +829,7 @@ class SqliteStore(BaseSqliteStore, BaseStore):
results = [] results = []
for namespace, items in namespace_groups.items(): for namespace, items in namespace_groups.items():
_, keys = zip(*items, strict=False) _, keys = zip(*items)
this_refresh_ttls = refresh_ttls[namespace] this_refresh_ttls = refresh_ttls[namespace]
refresh_ttl_any = any(this_refresh_ttls) refresh_ttl_any = any(this_refresh_ttls)
@@ -1156,7 +1156,7 @@ class SqliteStore(BaseSqliteStore, BaseStore):
Args: Args:
timeout: Maximum time to wait for the thread to stop, in seconds. timeout: Maximum time to wait for the thread to stop, in seconds.
If `None`, wait indefinitely. If None, wait indefinitely.
Returns: Returns:
bool: True if the thread was successfully stopped or wasn't running, bool: True if the thread was successfully stopped or wasn't running,
@@ -1304,7 +1304,7 @@ class SqliteStore(BaseSqliteStore, BaseStore):
# Convert vectors to SQLite-friendly format # Convert vectors to SQLite-friendly format
vector_params = [] vector_params = []
for (ns, k, pathname, _), vector in zip(txt_params, vectors, strict=False): for (ns, k, pathname, _), vector in zip(txt_params, vectors):
vector_params.extend( vector_params.extend(
[ns, k, pathname, sqlite_vec.serialize_float32(vector)] [ns, k, pathname, sqlite_vec.serialize_float32(vector)]
) )
@@ -1332,9 +1332,7 @@ class SqliteStore(BaseSqliteStore, BaseStore):
) )
# Replace placeholders with actual embeddings # Replace placeholders with actual embeddings
for (embed_req_idx, _), embedding in zip( for (embed_req_idx, _), embedding in zip(embedding_requests, embeddings):
embedding_requests, embeddings, strict=False
):
if embed_req_idx < len(prepared_queries): if embed_req_idx < len(prepared_queries):
_params_list: list = prepared_queries[embed_req_idx][1] _params_list: list = prepared_queries[embed_req_idx][1]
for i, param in enumerate(_params_list): for i, param in enumerate(_params_list):
@@ -1346,7 +1344,7 @@ class SqliteStore(BaseSqliteStore, BaseStore):
) )
for (original_op_idx, _), (query, params, needs_refresh) in zip( for (original_op_idx, _), (query, params, needs_refresh) in zip(
search_ops, prepared_queries, strict=False search_ops, prepared_queries
): ):
cur.execute(query, params) cur.execute(query, params)
rows = cur.fetchall() rows = cur.fetchall()
@@ -1419,7 +1417,7 @@ class SqliteStore(BaseSqliteStore, BaseStore):
cur: sqlite3.Cursor, cur: sqlite3.Cursor,
) -> None: ) -> None:
queries = self._get_batch_list_namespaces_queries(list_ops) queries = self._get_batch_list_namespaces_queries(list_ops)
for (query, params), (idx, _) in zip(queries, list_ops, strict=False): for (query, params), (idx, _) in zip(queries, list_ops):
cur.execute(query, params) cur.execute(query, params)
results[idx] = [_decode_ns_text(row[0]) for row in cur.fetchall()] results[idx] = [_decode_ns_text(row[0]) for row in cur.fetchall()]
+8 -19
View File
@@ -4,43 +4,34 @@ build-backend = "hatchling.build"
[project] [project]
name = "langgraph-checkpoint-sqlite" name = "langgraph-checkpoint-sqlite"
version = "3.0.0" version = "2.0.11"
description = "Library with a SQLite implementation of LangGraph checkpoint saver." description = "Library with a SQLite implementation of LangGraph checkpoint saver."
authors = [] authors = []
requires-python = ">=3.10" requires-python = ">=3.9"
readme = "README.md" readme = "README.md"
license = "MIT" license = "MIT"
license-files = ['LICENSE'] license-files = ['LICENSE']
dependencies = [ dependencies = [
"langgraph-checkpoint>=3,<4.0.0", "langgraph-checkpoint>=2.0.21,<3.0.0",
"aiosqlite>=0.20", "aiosqlite>=0.20",
"sqlite-vec>=0.1.6", "sqlite-vec>=0.1.6",
] ]
[project.urls] [project.urls]
Source = "https://github.com/langchain-ai/langgraph/tree/main/libs/checkpoint-sqlite" Repository = "https://www.github.com/langchain-ai/langgraph"
Twitter = "https://x.com/LangChainAI"
Slack = "https://www.langchain.com/join-community"
Reddit = "https://www.reddit.com/r/LangChain/"
[dependency-groups] [dependency-groups]
test = [ dev = [
"ruff",
"codespell",
"pytest", "pytest",
"pytest-asyncio", "pytest-asyncio",
"pytest-mock", "pytest-mock",
"pytest-watcher", "pytest-watcher",
"mypy",
"langgraph-checkpoint", "langgraph-checkpoint",
"pytest-retry>=1.7.0", "pytest-retry>=1.7.0",
] ]
lint = [
"ruff",
"codespell",
"mypy",
]
dev = [
{include-group = "test"},
{include-group = "lint"},
]
[tool.uv] [tool.uv]
default-groups = ['dev'] default-groups = ['dev']
@@ -62,10 +53,8 @@ lint.select = [
"UP", # pyupgrade "UP", # pyupgrade
"B", # flake8-bugbear "B", # flake8-bugbear
"I", # isort "I", # isort
"UP", # pyupgrade
] ]
lint.ignore = ["E501", "B008"] lint.ignore = ["E501", "B008"]
target-version = "py310"
[tool.pytest-watcher] [tool.pytest-watcher]
now = true now = true
@@ -5,7 +5,7 @@ import tempfile
import uuid import uuid
from collections.abc import AsyncIterator, Generator, Iterable from collections.abc import AsyncIterator, Generator, Iterable
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from typing import cast from typing import Optional, Union, cast
import pytest import pytest
from langgraph.store.base import ( from langgraph.store.base import (
@@ -51,7 +51,7 @@ def fake_embeddings() -> CharacterEmbeddings:
async def create_vector_store( async def create_vector_store(
fake_embeddings: CharacterEmbeddings, fake_embeddings: CharacterEmbeddings,
conn_string: str = ":memory:", conn_string: str = ":memory:",
text_fields: list[str] | None = None, text_fields: Optional[list[str]] = None,
) -> AsyncIterator[AsyncSqliteStore]: ) -> AsyncIterator[AsyncSqliteStore]:
"""Create an AsyncSqliteStore with vector search capabilities.""" """Create an AsyncSqliteStore with vector search capabilities."""
index_config: SqliteIndexConfig = { index_config: SqliteIndexConfig = {
@@ -168,7 +168,7 @@ async def test_abatch_order(store: AsyncSqliteStore) -> None:
] ]
results = await store.abatch( results = await store.abatch(
cast(Iterable[GetOp | PutOp | SearchOp | ListNamespacesOp], ops) cast(Iterable[Union[GetOp, PutOp, SearchOp, ListNamespacesOp]], ops)
) )
assert len(results) == 5 assert len(results) == 5
assert isinstance(results[0], Item) assert isinstance(results[0], Item)
@@ -193,7 +193,7 @@ async def test_abatch_order(store: AsyncSqliteStore) -> None:
] ]
results_reordered = await store.abatch( results_reordered = await store.abatch(
cast(Iterable[GetOp | PutOp | SearchOp | ListNamespacesOp], ops_reordered) cast(Iterable[Union[GetOp, PutOp, SearchOp, ListNamespacesOp]], ops_reordered)
) )
assert len(results_reordered) == 5 assert len(results_reordered) == 5
assert isinstance(results_reordered[0], list) assert isinstance(results_reordered[0], list)
@@ -681,7 +681,7 @@ async def test_search_items(
fake_embeddings, text_fields=["key0", "key1", "key3"] fake_embeddings, text_fields=["key0", "key1", "key3"]
) as store: ) as store:
# Insert test data # Insert test data
for ns, item in zip(test_namespaces, test_items, strict=False): for ns, item in zip(test_namespaces, test_items):
key = f"item_{ns[-1]}" key = f"item_{ns[-1]}"
await store.aput(ns, key, item) await store.aput(ns, key, item)
+7 -7
View File
@@ -5,7 +5,7 @@ import tempfile
import uuid import uuid
from collections.abc import Generator, Iterable from collections.abc import Generator, Iterable
from contextlib import contextmanager from contextlib import contextmanager
from typing import Any, Literal, cast from typing import Any, Literal, Optional, Union, cast
import pytest import pytest
from langchain_core.embeddings import Embeddings from langchain_core.embeddings import Embeddings
@@ -110,7 +110,7 @@ VECTOR_TYPES = ["cosine"] # SQLite only supports cosine similarity
@contextmanager @contextmanager
def create_vector_store( def create_vector_store(
fake_embeddings: CharacterEmbeddings, fake_embeddings: CharacterEmbeddings,
text_fields: list[str] | None = None, text_fields: Optional[list[str]] = None,
distance_type: str = "cosine", distance_type: str = "cosine",
conn_type: Literal["memory", "file"] = "memory", conn_type: Literal["memory", "file"] = "memory",
) -> Generator[SqliteStore, None, None]: ) -> Generator[SqliteStore, None, None]:
@@ -153,7 +153,7 @@ def test_batch_order(store: SqliteStore) -> None:
] ]
results = store.batch( results = store.batch(
cast(Iterable[GetOp | PutOp | SearchOp | ListNamespacesOp], ops) cast(Iterable[Union[GetOp, PutOp, SearchOp, ListNamespacesOp]], ops)
) )
assert len(results) == 5 assert len(results) == 5
assert isinstance(results[0], Item) assert isinstance(results[0], Item)
@@ -182,7 +182,7 @@ def test_batch_order(store: SqliteStore) -> None:
] ]
results_reordered = store.batch( results_reordered = store.batch(
cast(Iterable[GetOp | PutOp | SearchOp | ListNamespacesOp], ops_reordered) cast(Iterable[Union[GetOp, PutOp, SearchOp, ListNamespacesOp]], ops_reordered)
) )
assert len(results_reordered) == 5 assert len(results_reordered) == 5
assert isinstance(results_reordered[0], list) assert isinstance(results_reordered[0], list)
@@ -301,7 +301,7 @@ def test_batch_list_namespaces_ops(store: SqliteStore) -> None:
] ]
results = store.batch( results = store.batch(
cast(Iterable[GetOp | PutOp | SearchOp | ListNamespacesOp], ops) cast(Iterable[Union[GetOp, PutOp, SearchOp, ListNamespacesOp]], ops)
) )
assert len(results) == 3 assert len(results) == 3
@@ -778,7 +778,7 @@ def _cosine_similarity(X: list[float], Y: list[list[float]]) -> list[float]:
similarities = [] similarities = []
for y in Y: for y in Y:
dot_product = sum(a * b for a, b in zip(X, y, strict=False)) dot_product = sum(a * b for a, b in zip(X, y))
norm1 = sum(a * a for a in X) ** 0.5 norm1 = sum(a * a for a in X) ** 0.5
norm2 = sum(a * a for a in y) ** 0.5 norm2 = sum(a * a for a in y) ** 0.5
similarity = dot_product / (norm1 * norm2) if norm1 > 0 and norm2 > 0 else 0.0 similarity = dot_product / (norm1 * norm2) if norm1 > 0 and norm2 > 0 else 0.0
@@ -1011,7 +1011,7 @@ def test_search_items(
fake_embeddings, text_fields=["key0", "key1", "key3"] fake_embeddings, text_fields=["key0", "key1", "key3"]
) as store: ) as store:
# Insert test data # Insert test data
for ns, item in zip(test_namespaces, test_items, strict=False): for ns, item in zip(test_namespaces, test_items):
key = f"item_{ns[-1]}" key = f"item_{ns[-1]}"
store.put(ns, key, item) store.put(ns, key, item)
+212 -206
View File
@@ -1,6 +1,6 @@
version = 1 version = 1
revision = 3 revision = 3
requires-python = ">=3.10" requires-python = ">=3.9"
[[package]] [[package]]
name = "aiosqlite" name = "aiosqlite"
@@ -117,6 +117,17 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" },
{ url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" },
{ url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" },
{ url = "https://files.pythonhosted.org/packages/c2/ca/9a0983dd5c8e9733565cf3db4df2b0a2e9a82659fd8aa2a868ac6e4a991f/charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05", size = 207520, upload-time = "2025-08-09T07:57:11.026Z" },
{ url = "https://files.pythonhosted.org/packages/39/c6/99271dc37243a4f925b09090493fb96c9333d7992c6187f5cfe5312008d2/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e", size = 147307, upload-time = "2025-08-09T07:57:12.4Z" },
{ url = "https://files.pythonhosted.org/packages/e4/69/132eab043356bba06eb333cc2cc60c6340857d0a2e4ca6dc2b51312886b3/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99", size = 160448, upload-time = "2025-08-09T07:57:13.712Z" },
{ url = "https://files.pythonhosted.org/packages/04/9a/914d294daa4809c57667b77470533e65def9c0be1ef8b4c1183a99170e9d/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7", size = 157758, upload-time = "2025-08-09T07:57:14.979Z" },
{ url = "https://files.pythonhosted.org/packages/b0/a8/6f5bcf1bcf63cb45625f7c5cadca026121ff8a6c8a3256d8d8cd59302663/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7", size = 152487, upload-time = "2025-08-09T07:57:16.332Z" },
{ url = "https://files.pythonhosted.org/packages/c4/72/d3d0e9592f4e504f9dea08b8db270821c909558c353dc3b457ed2509f2fb/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19", size = 150054, upload-time = "2025-08-09T07:57:17.576Z" },
{ url = "https://files.pythonhosted.org/packages/20/30/5f64fe3981677fe63fa987b80e6c01042eb5ff653ff7cec1b7bd9268e54e/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312", size = 161703, upload-time = "2025-08-09T07:57:20.012Z" },
{ url = "https://files.pythonhosted.org/packages/e1/ef/dd08b2cac9284fd59e70f7d97382c33a3d0a926e45b15fc21b3308324ffd/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc", size = 159096, upload-time = "2025-08-09T07:57:21.329Z" },
{ url = "https://files.pythonhosted.org/packages/45/8c/dcef87cfc2b3f002a6478f38906f9040302c68aebe21468090e39cde1445/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34", size = 153852, upload-time = "2025-08-09T07:57:22.608Z" },
{ url = "https://files.pythonhosted.org/packages/63/86/9cbd533bd37883d467fcd1bd491b3547a3532d0fbb46de2b99feeebf185e/charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432", size = 99840, upload-time = "2025-08-09T07:57:23.883Z" },
{ url = "https://files.pythonhosted.org/packages/ce/d6/7e805c8e5c46ff9729c49950acc4ee0aeb55efb8b3a56687658ad10c3216/charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca", size = 107438, upload-time = "2025-08-09T07:57:25.287Z" },
{ url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" },
] ]
@@ -246,7 +257,7 @@ wheels = [
[[package]] [[package]]
name = "langgraph-checkpoint" name = "langgraph-checkpoint"
version = "3.0.1" version = "2.1.2"
source = { editable = "../checkpoint" } source = { editable = "../checkpoint" }
dependencies = [ dependencies = [
{ name = "langchain-core" }, { name = "langchain-core" },
@@ -256,7 +267,7 @@ dependencies = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "langchain-core", specifier = ">=0.2.38" }, { name = "langchain-core", specifier = ">=0.2.38" },
{ name = "ormsgpack", specifier = ">=1.12.0" }, { name = "ormsgpack", specifier = ">=1.10.0" },
] ]
[package.metadata.requires-dev] [package.metadata.requires-dev]
@@ -274,26 +285,10 @@ dev = [
{ name = "redis" }, { name = "redis" },
{ name = "ruff" }, { name = "ruff" },
] ]
lint = [
{ name = "codespell" },
{ name = "mypy" },
{ name = "ruff" },
]
test = [
{ name = "dataclasses-json" },
{ name = "numpy" },
{ name = "pandas" },
{ name = "pandas-stubs", specifier = ">=2.2.2.240807" },
{ name = "pytest" },
{ name = "pytest-asyncio" },
{ name = "pytest-mock" },
{ name = "pytest-watcher" },
{ name = "redis" },
]
[[package]] [[package]]
name = "langgraph-checkpoint-sqlite" name = "langgraph-checkpoint-sqlite"
version = "3.0.0" version = "2.0.11"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "aiosqlite" }, { name = "aiosqlite" },
@@ -313,19 +308,6 @@ dev = [
{ name = "pytest-watcher" }, { name = "pytest-watcher" },
{ name = "ruff" }, { name = "ruff" },
] ]
lint = [
{ name = "codespell" },
{ name = "mypy" },
{ name = "ruff" },
]
test = [
{ name = "langgraph-checkpoint" },
{ name = "pytest" },
{ name = "pytest-asyncio" },
{ name = "pytest-mock" },
{ name = "pytest-retry" },
{ name = "pytest-watcher" },
]
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
@@ -346,19 +328,6 @@ dev = [
{ name = "pytest-watcher" }, { name = "pytest-watcher" },
{ name = "ruff" }, { name = "ruff" },
] ]
lint = [
{ name = "codespell" },
{ name = "mypy" },
{ name = "ruff" },
]
test = [
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
{ name = "pytest" },
{ name = "pytest-asyncio" },
{ name = "pytest-mock" },
{ name = "pytest-retry", specifier = ">=1.7.0" },
{ name = "pytest-watcher" },
]
[[package]] [[package]]
name = "langsmith" name = "langsmith"
@@ -420,6 +389,12 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/5b/11/040983fad5132d85914c874a2836252bbc57832065548885b5bb5b0d4359/mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb", size = 13326683, upload-time = "2025-09-19T00:09:55.572Z" }, { url = "https://files.pythonhosted.org/packages/5b/11/040983fad5132d85914c874a2836252bbc57832065548885b5bb5b0d4359/mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb", size = 13326683, upload-time = "2025-09-19T00:09:55.572Z" },
{ url = "https://files.pythonhosted.org/packages/e9/ba/89b2901dd77414dd7a8c8729985832a5735053be15b744c18e4586e506ef/mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075", size = 13514749, upload-time = "2025-09-19T00:10:44.827Z" }, { url = "https://files.pythonhosted.org/packages/e9/ba/89b2901dd77414dd7a8c8729985832a5735053be15b744c18e4586e506ef/mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075", size = 13514749, upload-time = "2025-09-19T00:10:44.827Z" },
{ url = "https://files.pythonhosted.org/packages/25/bc/cc98767cffd6b2928ba680f3e5bc969c4152bf7c2d83f92f5a504b92b0eb/mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf", size = 9982959, upload-time = "2025-09-19T00:10:37.344Z" }, { url = "https://files.pythonhosted.org/packages/25/bc/cc98767cffd6b2928ba680f3e5bc969c4152bf7c2d83f92f5a504b92b0eb/mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf", size = 9982959, upload-time = "2025-09-19T00:10:37.344Z" },
{ url = "https://files.pythonhosted.org/packages/3f/a6/490ff491d8ecddf8ab91762d4f67635040202f76a44171420bcbe38ceee5/mypy-1.18.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25a9c8fb67b00599f839cf472713f54249a62efd53a54b565eb61956a7e3296b", size = 12807230, upload-time = "2025-09-19T00:09:49.471Z" },
{ url = "https://files.pythonhosted.org/packages/eb/2e/60076fc829645d167ece9e80db9e8375648d210dab44cc98beb5b322a826/mypy-1.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2b9c7e284ee20e7598d6f42e13ca40b4928e6957ed6813d1ab6348aa3f47133", size = 11895666, upload-time = "2025-09-19T00:10:53.678Z" },
{ url = "https://files.pythonhosted.org/packages/97/4a/1e2880a2a5dda4dc8d9ecd1a7e7606bc0b0e14813637eeda40c38624e037/mypy-1.18.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6985ed057513e344e43a26cc1cd815c7a94602fb6a3130a34798625bc2f07b6", size = 12499608, upload-time = "2025-09-19T00:09:36.204Z" },
{ url = "https://files.pythonhosted.org/packages/00/81/a117f1b73a3015b076b20246b1f341c34a578ebd9662848c6b80ad5c4138/mypy-1.18.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f27105f1525ec024b5c630c0b9f36d5c1cc4d447d61fe51ff4bd60633f47ac", size = 13244551, upload-time = "2025-09-19T00:10:17.531Z" },
{ url = "https://files.pythonhosted.org/packages/9b/61/b9f48e1714ce87c7bf0358eb93f60663740ebb08f9ea886ffc670cea7933/mypy-1.18.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:030c52d0ea8144e721e49b1f68391e39553d7451f0c3f8a7565b59e19fcb608b", size = 13491552, upload-time = "2025-09-19T00:10:13.753Z" },
{ url = "https://files.pythonhosted.org/packages/c9/66/b2c0af3b684fa80d1b27501a8bdd3d2daa467ea3992a8aa612f5ca17c2db/mypy-1.18.2-cp39-cp39-win_amd64.whl", hash = "sha256:aa5e07ac1a60a253445797e42b8b2963c9675563a94f11291ab40718b016a7a0", size = 9765635, upload-time = "2025-09-19T00:10:30.993Z" },
{ url = "https://files.pythonhosted.org/packages/87/e3/be76d87158ebafa0309946c4a73831974d4d6ab4f4ef40c3b53a385a66fd/mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e", size = 2352367, upload-time = "2025-09-19T00:10:15.489Z" }, { url = "https://files.pythonhosted.org/packages/87/e3/be76d87158ebafa0309946c4a73831974d4d6ab4f4ef40c3b53a385a66fd/mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e", size = 2352367, upload-time = "2025-09-19T00:10:15.489Z" },
] ]
@@ -507,61 +482,67 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/da/09/17d9d2b60592890ff7382e591aa1d9afb202a266b180c3d4049b1ec70e4a/orjson-3.11.3-cp314-cp314-win32.whl", hash = "sha256:0c6d7328c200c349e3a4c6d8c83e0a5ad029bdc2d417f234152bf34842d0fc8d", size = 136266, upload-time = "2025-08-26T17:46:13.853Z" }, { url = "https://files.pythonhosted.org/packages/da/09/17d9d2b60592890ff7382e591aa1d9afb202a266b180c3d4049b1ec70e4a/orjson-3.11.3-cp314-cp314-win32.whl", hash = "sha256:0c6d7328c200c349e3a4c6d8c83e0a5ad029bdc2d417f234152bf34842d0fc8d", size = 136266, upload-time = "2025-08-26T17:46:13.853Z" },
{ url = "https://files.pythonhosted.org/packages/15/58/358f6846410a6b4958b74734727e582ed971e13d335d6c7ce3e47730493e/orjson-3.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:317bbe2c069bbc757b1a2e4105b64aacd3bc78279b66a6b9e51e846e4809f804", size = 131351, upload-time = "2025-08-26T17:46:15.27Z" }, { url = "https://files.pythonhosted.org/packages/15/58/358f6846410a6b4958b74734727e582ed971e13d335d6c7ce3e47730493e/orjson-3.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:317bbe2c069bbc757b1a2e4105b64aacd3bc78279b66a6b9e51e846e4809f804", size = 131351, upload-time = "2025-08-26T17:46:15.27Z" },
{ url = "https://files.pythonhosted.org/packages/28/01/d6b274a0635be0468d4dbd9cafe80c47105937a0d42434e805e67cd2ed8b/orjson-3.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:e8f6a7a27d7b7bec81bd5924163e9af03d49bbb63013f107b48eb5d16db711bc", size = 125985, upload-time = "2025-08-26T17:46:16.67Z" }, { url = "https://files.pythonhosted.org/packages/28/01/d6b274a0635be0468d4dbd9cafe80c47105937a0d42434e805e67cd2ed8b/orjson-3.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:e8f6a7a27d7b7bec81bd5924163e9af03d49bbb63013f107b48eb5d16db711bc", size = 125985, upload-time = "2025-08-26T17:46:16.67Z" },
{ url = "https://files.pythonhosted.org/packages/99/a6/18d88ccf8e5d8f711310eba9b4f6562f4aa9d594258efdc4dcf8c1550090/orjson-3.11.3-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:56afaf1e9b02302ba636151cfc49929c1bb66b98794291afd0e5f20fecaf757c", size = 238221, upload-time = "2025-08-26T17:46:18.113Z" },
{ url = "https://files.pythonhosted.org/packages/ee/18/e210365a17bf984c89db40c8be65da164b4ce6a866a2a0ae1d6407c2630b/orjson-3.11.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:913f629adef31d2d350d41c051ce7e33cf0fd06a5d1cb28d49b1899b23b903aa", size = 123209, upload-time = "2025-08-26T17:46:19.688Z" },
{ url = "https://files.pythonhosted.org/packages/26/43/6b3f8ec15fa910726ed94bd2e618f86313ad1cae7c3c8c6b9b8a3a161814/orjson-3.11.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0a23b41f8f98b4e61150a03f83e4f0d566880fe53519d445a962929a4d21045", size = 127881, upload-time = "2025-08-26T17:46:21.502Z" },
{ url = "https://files.pythonhosted.org/packages/4a/ed/f41d2406355ce67efdd4ab504732b27bea37b7dbdab3eb86314fe764f1b9/orjson-3.11.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d721fee37380a44f9d9ce6c701b3960239f4fb3d5ceea7f31cbd43882edaa2f", size = 130306, upload-time = "2025-08-26T17:46:22.914Z" },
{ url = "https://files.pythonhosted.org/packages/3e/a1/1be02950f92c82e64602d3d284bd76d9fc82a6b92c9ce2a387e57a825a11/orjson-3.11.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73b92a5b69f31b1a58c0c7e31080aeaec49c6e01b9522e71ff38d08f15aa56de", size = 132383, upload-time = "2025-08-26T17:46:24.33Z" },
{ url = "https://files.pythonhosted.org/packages/39/49/46766ac00c68192b516a15ffc44c2a9789ca3468b8dc8a500422d99bf0dd/orjson-3.11.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2489b241c19582b3f1430cc5d732caefc1aaf378d97e7fb95b9e56bed11725f", size = 135159, upload-time = "2025-08-26T17:46:25.741Z" },
{ url = "https://files.pythonhosted.org/packages/47/e1/27fd5e7600fdd82996329d48ee56f6e9e9ae4d31eadbc7f93fd2ff0d8214/orjson-3.11.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5189a5dab8b0312eadaf9d58d3049b6a52c454256493a557405e77a3d67ab7f", size = 132690, upload-time = "2025-08-26T17:46:27.271Z" },
{ url = "https://files.pythonhosted.org/packages/d8/21/f57ef08799a68c36ef96fe561101afeef735caa80814636b2e18c234e405/orjson-3.11.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9d8787bdfbb65a85ea76d0e96a3b1bed7bf0fbcb16d40408dc1172ad784a49d2", size = 131086, upload-time = "2025-08-26T17:46:33.067Z" },
{ url = "https://files.pythonhosted.org/packages/cd/84/a3a24306a9dc482e929232c65f5b8c69188136edd6005441d8cc4754f7ea/orjson-3.11.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:8e531abd745f51f8035e207e75e049553a86823d189a51809c078412cefb399a", size = 403884, upload-time = "2025-08-26T17:46:34.55Z" },
{ url = "https://files.pythonhosted.org/packages/11/98/fdae5b2c28bc358e6868e54c8eca7398c93d6a511f0436b61436ad1b04dc/orjson-3.11.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8ab962931015f170b97a3dd7bd933399c1bae8ed8ad0fb2a7151a5654b6941c7", size = 145837, upload-time = "2025-08-26T17:46:36.46Z" },
{ url = "https://files.pythonhosted.org/packages/7d/a9/2fe5cd69ed231f3ed88b1ad36a6957e3d2c876eb4b2c6b17b8ae0a6681fc/orjson-3.11.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:124d5ba71fee9c9902c4a7baa9425e663f7f0aecf73d31d54fe3dd357d62c1a7", size = 135325, upload-time = "2025-08-26T17:46:38.03Z" },
{ url = "https://files.pythonhosted.org/packages/ac/a4/7d4c8aefb45f6c8d7d527d84559a3a7e394b9fd1d424a2b5bcaf75fa68e7/orjson-3.11.3-cp39-cp39-win32.whl", hash = "sha256:22724d80ee5a815a44fc76274bb7ba2e7464f5564aacb6ecddaa9970a83e3225", size = 136184, upload-time = "2025-08-26T17:46:39.542Z" },
{ url = "https://files.pythonhosted.org/packages/9a/1f/1d6a24d22001e96c0afcf1806b6eabee1109aebd2ef20ec6698f6a6012d7/orjson-3.11.3-cp39-cp39-win_amd64.whl", hash = "sha256:215c595c792a87d4407cb72dd5e0f6ee8e694ceeb7f9102b533c5a9bf2a916bb", size = 131373, upload-time = "2025-08-26T17:46:41.227Z" },
] ]
[[package]] [[package]]
name = "ormsgpack" name = "ormsgpack"
version = "1.12.0" version = "1.10.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/6c/67/d5ef41c3b4a94400be801984ef7c7fc9623e1a82b643e74eeec367e7462b/ormsgpack-1.12.0.tar.gz", hash = "sha256:94be818fdbb0285945839b88763b269987787cb2f7ef280cad5d6ec815b7e608", size = 49959, upload-time = "2025-11-04T18:30:10.083Z" } sdist = { url = "https://files.pythonhosted.org/packages/92/36/44eed5ef8ce93cded76a576780bab16425ce7876f10d3e2e6265e46c21ea/ormsgpack-1.10.0.tar.gz", hash = "sha256:7f7a27efd67ef22d7182ec3b7fa7e9d147c3ad9be2a24656b23c989077e08b16", size = 58629, upload-time = "2025-05-24T19:07:53.944Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/4d/0c/8f45fcd22c95190b05d4fba71375d8f783a9e3b0b6aaf476812b693e3868/ormsgpack-1.12.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e08904c232358b94a682ccfbb680bc47d3fd5c424bb7dccb65974dd20c95e8e1", size = 369156, upload-time = "2025-11-04T18:29:17.629Z" }, { url = "https://files.pythonhosted.org/packages/fc/74/c2dd5daf069e3798d09d5746000f9b210de04df83834e5cb47f0ace51892/ormsgpack-1.10.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8a52c7ce7659459f3dc8dec9fd6a6c76f855a0a7e2b61f26090982ac10b95216", size = 376280, upload-time = "2025-05-24T19:06:51.3Z" },
{ url = "https://files.pythonhosted.org/packages/d2/f8/c7adc093d4ceb05e38786906815f868210f808326c27f8124b4d9466a26b/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9ed7a4b0037d69c8ba7e670e03ee65ae8d5c5114a409e73c5770d7fb5e4b895", size = 195743, upload-time = "2025-11-04T18:29:18.964Z" }, { url = "https://files.pythonhosted.org/packages/78/7b/30ff4bffb709e8a242005a8c4d65714fd96308ad640d31cff1b85c0d8cc4/ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:060f67fe927582f4f63a1260726d019204b72f460cf20930e6c925a1d129f373", size = 204335, upload-time = "2025-05-24T19:06:53.442Z" },
{ url = "https://files.pythonhosted.org/packages/fe/b8/bf002648fa6c150ed6157837b00303edafb35f65c352429463f83214de18/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:db2928525b684f3f2af0367aef7ae8d20cde37fc5349c700017129d493a755aa", size = 206472, upload-time = "2025-11-04T18:29:19.951Z" }, { url = "https://files.pythonhosted.org/packages/8f/3f/c95b7d142819f801a0acdbd04280e8132e43b6e5a8920173e8eb92ea0e6a/ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7058ef6092f995561bf9f71d6c9a4da867b6cc69d2e94cb80184f579a3ceed5", size = 215373, upload-time = "2025-05-24T19:06:55.153Z" },
{ url = "https://files.pythonhosted.org/packages/23/d6/1f445947c95a931bb189b7864a3f9dcbeebe7dcbc1b3c7387427b3779228/ormsgpack-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45f911d9c5b23d11e49ff03fc8f9566745a2b1a7d9033733a1c0a2fa9301cd60", size = 207959, upload-time = "2025-11-04T18:29:21.282Z" }, { url = "https://files.pythonhosted.org/packages/ef/1a/e30f4bcf386db2015d1686d1da6110c95110294d8ea04f86091dd5eb3361/ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6f3509c1b0e51b15552d314b1d409321718122e90653122ce4b997f01453a", size = 216469, upload-time = "2025-05-24T19:06:56.555Z" },
{ url = "https://files.pythonhosted.org/packages/5c/9c/dd8ccd7553a5c1d0b4b69a0541611983a2f9bc2e8c5708a4bfffc0100468/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:98c54ae6fd682b2aceb264505af9b2255f3df9d84e6e4369bc44d2110f1f311d", size = 377659, upload-time = "2025-11-04T18:29:22.561Z" }, { url = "https://files.pythonhosted.org/packages/96/fc/7e44aeade22b91883586f45b7278c118fd210834c069774891447f444fc9/ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:51c1edafd5c72b863b1f875ec31c529f09c872a5ff6fe473b9dfaf188ccc3227", size = 384590, upload-time = "2025-05-24T19:06:58.286Z" },
{ url = "https://files.pythonhosted.org/packages/3d/08/3282d8f6330e742d4cdbcfbe2c100b403ae5526ae82a1c1b6a11b7967e37/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:857ab987c3502de08258cc4baf0e87267cb2c80931601084e13df3c355b1ab9d", size = 471391, upload-time = "2025-11-04T18:29:23.663Z" }, { url = "https://files.pythonhosted.org/packages/ec/78/f92c24e8446697caa83c122f10b6cf5e155eddf81ce63905c8223a260482/ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c780b44107a547a9e9327270f802fa4d6b0f6667c9c03c3338c0ce812259a0f7", size = 478891, upload-time = "2025-05-24T19:07:00.126Z" },
{ url = "https://files.pythonhosted.org/packages/18/d4/94a2fbfd4837754bda7a099b6a23b9d40aba9e76e1af8b8fb8133612eb54/ormsgpack-1.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27579d45dc502ee736238e1024559cb0a01aa72a3b68827448b8edf6a2dcdc9c", size = 381501, upload-time = "2025-11-04T18:29:24.771Z" }, { url = "https://files.pythonhosted.org/packages/5a/75/87449690253c64bea2b663c7c8f2dbc9ad39d73d0b38db74bdb0f3947b16/ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:137aab0d5cdb6df702da950a80405eb2b7038509585e32b4e16289604ac7cb84", size = 390121, upload-time = "2025-05-24T19:07:01.777Z" },
{ url = "https://files.pythonhosted.org/packages/d8/c6/1a9fa122cb5deb10b067bbaa43165b12291a914cc0ce364988ff17bbf405/ormsgpack-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c78379d054760875540cf2e81f28da1bb78d09fda3eabdbeb6c53b3e297158cb", size = 112715, upload-time = "2025-11-04T18:29:26.016Z" }, { url = "https://files.pythonhosted.org/packages/69/cc/c83257faf3a5169ec29dd87121317a25711da9412ee8c1e82f2e1a00c0be/ormsgpack-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:3e666cb63030538fa5cd74b1e40cb55b6fdb6e2981f024997a288bf138ebad07", size = 121196, upload-time = "2025-05-24T19:07:03.47Z" },
{ url = "https://files.pythonhosted.org/packages/1a/ba/3cae83cf36420c1c8dd294f16c852c03313aafe2439a165c4c6ac611b1d0/ormsgpack-1.12.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c40d86d77391b18dd34de5295e3de2b8ad818bcab9c9def4121c8ec5c9714ae4", size = 369159, upload-time = "2025-11-04T18:29:27.057Z" }, { url = "https://files.pythonhosted.org/packages/30/27/7da748bc0d7d567950a378dee5a32477ed5d15462ab186918b5f25cac1ad/ormsgpack-1.10.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4bb7df307e17b36cbf7959cd642c47a7f2046ae19408c564e437f0ec323a7775", size = 376275, upload-time = "2025-05-24T19:07:05.128Z" },
{ url = "https://files.pythonhosted.org/packages/97/d4/5e176309e01a8b9098d80201aac1eb7db9336c3b5b4fa6254a2bbb0d0fa0/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:777b7fab364dc0f200bb382a98a385c8222ffa6a2333d627d763797326202c86", size = 195744, upload-time = "2025-11-04T18:29:28.069Z" }, { url = "https://files.pythonhosted.org/packages/7b/65/c082cc8c74a914dbd05af0341c761c73c3d9960b7432bbf9b8e1e20811af/ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8817ae439c671779e1127ee62f0ac67afdeaeeacb5f0db45703168aa74a2e4af", size = 204335, upload-time = "2025-05-24T19:07:06.423Z" },
{ url = "https://files.pythonhosted.org/packages/4f/83/6d80c8c5571639c000a39f38f77752dfaf9d9e552d775331e8d280f66a4e/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b5089ad9dd5b3d3013b245a55e4abaea2f8ad70f4a78e1b002127b02340004", size = 206474, upload-time = "2025-11-04T18:29:29.034Z" }, { url = "https://files.pythonhosted.org/packages/46/62/17ef7e5d9766c79355b9c594cc9328c204f1677bc35da0595cc4e46449f0/ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f345f81e852035d80232e64374d3a104139d60f8f43c6c5eade35c4bac5590e", size = 215372, upload-time = "2025-05-24T19:07:08.149Z" },
{ url = "https://files.pythonhosted.org/packages/5e/e6/940311e48dc0cfc3e212bd7007a21ed0825158638057687d804f2c5c2cca/ormsgpack-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:deaf0c87cace7bc08fbf68c5cc66605b593df6427e9f4de235b2da358787e008", size = 207959, upload-time = "2025-11-04T18:29:30.315Z" }, { url = "https://files.pythonhosted.org/packages/4e/92/7c91e8115fc37e88d1a35e13200fda3054ff5d2e5adf017345e58cea4834/ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21de648a1c7ef692bdd287fb08f047bd5371d7462504c0a7ae1553c39fee35e3", size = 216470, upload-time = "2025-05-24T19:07:09.903Z" },
{ url = "https://files.pythonhosted.org/packages/1a/e3/fbe94b0a311815343b86a95a0627e4901b11ff6fd522679ca29a2a88c99b/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f62d476fe28bc5675d9aff30341bfa9f41d7de332c5b63fbbe9aaf6bb7ec74d4", size = 377666, upload-time = "2025-11-04T18:29:31.38Z" }, { url = "https://files.pythonhosted.org/packages/2c/86/ce053c52e2517b90e390792d83e926a7a523c1bce5cc63d0a7cd05ce6cf6/ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3a7d844ae9cbf2112c16086dd931b2acefce14cefd163c57db161170c2bfa22b", size = 384591, upload-time = "2025-05-24T19:07:11.24Z" },
{ url = "https://files.pythonhosted.org/packages/a3/3b/229cfa28076798ffb619aaa854b842de3f2ed5ea4e6509bf34d14c038c4d/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ded7810095b887e28434f32f5a345d354e88cf851bab3c5435aeb86a718618d2", size = 471394, upload-time = "2025-11-04T18:29:32.521Z" }, { url = "https://files.pythonhosted.org/packages/07/e8/2ad59f2ab222c6029e500bc966bfd2fe5cb099f8ab6b7ebeb50ddb1a6fe5/ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e4d80585403d86d7f800cf3d0aafac1189b403941e84e90dd5102bb2b92bf9d5", size = 478892, upload-time = "2025-05-24T19:07:13.147Z" },
{ url = "https://files.pythonhosted.org/packages/6b/bd/4eae4ab35586e4175c07acb5f98aec83aa9d8987f71ea0443aa900191bdf/ormsgpack-1.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f72a1dea0c4ae7c4101dcfbe8133f274a9d769d0b87fe5188db4fab07ffabaee", size = 381506, upload-time = "2025-11-04T18:29:33.533Z" }, { url = "https://files.pythonhosted.org/packages/f4/73/f55e4b47b7b18fd8e7789680051bf830f1e39c03f1d9ed993cd0c3e97215/ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:da1de515a87e339e78a3ccf60e39f5fb740edac3e9e82d3c3d209e217a13ac08", size = 390122, upload-time = "2025-05-24T19:07:14.557Z" },
{ url = "https://files.pythonhosted.org/packages/dd/51/f9d56d6d015cbfa1ce9a4358ca30a41744644f0cf606e060d7203efe5af8/ormsgpack-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:8f479bfef847255d7d0b12c7a198f6a21490155da2da3062e082ba370893d4a1", size = 112707, upload-time = "2025-11-04T18:29:34.898Z" }, { url = "https://files.pythonhosted.org/packages/f7/87/073251cdb93d4c6241748568b3ad1b2a76281fb2002eed16a3a4043d61cf/ormsgpack-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:57c4601812684024132cbb32c17a7d4bb46ffc7daf2fddf5b697391c2c4f142a", size = 121197, upload-time = "2025-05-24T19:07:15.981Z" },
{ url = "https://files.pythonhosted.org/packages/f4/07/bb189ef7072979f2f96e8716e952172efdce9c54930aa0814bec73aee19b/ormsgpack-1.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:3583ca410e4502144b2594170542e4bbef7b15643fd1208703ae820f11029036", size = 106533, upload-time = "2025-11-04T18:29:36.112Z" }, { url = "https://files.pythonhosted.org/packages/99/95/f3ab1a7638f6aa9362e87916bb96087fbbc5909db57e19f12ad127560e1e/ormsgpack-1.10.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4e159d50cd4064d7540e2bc6a0ab66eab70b0cc40c618b485324ee17037527c0", size = 376806, upload-time = "2025-05-24T19:07:17.221Z" },
{ url = "https://files.pythonhosted.org/packages/a2/f2/c1036b2775fcc0cfa5fd618c53bcd3b862ee07298fb627f03af4c7982f84/ormsgpack-1.12.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e0c1e08b64d99076fee155276097489b82cc56e8d5951c03c721a65a32f44494", size = 369538, upload-time = "2025-11-04T18:29:37.125Z" }, { url = "https://files.pythonhosted.org/packages/6c/2b/42f559f13c0b0f647b09d749682851d47c1a7e48308c43612ae6833499c8/ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb47c85f3a866e29279d801115b554af0fefc409e2ed8aa90aabfa77efe5cc6", size = 204433, upload-time = "2025-05-24T19:07:18.569Z" },
{ url = "https://files.pythonhosted.org/packages/d9/ca/526c4ae02f3cb34621af91bf8282a10d666757c2e0c6ff391ff5d403d607/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd43bcb299131690b8e0677af172020b2ada8e625169034b42ac0c13adf84aa", size = 195872, upload-time = "2025-11-04T18:29:38.34Z" }, { url = "https://files.pythonhosted.org/packages/45/42/1ca0cb4d8c80340a89a4af9e6d8951fb8ba0d076a899d2084eadf536f677/ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c28249574934534c9bd5dce5485c52f21bcea0ee44d13ece3def6e3d2c3798b5", size = 215547, upload-time = "2025-05-24T19:07:20.245Z" },
{ url = "https://files.pythonhosted.org/packages/7f/0f/83bb7968e9715f6a85be53d041b1e6324a05428f56b8b980dac866886871/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0149d595341e22ead340bf281b2995c4cc7dc8d522a6b5f575fe17aa407604", size = 206469, upload-time = "2025-11-04T18:29:39.749Z" }, { url = "https://files.pythonhosted.org/packages/0a/38/184a570d7c44c0260bc576d1daaac35b2bfd465a50a08189518505748b9a/ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1957dcadbb16e6a981cd3f9caef9faf4c2df1125e2a1b702ee8236a55837ce07", size = 216746, upload-time = "2025-05-24T19:07:21.83Z" },
{ url = "https://files.pythonhosted.org/packages/02/e3/9e93ca1065f2d4af035804a842b1ff3025bab580c7918239bb225cd1fee2/ormsgpack-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f19a1b27d169deb553c80fd10b589fc2be1fc14cee779fae79fcaf40db04de2b", size = 208273, upload-time = "2025-11-04T18:29:40.769Z" }, { url = "https://files.pythonhosted.org/packages/69/2f/1aaffd08f6b7fdc2a57336a80bdfb8df24e6a65ada5aa769afecfcbc6cc6/ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3b29412558c740bf6bac156727aa85ac67f9952cd6f071318f29ee72e1a76044", size = 384783, upload-time = "2025-05-24T19:07:23.674Z" },
{ url = "https://files.pythonhosted.org/packages/b3/d8/6d6ef901b3a8b8f3ab8836b135a56eb7f66c559003e251d9530bedb12627/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f28896942d655064940dfe06118b7ce1e3468d051483148bf02c99ec157483a", size = 377839, upload-time = "2025-11-04T18:29:42.092Z" }, { url = "https://files.pythonhosted.org/packages/a9/63/3e53d6f43bb35e00c98f2b8ab2006d5138089ad254bc405614fbf0213502/ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6933f350c2041ec189fe739f0ba7d6117c8772f5bc81f45b97697a84d03020dd", size = 479076, upload-time = "2025-05-24T19:07:25.047Z" },
{ url = "https://files.pythonhosted.org/packages/4c/72/fcb704bfa4c2c3a37b647d597cc45a13cffc9d50baac635a9ad620731d29/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9396efcfa48b4abbc06e44c5dbc3c4574a8381a80cb4cd01eea15d28b38c554e", size = 471446, upload-time = "2025-11-04T18:29:43.133Z" }, { url = "https://files.pythonhosted.org/packages/b8/19/fa1121b03b61402bb4d04e35d164e2320ef73dfb001b57748110319dd014/ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a86de06d368fcc2e58b79dece527dc8ca831e0e8b9cec5d6e633d2777ec93d0", size = 390447, upload-time = "2025-05-24T19:07:26.568Z" },
{ url = "https://files.pythonhosted.org/packages/84/f8/402e4e3eb997c2ee534c99bec4b5bb359c2a1f9edadf043e254a71e11378/ormsgpack-1.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:96586ed537a5fb386a162c4f9f7d8e6f76e07b38a990d50c73f11131e00ff040", size = 381783, upload-time = "2025-11-04T18:29:44.466Z" }, { url = "https://files.pythonhosted.org/packages/b0/0d/73143ecb94ac4a5dcba223402139240a75dee0cc6ba8a543788a5646407a/ormsgpack-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:35fa9f81e5b9a0dab42e09a73f7339ecffdb978d6dbf9deb2ecf1e9fc7808722", size = 121401, upload-time = "2025-05-24T19:07:28.308Z" },
{ url = "https://files.pythonhosted.org/packages/f0/8d/5897b700360bc00911b70ae5ef1134ee7abf5baa81a92a4be005917d3dfd/ormsgpack-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e70387112fb3870e4844de090014212cdcf1342f5022047aecca01ec7de05d7a", size = 112943, upload-time = "2025-11-04T18:29:45.468Z" }, { url = "https://files.pythonhosted.org/packages/61/f8/ec5f4e03268d0097545efaab2893aa63f171cf2959cb0ea678a5690e16a1/ormsgpack-1.10.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d816d45175a878993b7372bd5408e0f3ec5a40f48e2d5b9d8f1cc5d31b61f1f", size = 376806, upload-time = "2025-05-24T19:07:29.555Z" },
{ url = "https://files.pythonhosted.org/packages/5b/44/1e73649f79bb96d6cf9e5bcbac68b6216d238bba80af351c4c0cbcf7ee15/ormsgpack-1.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:d71290a23de5d4829610c42665d816c661ecad8979883f3f06b2e3ab9639962e", size = 106688, upload-time = "2025-11-04T18:29:46.411Z" }, { url = "https://files.pythonhosted.org/packages/c1/19/b3c53284aad1e90d4d7ed8c881a373d218e16675b8b38e3569d5b40cc9b8/ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90345ccb058de0f35262893751c603b6376b05f02be2b6f6b7e05d9dd6d5643", size = 204433, upload-time = "2025-05-24T19:07:30.977Z" },
{ url = "https://files.pythonhosted.org/packages/2e/e8/35f11ce9313111488b26b3035e4cbe55caa27909c0b6c8b5b5cd59f9661e/ormsgpack-1.12.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:766f2f3b512d85cd375b26a8b1329b99843560b50b93d3880718e634ad4a5de5", size = 369574, upload-time = "2025-11-04T18:29:47.431Z" }, { url = "https://files.pythonhosted.org/packages/09/0b/845c258f59df974a20a536c06cace593698491defdd3d026a8a5f9b6e745/ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:144b5e88f1999433e54db9d637bae6fe21e935888be4e3ac3daecd8260bd454e", size = 215549, upload-time = "2025-05-24T19:07:32.345Z" },
{ url = "https://files.pythonhosted.org/packages/61/b0/77461587f412d4e598d3687bafe23455ed0f26269f44be20252eddaa624e/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84b285b1f3f185aad7da45641b873b30acfd13084cf829cf668c4c6480a81583", size = 195893, upload-time = "2025-11-04T18:29:48.735Z" }, { url = "https://files.pythonhosted.org/packages/61/56/57fce8fb34ca6c9543c026ebebf08344c64dbb7b6643d6ddd5355d37e724/ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2190b352509d012915921cca76267db136cd026ddee42f1b0d9624613cc7058c", size = 216747, upload-time = "2025-05-24T19:07:34.075Z" },
{ url = "https://files.pythonhosted.org/packages/c6/67/e197ceb04c3b550589e5407fc9fdae10f4e2e2eba5fdac921a269e02e974/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e23604fc79fe110292cb365f4c8232e64e63a34f470538be320feae3921f271b", size = 206503, upload-time = "2025-11-04T18:29:49.99Z" }, { url = "https://files.pythonhosted.org/packages/b8/3f/655b5f6a2475c8d209f5348cfbaaf73ce26237b92d79ef2ad439407dd0fa/ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:86fd9c1737eaba43d3bb2730add9c9e8b5fbed85282433705dd1b1e88ea7e6fb", size = 384785, upload-time = "2025-05-24T19:07:35.83Z" },
{ url = "https://files.pythonhosted.org/packages/0b/b1/7fa8ba82a25cef678983c7976f85edeef5014f5c26495f338258e6a3cf1c/ormsgpack-1.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc32b156c113a0fae2975051417d8d9a7a5247c34b2d7239410c46b75ce9348a", size = 208257, upload-time = "2025-11-04T18:29:51.007Z" }, { url = "https://files.pythonhosted.org/packages/4b/94/687a0ad8afd17e4bce1892145d6a1111e58987ddb176810d02a1f3f18686/ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:33afe143a7b61ad21bb60109a86bb4e87fec70ef35db76b89c65b17e32da7935", size = 479076, upload-time = "2025-05-24T19:07:37.533Z" },
{ url = "https://files.pythonhosted.org/packages/ce/b1/759e999390000d2589e6d0797f7265e6ec28378547075d28d3736248ab63/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:94ac500dd10c20fa8b8a23bc55606250bfe711bf9716828d9f3d44dfd1f25668", size = 377852, upload-time = "2025-11-04T18:29:52.103Z" }, { url = "https://files.pythonhosted.org/packages/c8/34/68925232e81e0e062a2f0ac678f62aa3b6f7009d6a759e19324dbbaebae7/ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f23d45080846a7b90feabec0d330a9cc1863dc956728412e4f7986c80ab3a668", size = 390446, upload-time = "2025-05-24T19:07:39.469Z" },
{ url = "https://files.pythonhosted.org/packages/51/e7/0af737c94272494d9d84a3c29cc42c973ef7fd2342917020906596db863c/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c5201ff7ec24f721f813a182885a17064cffdbe46b2412685a52e6374a872c8f", size = 471456, upload-time = "2025-11-04T18:29:53.336Z" }, { url = "https://files.pythonhosted.org/packages/12/ad/f4e1a36a6d1714afb7ffb74b3ababdcb96529cf4e7a216f9f7c8eda837b6/ormsgpack-1.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:534d18acb805c75e5fba09598bf40abe1851c853247e61dda0c01f772234da69", size = 121399, upload-time = "2025-05-24T19:07:40.854Z" },
{ url = "https://files.pythonhosted.org/packages/f4/ba/c81f0aa4f19fbf457213395945b672e6fde3ce777e3587456e7f0fca2147/ormsgpack-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a9740bb3839c9368aacae1cbcfc474ee6976458f41cc135372b7255d5206c953", size = 381813, upload-time = "2025-11-04T18:29:54.394Z" }, { url = "https://files.pythonhosted.org/packages/75/8f/bb80469db9d5b10708cba6997463d140486ca7053a5d18f99b5739cfecf7/ormsgpack-1.10.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:efdb25cf6d54085f7ae557268d59fd2d956f1a09a340856e282d2960fe929f32", size = 376272, upload-time = "2025-05-24T19:07:42.16Z" },
{ url = "https://files.pythonhosted.org/packages/ce/15/429c72d64323503fd42cc4ca8398930ded8aa8b3470df8a86b3bbae7a35c/ormsgpack-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ed37f29772432048b58174e920a1d4c4cde0404a5d448d3d8bbcc95d86a6918", size = 112949, upload-time = "2025-11-04T18:29:55.371Z" }, { url = "https://files.pythonhosted.org/packages/08/9c/48f714ed3d5a153f25e3b490496e6ba214aee265a82be1b61e39019ea146/ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddfcb30d4b1be2439836249d675f297947f4fb8efcd3eeb6fd83021d773cadc4", size = 204314, upload-time = "2025-05-24T19:07:43.444Z" },
{ url = "https://files.pythonhosted.org/packages/55/b9/e72c451a40f8c57bfc229e0b8e536ecea7203c8f0a839676df2ffb605c62/ormsgpack-1.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:b03994bbec5d6d42e03d6604e327863f885bde67aa61e06107ce1fa5bdd3e71d", size = 106689, upload-time = "2025-11-04T18:29:56.262Z" }, { url = "https://files.pythonhosted.org/packages/27/42/7f9edf6e5511120b5304c76c5d3a8b4719ff927555a6dba41b6f9d041b30/ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee0944b6ccfd880beb1ca29f9442a774683c366f17f4207f8b81c5e24cadb453", size = 215386, upload-time = "2025-05-24T19:07:45.232Z" },
{ url = "https://files.pythonhosted.org/packages/13/16/13eab1a75da531b359105fdee90dda0b6bd1ca0a09880250cf91d8bdfdea/ormsgpack-1.12.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0f3981ba3cba80656012090337e548e597799e14b41e3d0b595ab5ab05a23d7f", size = 369620, upload-time = "2025-11-04T18:29:57.255Z" }, { url = "https://files.pythonhosted.org/packages/40/87/41e14485857fbe4ed5a530677fe60dd6910a254825c0b1cb5b04baaa4be0/ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35cdff6a0d3ba04e40a751129763c3b9b57a602c02944138e4b760ec99ae80a1", size = 216466, upload-time = "2025-05-24T19:07:46.548Z" },
{ url = "https://files.pythonhosted.org/packages/a0/c1/cbcc38b7af4ce58d8893e56d3595c0c8dcd117093bf048f889cf351bdba0/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:901f6f55184d6776dbd5183cbce14caf05bf7f467eef52faf9b094686980bf71", size = 195925, upload-time = "2025-11-04T18:29:58.34Z" }, { url = "https://files.pythonhosted.org/packages/cb/68/769fa1c721d8aa6799c0ce98b1711ae57de3e6379b554ebf9a11be4c62ff/ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:599ccdabc19c618ef5de6e6f2e7f5d48c1f531a625fa6772313b8515bc710681", size = 384600, upload-time = "2025-05-24T19:07:47.945Z" },
{ url = "https://files.pythonhosted.org/packages/5c/59/4fa4dc0681490e12b75333440a1c0fd9741b0ebff272b1db4a29d35c2021/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e13b15412571422b711b40f45e3fe6d993ea3314b5e97d1a853fe99226c5effc", size = 206594, upload-time = "2025-11-04T18:29:59.329Z" }, { url = "https://files.pythonhosted.org/packages/4e/f9/b57fd387fe16753783a3cea0ed2471c727bbed4356d8a08e3f0340251870/ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:bf46f57da9364bd5eefd92365c1b78797f56c6f780581eecd60cd7b367f9b4d3", size = 478888, upload-time = "2025-05-24T19:07:49.801Z" },
{ url = "https://files.pythonhosted.org/packages/39/67/249770896bc32bb91b22c30256961f935d0915cbcf6e289a7fc961d9b14c/ormsgpack-1.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91fa8a452553a62e5fb3fbab471e7faf7b3bec3c87a2f355ebf3d7aab290fe4f", size = 208307, upload-time = "2025-11-04T18:30:00.377Z" }, { url = "https://files.pythonhosted.org/packages/3e/0f/464cdfa7f9ee817c2d94485880b6c3c4b9f22df9fcbf21c303bbfebcb3ed/ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b796f64fdf823dedb1e35436a4a6f889cf78b1aa42d3097c66e5adfd8c3bd72d", size = 390118, upload-time = "2025-05-24T19:07:51.193Z" },
{ url = "https://files.pythonhosted.org/packages/07/0a/e041a248cd72f2f4c07e155913e0a3ede4c86cf21a40ae6cd79f135f2847/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74ec101f69624695eec4ce7c953192d97748254abe78fb01b591f06d529e1952", size = 377844, upload-time = "2025-11-04T18:30:01.389Z" }, { url = "https://files.pythonhosted.org/packages/ad/03/b9146dff5458def4c0a2b1e35c1c24e4d5e8083899aa0718b6eccba39317/ormsgpack-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:106253ac9dc08520951e556b3c270220fcb8b4fef0d30b71eedac4befa4de749", size = 121199, upload-time = "2025-05-24T19:07:52.639Z" },
{ url = "https://files.pythonhosted.org/packages/d8/71/6f7773e4ffda73a358ce4bba69b3e8bee9d40a7a06315e4c1cd7a3ea9d02/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9bbf7896580848326c1f9bd7531f264e561f98db7e08e15aa75963d83832c717", size = 471572, upload-time = "2025-11-04T18:30:02.486Z" },
{ url = "https://files.pythonhosted.org/packages/65/29/af6769a4289c07acc71e7bda1d64fb31800563147d73142686e185e82348/ormsgpack-1.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7567917da613b8f8d591c1674e411fd3404bea41ef2b9a0e0a1e049c0f9406d7", size = 381842, upload-time = "2025-11-04T18:30:03.799Z" },
{ url = "https://files.pythonhosted.org/packages/0b/dd/0a86195ee7a1a96c088aefc8504385e881cf56f4563ed81bafe21cbf1fb0/ormsgpack-1.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e418256c5d8622b8bc92861936f7c6a0131355e7bcad88a42102ae8227f8a1c", size = 113008, upload-time = "2025-11-04T18:30:04.777Z" },
{ url = "https://files.pythonhosted.org/packages/4c/57/fafc79e32f3087f6f26f509d80b8167516326bfea38d30502627c01617e0/ormsgpack-1.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:433ace29aa02713554f714c62a4e4dcad0c9e32674ba4f66742c91a4c3b1b969", size = 106648, upload-time = "2025-11-04T18:30:05.708Z" },
{ url = "https://files.pythonhosted.org/packages/b3/cf/5d58d9b132128d2fe5d586355dde76af386554abef00d608f66b913bff1f/ormsgpack-1.12.0-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e57164be4ca34b64e210ec515059193280ac84df4d6f31a6fcbfb2fc8436de55", size = 369803, upload-time = "2025-11-04T18:30:06.728Z" },
{ url = "https://files.pythonhosted.org/packages/67/42/968a2da361eaff2e4cbb17c82c7599787babf16684110ad70409646cc1e4/ormsgpack-1.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:904f96289deaa92fc6440b122edc27c5bdc28234edd63717f6d853d88c823a83", size = 195991, upload-time = "2025-11-04T18:30:07.713Z" },
{ url = "https://files.pythonhosted.org/packages/03/f0/9696c6c6cf8ad35170f0be8d0ef3523cc258083535f6c8071cb8235ebb8b/ormsgpack-1.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b291d086e524a1062d57d1b7b5a8bcaaf29caebf0212fec12fd86240bd33633", size = 208316, upload-time = "2025-11-04T18:30:08.663Z" },
] ]
[[package]] [[package]]
@@ -593,7 +574,7 @@ wheels = [
[[package]] [[package]]
name = "pydantic" name = "pydantic"
version = "2.12.2" version = "2.11.9"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "annotated-types" }, { name = "annotated-types" },
@@ -601,123 +582,118 @@ dependencies = [
{ name = "typing-extensions" }, { name = "typing-extensions" },
{ name = "typing-inspection" }, { name = "typing-inspection" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/8d/35/d319ed522433215526689bad428a94058b6dd12190ce7ddd78618ac14b28/pydantic-2.12.2.tar.gz", hash = "sha256:7b8fa15b831a4bbde9d5b84028641ac3080a4ca2cbd4a621a661687e741624fd", size = 816358, upload-time = "2025-10-14T15:02:21.842Z" } sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/6c/98/468cb649f208a6f1279448e6e5247b37ae79cf5e4041186f1e2ef3d16345/pydantic-2.12.2-py3-none-any.whl", hash = "sha256:25ff718ee909acd82f1ff9b1a4acfd781bb23ab3739adaa7144f19a6a4e231ae", size = 460628, upload-time = "2025-10-14T15:02:19.623Z" }, { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" },
] ]
[[package]] [[package]]
name = "pydantic-core" name = "pydantic-core"
version = "2.41.4" version = "2.33.2"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "typing-extensions" }, { name = "typing-extensions" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/df/18/d0944e8eaaa3efd0a91b0f1fc537d3be55ad35091b6a87638211ba691964/pydantic_core-2.41.4.tar.gz", hash = "sha256:70e47929a9d4a1905a67e4b687d5946026390568a8e952b92824118063cee4d5", size = 457557, upload-time = "2025-10-14T10:23:47.909Z" } sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/3d/9b8ca77b0f76fcdbf8bc6b72474e264283f461284ca84ac3fde570c6c49a/pydantic_core-2.41.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2442d9a4d38f3411f22eb9dd0912b7cbf4b7d5b6c92c4173b75d3e1ccd84e36e", size = 2111197, upload-time = "2025-10-14T10:19:43.303Z" }, { url = "https://files.pythonhosted.org/packages/e5/92/b31726561b5dae176c2d2c2dc43a9c5bfba5d32f96f8b4c0a600dd492447/pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8", size = 2028817, upload-time = "2025-04-23T18:30:43.919Z" },
{ url = "https://files.pythonhosted.org/packages/59/92/b7b0fe6ed4781642232755cb7e56a86e2041e1292f16d9ae410a0ccee5ac/pydantic_core-2.41.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:30a9876226dda131a741afeab2702e2d127209bde3c65a2b8133f428bc5d006b", size = 1917909, upload-time = "2025-10-14T10:19:45.194Z" }, { url = "https://files.pythonhosted.org/packages/a3/44/3f0b95fafdaca04a483c4e685fe437c6891001bf3ce8b2fded82b9ea3aa1/pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d", size = 1861357, upload-time = "2025-04-23T18:30:46.372Z" },
{ url = "https://files.pythonhosted.org/packages/52/8c/3eb872009274ffa4fb6a9585114e161aa1a0915af2896e2d441642929fe4/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d55bbac04711e2980645af68b97d445cdbcce70e5216de444a6c4b6943ebcccd", size = 1969905, upload-time = "2025-10-14T10:19:46.567Z" }, { url = "https://files.pythonhosted.org/packages/30/97/e8f13b55766234caae05372826e8e4b3b96e7b248be3157f53237682e43c/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d", size = 1898011, upload-time = "2025-04-23T18:30:47.591Z" },
{ url = "https://files.pythonhosted.org/packages/f4/21/35adf4a753bcfaea22d925214a0c5b880792e3244731b3f3e6fec0d124f7/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e1d778fb7849a42d0ee5927ab0f7453bf9f85eef8887a546ec87db5ddb178945", size = 2051938, upload-time = "2025-10-14T10:19:48.237Z" }, { url = "https://files.pythonhosted.org/packages/9b/a3/99c48cf7bafc991cc3ee66fd544c0aae8dc907b752f1dad2d79b1b5a471f/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572", size = 1982730, upload-time = "2025-04-23T18:30:49.328Z" },
{ url = "https://files.pythonhosted.org/packages/7d/d0/cdf7d126825e36d6e3f1eccf257da8954452934ede275a8f390eac775e89/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b65077a4693a98b90ec5ad8f203ad65802a1b9b6d4a7e48066925a7e1606706", size = 2250710, upload-time = "2025-10-14T10:19:49.619Z" }, { url = "https://files.pythonhosted.org/packages/de/8e/a5b882ec4307010a840fb8b58bd9bf65d1840c92eae7534c7441709bf54b/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02", size = 2136178, upload-time = "2025-04-23T18:30:50.907Z" },
{ url = "https://files.pythonhosted.org/packages/2e/1c/af1e6fd5ea596327308f9c8d1654e1285cc3d8de0d584a3c9d7705bf8a7c/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62637c769dee16eddb7686bf421be48dfc2fae93832c25e25bc7242e698361ba", size = 2367445, upload-time = "2025-10-14T10:19:51.269Z" }, { url = "https://files.pythonhosted.org/packages/e4/bb/71e35fc3ed05af6834e890edb75968e2802fe98778971ab5cba20a162315/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b", size = 2736462, upload-time = "2025-04-23T18:30:52.083Z" },
{ url = "https://files.pythonhosted.org/packages/d3/81/8cece29a6ef1b3a92f956ea6da6250d5b2d2e7e4d513dd3b4f0c7a83dfea/pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfe3aa529c8f501babf6e502936b9e8d4698502b2cfab41e17a028d91b1ac7b", size = 2072875, upload-time = "2025-10-14T10:19:52.671Z" }, { url = "https://files.pythonhosted.org/packages/31/0d/c8f7593e6bc7066289bbc366f2235701dcbebcd1ff0ef8e64f6f239fb47d/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2", size = 2005652, upload-time = "2025-04-23T18:30:53.389Z" },
{ url = "https://files.pythonhosted.org/packages/e3/37/a6a579f5fc2cd4d5521284a0ab6a426cc6463a7b3897aeb95b12f1ba607b/pydantic_core-2.41.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca2322da745bf2eeb581fc9ea3bbb31147702163ccbcbf12a3bb630e4bf05e1d", size = 2191329, upload-time = "2025-10-14T10:19:54.214Z" }, { url = "https://files.pythonhosted.org/packages/d2/7a/996d8bd75f3eda405e3dd219ff5ff0a283cd8e34add39d8ef9157e722867/pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a", size = 2113306, upload-time = "2025-04-23T18:30:54.661Z" },
{ url = "https://files.pythonhosted.org/packages/ae/03/505020dc5c54ec75ecba9f41119fd1e48f9e41e4629942494c4a8734ded1/pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e8cd3577c796be7231dcf80badcf2e0835a46665eaafd8ace124d886bab4d700", size = 2151658, upload-time = "2025-10-14T10:19:55.843Z" }, { url = "https://files.pythonhosted.org/packages/ff/84/daf2a6fb2db40ffda6578a7e8c5a6e9c8affb251a05c233ae37098118788/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac", size = 2073720, upload-time = "2025-04-23T18:30:56.11Z" },
{ url = "https://files.pythonhosted.org/packages/cb/5d/2c0d09fb53aa03bbd2a214d89ebfa6304be7df9ed86ee3dc7770257f41ee/pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:1cae8851e174c83633f0833e90636832857297900133705ee158cf79d40f03e6", size = 2316777, upload-time = "2025-10-14T10:19:57.607Z" }, { url = "https://files.pythonhosted.org/packages/77/fb/2258da019f4825128445ae79456a5499c032b55849dbd5bed78c95ccf163/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a", size = 2244915, upload-time = "2025-04-23T18:30:57.501Z" },
{ url = "https://files.pythonhosted.org/packages/ea/4b/c2c9c8f5e1f9c864b57d08539d9d3db160e00491c9f5ee90e1bfd905e644/pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a26d950449aae348afe1ac8be5525a00ae4235309b729ad4d3399623125b43c9", size = 2320705, upload-time = "2025-10-14T10:19:59.016Z" }, { url = "https://files.pythonhosted.org/packages/d8/7a/925ff73756031289468326e355b6fa8316960d0d65f8b5d6b3a3e7866de7/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b", size = 2241884, upload-time = "2025-04-23T18:30:58.867Z" },
{ url = "https://files.pythonhosted.org/packages/28/c3/a74c1c37f49c0a02c89c7340fafc0ba816b29bd495d1a31ce1bdeacc6085/pydantic_core-2.41.4-cp310-cp310-win32.whl", hash = "sha256:0cf2a1f599efe57fa0051312774280ee0f650e11152325e41dfd3018ef2c1b57", size = 1975464, upload-time = "2025-10-14T10:20:00.581Z" }, { url = "https://files.pythonhosted.org/packages/0b/b0/249ee6d2646f1cdadcb813805fe76265745c4010cf20a8eba7b0e639d9b2/pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22", size = 1910496, upload-time = "2025-04-23T18:31:00.078Z" },
{ url = "https://files.pythonhosted.org/packages/d6/23/5dd5c1324ba80303368f7569e2e2e1a721c7d9eb16acb7eb7b7f85cb1be2/pydantic_core-2.41.4-cp310-cp310-win_amd64.whl", hash = "sha256:a8c2e340d7e454dc3340d3d2e8f23558ebe78c98aa8f68851b04dcb7bc37abdc", size = 2024497, upload-time = "2025-10-14T10:20:03.018Z" }, { url = "https://files.pythonhosted.org/packages/66/ff/172ba8f12a42d4b552917aa65d1f2328990d3ccfc01d5b7c943ec084299f/pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640", size = 1955019, upload-time = "2025-04-23T18:31:01.335Z" },
{ url = "https://files.pythonhosted.org/packages/62/4c/f6cbfa1e8efacd00b846764e8484fe173d25b8dab881e277a619177f3384/pydantic_core-2.41.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:28ff11666443a1a8cf2a044d6a545ebffa8382b5f7973f22c36109205e65dc80", size = 2109062, upload-time = "2025-10-14T10:20:04.486Z" }, { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" },
{ url = "https://files.pythonhosted.org/packages/21/f8/40b72d3868896bfcd410e1bd7e516e762d326201c48e5b4a06446f6cf9e8/pydantic_core-2.41.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:61760c3925d4633290292bad462e0f737b840508b4f722247d8729684f6539ae", size = 1916301, upload-time = "2025-10-14T10:20:06.857Z" }, { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" },
{ url = "https://files.pythonhosted.org/packages/94/4d/d203dce8bee7faeca791671c88519969d98d3b4e8f225da5b96dad226fc8/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eae547b7315d055b0de2ec3965643b0ab82ad0106a7ffd29615ee9f266a02827", size = 1968728, upload-time = "2025-10-14T10:20:08.353Z" }, { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" },
{ url = "https://files.pythonhosted.org/packages/65/f5/6a66187775df87c24d526985b3a5d78d861580ca466fbd9d4d0e792fcf6c/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef9ee5471edd58d1fcce1c80ffc8783a650e3e3a193fe90d52e43bb4d87bff1f", size = 2050238, upload-time = "2025-10-14T10:20:09.766Z" }, { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" },
{ url = "https://files.pythonhosted.org/packages/5e/b9/78336345de97298cf53236b2f271912ce11f32c1e59de25a374ce12f9cce/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15dd504af121caaf2c95cb90c0ebf71603c53de98305621b94da0f967e572def", size = 2249424, upload-time = "2025-10-14T10:20:11.732Z" }, { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" },
{ url = "https://files.pythonhosted.org/packages/99/bb/a4584888b70ee594c3d374a71af5075a68654d6c780369df269118af7402/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a926768ea49a8af4d36abd6a8968b8790f7f76dd7cbd5a4c180db2b4ac9a3a2", size = 2366047, upload-time = "2025-10-14T10:20:13.647Z" }, { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" },
{ url = "https://files.pythonhosted.org/packages/5f/8d/17fc5de9d6418e4d2ae8c675f905cdafdc59d3bf3bf9c946b7ab796a992a/pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916b9b7d134bff5440098a4deb80e4cb623e68974a87883299de9124126c2a8", size = 2071163, upload-time = "2025-10-14T10:20:15.307Z" }, { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" },
{ url = "https://files.pythonhosted.org/packages/54/e7/03d2c5c0b8ed37a4617430db68ec5e7dbba66358b629cd69e11b4d564367/pydantic_core-2.41.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5cf90535979089df02e6f17ffd076f07237efa55b7343d98760bde8743c4b265", size = 2190585, upload-time = "2025-10-14T10:20:17.3Z" }, { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" },
{ url = "https://files.pythonhosted.org/packages/be/fc/15d1c9fe5ad9266a5897d9b932b7f53d7e5cfc800573917a2c5d6eea56ec/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7533c76fa647fade2d7ec75ac5cc079ab3f34879626dae5689b27790a6cf5a5c", size = 2150109, upload-time = "2025-10-14T10:20:19.143Z" }, { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" },
{ url = "https://files.pythonhosted.org/packages/26/ef/e735dd008808226c83ba56972566138665b71477ad580fa5a21f0851df48/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:37e516bca9264cbf29612539801ca3cd5d1be465f940417b002905e6ed79d38a", size = 2315078, upload-time = "2025-10-14T10:20:20.742Z" }, { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" },
{ url = "https://files.pythonhosted.org/packages/90/00/806efdcf35ff2ac0f938362350cd9827b8afb116cc814b6b75cf23738c7c/pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0c19cb355224037c83642429b8ce261ae108e1c5fbf5c028bac63c77b0f8646e", size = 2318737, upload-time = "2025-10-14T10:20:22.306Z" }, { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" },
{ url = "https://files.pythonhosted.org/packages/41/7e/6ac90673fe6cb36621a2283552897838c020db343fa86e513d3f563b196f/pydantic_core-2.41.4-cp311-cp311-win32.whl", hash = "sha256:09c2a60e55b357284b5f31f5ab275ba9f7f70b7525e18a132ec1f9160b4f1f03", size = 1974160, upload-time = "2025-10-14T10:20:23.817Z" }, { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" },
{ url = "https://files.pythonhosted.org/packages/e0/9d/7c5e24ee585c1f8b6356e1d11d40ab807ffde44d2db3b7dfd6d20b09720e/pydantic_core-2.41.4-cp311-cp311-win_amd64.whl", hash = "sha256:711156b6afb5cb1cb7c14a2cc2c4a8b4c717b69046f13c6b332d8a0a8f41ca3e", size = 2021883, upload-time = "2025-10-14T10:20:25.48Z" }, { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" },
{ url = "https://files.pythonhosted.org/packages/33/90/5c172357460fc28b2871eb4a0fb3843b136b429c6fa827e4b588877bf115/pydantic_core-2.41.4-cp311-cp311-win_arm64.whl", hash = "sha256:6cb9cf7e761f4f8a8589a45e49ed3c0d92d1d696a45a6feaee8c904b26efc2db", size = 1968026, upload-time = "2025-10-14T10:20:27.039Z" }, { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" },
{ url = "https://files.pythonhosted.org/packages/e9/81/d3b3e95929c4369d30b2a66a91db63c8ed0a98381ae55a45da2cd1cc1288/pydantic_core-2.41.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ab06d77e053d660a6faaf04894446df7b0a7e7aba70c2797465a0a1af00fc887", size = 2099043, upload-time = "2025-10-14T10:20:28.561Z" }, { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" },
{ url = "https://files.pythonhosted.org/packages/58/da/46fdac49e6717e3a94fc9201403e08d9d61aa7a770fab6190b8740749047/pydantic_core-2.41.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c53ff33e603a9c1179a9364b0a24694f183717b2e0da2b5ad43c316c956901b2", size = 1910699, upload-time = "2025-10-14T10:20:30.217Z" }, { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" },
{ url = "https://files.pythonhosted.org/packages/1e/63/4d948f1b9dd8e991a5a98b77dd66c74641f5f2e5225fee37994b2e07d391/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:304c54176af2c143bd181d82e77c15c41cbacea8872a2225dd37e6544dce9999", size = 1952121, upload-time = "2025-10-14T10:20:32.246Z" }, { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" },
{ url = "https://files.pythonhosted.org/packages/b2/a7/e5fc60a6f781fc634ecaa9ecc3c20171d238794cef69ae0af79ac11b89d7/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:025ba34a4cf4fb32f917d5d188ab5e702223d3ba603be4d8aca2f82bede432a4", size = 2041590, upload-time = "2025-10-14T10:20:34.332Z" }, { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" },
{ url = "https://files.pythonhosted.org/packages/70/69/dce747b1d21d59e85af433428978a1893c6f8a7068fa2bb4a927fba7a5ff/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9f5f30c402ed58f90c70e12eff65547d3ab74685ffe8283c719e6bead8ef53f", size = 2219869, upload-time = "2025-10-14T10:20:35.965Z" }, { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" },
{ url = "https://files.pythonhosted.org/packages/83/6a/c070e30e295403bf29c4df1cb781317b6a9bac7cd07b8d3acc94d501a63c/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd96e5d15385d301733113bcaa324c8bcf111275b7675a9c6e88bfb19fc05e3b", size = 2345169, upload-time = "2025-10-14T10:20:37.627Z" }, { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" },
{ url = "https://files.pythonhosted.org/packages/f0/83/06d001f8043c336baea7fd202a9ac7ad71f87e1c55d8112c50b745c40324/pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98f348cbb44fae6e9653c1055db7e29de67ea6a9ca03a5fa2c2e11a47cff0e47", size = 2070165, upload-time = "2025-10-14T10:20:39.246Z" }, { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" },
{ url = "https://files.pythonhosted.org/packages/14/0a/e567c2883588dd12bcbc110232d892cf385356f7c8a9910311ac997ab715/pydantic_core-2.41.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec22626a2d14620a83ca583c6f5a4080fa3155282718b6055c2ea48d3ef35970", size = 2189067, upload-time = "2025-10-14T10:20:41.015Z" }, { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" },
{ url = "https://files.pythonhosted.org/packages/f4/1d/3d9fca34273ba03c9b1c5289f7618bc4bd09c3ad2289b5420481aa051a99/pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a95d4590b1f1a43bf33ca6d647b990a88f4a3824a8c4572c708f0b45a5290ed", size = 2132997, upload-time = "2025-10-14T10:20:43.106Z" }, { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" },
{ url = "https://files.pythonhosted.org/packages/52/70/d702ef7a6cd41a8afc61f3554922b3ed8d19dd54c3bd4bdbfe332e610827/pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:f9672ab4d398e1b602feadcffcdd3af44d5f5e6ddc15bc7d15d376d47e8e19f8", size = 2307187, upload-time = "2025-10-14T10:20:44.849Z" }, { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" },
{ url = "https://files.pythonhosted.org/packages/68/4c/c06be6e27545d08b802127914156f38d10ca287a9e8489342793de8aae3c/pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:84d8854db5f55fead3b579f04bda9a36461dab0730c5d570e1526483e7bb8431", size = 2305204, upload-time = "2025-10-14T10:20:46.781Z" }, { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" },
{ url = "https://files.pythonhosted.org/packages/b0/e5/35ae4919bcd9f18603419e23c5eaf32750224a89d41a8df1a3704b69f77e/pydantic_core-2.41.4-cp312-cp312-win32.whl", hash = "sha256:9be1c01adb2ecc4e464392c36d17f97e9110fbbc906bcbe1c943b5b87a74aabd", size = 1972536, upload-time = "2025-10-14T10:20:48.39Z" }, { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" },
{ url = "https://files.pythonhosted.org/packages/1e/c2/49c5bb6d2a49eb2ee3647a93e3dae7080c6409a8a7558b075027644e879c/pydantic_core-2.41.4-cp312-cp312-win_amd64.whl", hash = "sha256:d682cf1d22bab22a5be08539dca3d1593488a99998f9f412137bc323179067ff", size = 2031132, upload-time = "2025-10-14T10:20:50.421Z" }, { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" },
{ url = "https://files.pythonhosted.org/packages/06/23/936343dbcba6eec93f73e95eb346810fc732f71ba27967b287b66f7b7097/pydantic_core-2.41.4-cp312-cp312-win_arm64.whl", hash = "sha256:833eebfd75a26d17470b58768c1834dfc90141b7afc6eb0429c21fc5a21dcfb8", size = 1969483, upload-time = "2025-10-14T10:20:52.35Z" }, { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" },
{ url = "https://files.pythonhosted.org/packages/13/d0/c20adabd181a029a970738dfe23710b52a31f1258f591874fcdec7359845/pydantic_core-2.41.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:85e050ad9e5f6fe1004eec65c914332e52f429bc0ae12d6fa2092407a462c746", size = 2105688, upload-time = "2025-10-14T10:20:54.448Z" }, { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" },
{ url = "https://files.pythonhosted.org/packages/00/b6/0ce5c03cec5ae94cca220dfecddc453c077d71363b98a4bbdb3c0b22c783/pydantic_core-2.41.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7393f1d64792763a48924ba31d1e44c2cfbc05e3b1c2c9abb4ceeadd912cced", size = 1910807, upload-time = "2025-10-14T10:20:56.115Z" }, { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" },
{ url = "https://files.pythonhosted.org/packages/68/3e/800d3d02c8beb0b5c069c870cbb83799d085debf43499c897bb4b4aaff0d/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94dab0940b0d1fb28bcab847adf887c66a27a40291eedf0b473be58761c9799a", size = 1956669, upload-time = "2025-10-14T10:20:57.874Z" }, { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" },
{ url = "https://files.pythonhosted.org/packages/60/a4/24271cc71a17f64589be49ab8bd0751f6a0a03046c690df60989f2f95c2c/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de7c42f897e689ee6f9e93c4bec72b99ae3b32a2ade1c7e4798e690ff5246e02", size = 2051629, upload-time = "2025-10-14T10:21:00.006Z" }, { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" },
{ url = "https://files.pythonhosted.org/packages/68/de/45af3ca2f175d91b96bfb62e1f2d2f1f9f3b14a734afe0bfeff079f78181/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:664b3199193262277b8b3cd1e754fb07f2c6023289c815a1e1e8fb415cb247b1", size = 2224049, upload-time = "2025-10-14T10:21:01.801Z" }, { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" },
{ url = "https://files.pythonhosted.org/packages/af/8f/ae4e1ff84672bf869d0a77af24fd78387850e9497753c432875066b5d622/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d95b253b88f7d308b1c0b417c4624f44553ba4762816f94e6986819b9c273fb2", size = 2342409, upload-time = "2025-10-14T10:21:03.556Z" }, { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" },
{ url = "https://files.pythonhosted.org/packages/18/62/273dd70b0026a085c7b74b000394e1ef95719ea579c76ea2f0cc8893736d/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1351f5bbdbbabc689727cb91649a00cb9ee7203e0a6e54e9f5ba9e22e384b84", size = 2069635, upload-time = "2025-10-14T10:21:05.385Z" }, { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" },
{ url = "https://files.pythonhosted.org/packages/30/03/cf485fff699b4cdaea469bc481719d3e49f023241b4abb656f8d422189fc/pydantic_core-2.41.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1affa4798520b148d7182da0615d648e752de4ab1a9566b7471bc803d88a062d", size = 2194284, upload-time = "2025-10-14T10:21:07.122Z" }, { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" },
{ url = "https://files.pythonhosted.org/packages/f9/7e/c8e713db32405dfd97211f2fc0a15d6bf8adb7640f3d18544c1f39526619/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7b74e18052fea4aa8dea2fb7dbc23d15439695da6cbe6cfc1b694af1115df09d", size = 2137566, upload-time = "2025-10-14T10:21:08.981Z" }, { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" },
{ url = "https://files.pythonhosted.org/packages/04/f7/db71fd4cdccc8b75990f79ccafbbd66757e19f6d5ee724a6252414483fb4/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:285b643d75c0e30abda9dc1077395624f314a37e3c09ca402d4015ef5979f1a2", size = 2316809, upload-time = "2025-10-14T10:21:10.805Z" }, { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" },
{ url = "https://files.pythonhosted.org/packages/76/63/a54973ddb945f1bca56742b48b144d85c9fc22f819ddeb9f861c249d5464/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:f52679ff4218d713b3b33f88c89ccbf3a5c2c12ba665fb80ccc4192b4608dbab", size = 2311119, upload-time = "2025-10-14T10:21:12.583Z" }, { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" },
{ url = "https://files.pythonhosted.org/packages/f8/03/5d12891e93c19218af74843a27e32b94922195ded2386f7b55382f904d2f/pydantic_core-2.41.4-cp313-cp313-win32.whl", hash = "sha256:ecde6dedd6fff127c273c76821bb754d793be1024bc33314a120f83a3c69460c", size = 1981398, upload-time = "2025-10-14T10:21:14.584Z" }, { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" },
{ url = "https://files.pythonhosted.org/packages/be/d8/fd0de71f39db91135b7a26996160de71c073d8635edfce8b3c3681be0d6d/pydantic_core-2.41.4-cp313-cp313-win_amd64.whl", hash = "sha256:d081a1f3800f05409ed868ebb2d74ac39dd0c1ff6c035b5162356d76030736d4", size = 2030735, upload-time = "2025-10-14T10:21:16.432Z" }, { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" },
{ url = "https://files.pythonhosted.org/packages/72/86/c99921c1cf6650023c08bfab6fe2d7057a5142628ef7ccfa9921f2dda1d5/pydantic_core-2.41.4-cp313-cp313-win_arm64.whl", hash = "sha256:f8e49c9c364a7edcbe2a310f12733aad95b022495ef2a8d653f645e5d20c1564", size = 1973209, upload-time = "2025-10-14T10:21:18.213Z" }, { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" },
{ url = "https://files.pythonhosted.org/packages/36/0d/b5706cacb70a8414396efdda3d72ae0542e050b591119e458e2490baf035/pydantic_core-2.41.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ed97fd56a561f5eb5706cebe94f1ad7c13b84d98312a05546f2ad036bafe87f4", size = 1877324, upload-time = "2025-10-14T10:21:20.363Z" }, { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" },
{ url = "https://files.pythonhosted.org/packages/de/2d/cba1fa02cfdea72dfb3a9babb067c83b9dff0bbcb198368e000a6b756ea7/pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a870c307bf1ee91fc58a9a61338ff780d01bfae45922624816878dce784095d2", size = 1884515, upload-time = "2025-10-14T10:21:22.339Z" }, { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" },
{ url = "https://files.pythonhosted.org/packages/07/ea/3df927c4384ed9b503c9cc2d076cf983b4f2adb0c754578dfb1245c51e46/pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d25e97bc1f5f8f7985bdc2335ef9e73843bb561eb1fa6831fdfc295c1c2061cf", size = 2042819, upload-time = "2025-10-14T10:21:26.683Z" }, { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
{ url = "https://files.pythonhosted.org/packages/6a/ee/df8e871f07074250270a3b1b82aad4cd0026b588acd5d7d3eb2fcb1471a3/pydantic_core-2.41.4-cp313-cp313t-win_amd64.whl", hash = "sha256:d405d14bea042f166512add3091c1af40437c2e7f86988f3915fabd27b1e9cd2", size = 1995866, upload-time = "2025-10-14T10:21:28.951Z" }, { url = "https://files.pythonhosted.org/packages/53/ea/bbe9095cdd771987d13c82d104a9c8559ae9aec1e29f139e286fd2e9256e/pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d", size = 2028677, upload-time = "2025-04-23T18:32:27.227Z" },
{ url = "https://files.pythonhosted.org/packages/fc/de/b20f4ab954d6d399499c33ec4fafc46d9551e11dc1858fb7f5dca0748ceb/pydantic_core-2.41.4-cp313-cp313t-win_arm64.whl", hash = "sha256:19f3684868309db5263a11bace3c45d93f6f24afa2ffe75a647583df22a2ff89", size = 1970034, upload-time = "2025-10-14T10:21:30.869Z" }, { url = "https://files.pythonhosted.org/packages/49/1d/4ac5ed228078737d457a609013e8f7edc64adc37b91d619ea965758369e5/pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954", size = 1864735, upload-time = "2025-04-23T18:32:29.019Z" },
{ url = "https://files.pythonhosted.org/packages/54/28/d3325da57d413b9819365546eb9a6e8b7cbd9373d9380efd5f74326143e6/pydantic_core-2.41.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:e9205d97ed08a82ebb9a307e92914bb30e18cdf6f6b12ca4bedadb1588a0bfe1", size = 2102022, upload-time = "2025-10-14T10:21:32.809Z" }, { url = "https://files.pythonhosted.org/packages/23/9a/2e70d6388d7cda488ae38f57bc2f7b03ee442fbcf0d75d848304ac7e405b/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb", size = 1898467, upload-time = "2025-04-23T18:32:31.119Z" },
{ url = "https://files.pythonhosted.org/packages/9e/24/b58a1bc0d834bf1acc4361e61233ee217169a42efbdc15a60296e13ce438/pydantic_core-2.41.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:82df1f432b37d832709fbcc0e24394bba04a01b6ecf1ee87578145c19cde12ac", size = 1905495, upload-time = "2025-10-14T10:21:34.812Z" }, { url = "https://files.pythonhosted.org/packages/ff/2e/1568934feb43370c1ffb78a77f0baaa5a8b6897513e7a91051af707ffdc4/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7", size = 1983041, upload-time = "2025-04-23T18:32:33.655Z" },
{ url = "https://files.pythonhosted.org/packages/fb/a4/71f759cc41b7043e8ecdaab81b985a9b6cad7cec077e0b92cff8b71ecf6b/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3b4cc4539e055cfa39a3763c939f9d409eb40e85813257dcd761985a108554", size = 1956131, upload-time = "2025-10-14T10:21:36.924Z" }, { url = "https://files.pythonhosted.org/packages/01/1a/1a1118f38ab64eac2f6269eb8c120ab915be30e387bb561e3af904b12499/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4", size = 2136503, upload-time = "2025-04-23T18:32:35.519Z" },
{ url = "https://files.pythonhosted.org/packages/b0/64/1e79ac7aa51f1eec7c4cda8cbe456d5d09f05fdd68b32776d72168d54275/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1eb1754fce47c63d2ff57fdb88c351a6c0150995890088b33767a10218eaa4e", size = 2052236, upload-time = "2025-10-14T10:21:38.927Z" }, { url = "https://files.pythonhosted.org/packages/5c/da/44754d1d7ae0f22d6d3ce6c6b1486fc07ac2c524ed8f6eca636e2e1ee49b/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b", size = 2736079, upload-time = "2025-04-23T18:32:37.659Z" },
{ url = "https://files.pythonhosted.org/packages/e9/e3/a3ffc363bd4287b80f1d43dc1c28ba64831f8dfc237d6fec8f2661138d48/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6ab5ab30ef325b443f379ddb575a34969c333004fca5a1daa0133a6ffaad616", size = 2223573, upload-time = "2025-10-14T10:21:41.574Z" }, { url = "https://files.pythonhosted.org/packages/4d/98/f43cd89172220ec5aa86654967b22d862146bc4d736b1350b4c41e7c9c03/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3", size = 2006508, upload-time = "2025-04-23T18:32:39.637Z" },
{ url = "https://files.pythonhosted.org/packages/28/27/78814089b4d2e684a9088ede3790763c64693c3d1408ddc0a248bc789126/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:31a41030b1d9ca497634092b46481b937ff9397a86f9f51bd41c4767b6fc04af", size = 2342467, upload-time = "2025-10-14T10:21:44.018Z" }, { url = "https://files.pythonhosted.org/packages/2b/cc/f77e8e242171d2158309f830f7d5d07e0531b756106f36bc18712dc439df/pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a", size = 2113693, upload-time = "2025-04-23T18:32:41.818Z" },
{ url = "https://files.pythonhosted.org/packages/92/97/4de0e2a1159cb85ad737e03306717637842c88c7fd6d97973172fb183149/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a44ac1738591472c3d020f61c6df1e4015180d6262ebd39bf2aeb52571b60f12", size = 2063754, upload-time = "2025-10-14T10:21:46.466Z" }, { url = "https://files.pythonhosted.org/packages/54/7a/7be6a7bd43e0a47c147ba7fbf124fe8aaf1200bc587da925509641113b2d/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782", size = 2074224, upload-time = "2025-04-23T18:32:44.033Z" },
{ url = "https://files.pythonhosted.org/packages/0f/50/8cb90ce4b9efcf7ae78130afeb99fd1c86125ccdf9906ef64b9d42f37c25/pydantic_core-2.41.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d72f2b5e6e82ab8f94ea7d0d42f83c487dc159c5240d8f83beae684472864e2d", size = 2196754, upload-time = "2025-10-14T10:21:48.486Z" }, { url = "https://files.pythonhosted.org/packages/2a/07/31cf8fadffbb03be1cb520850e00a8490c0927ec456e8293cafda0726184/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9", size = 2245403, upload-time = "2025-04-23T18:32:45.836Z" },
{ url = "https://files.pythonhosted.org/packages/34/3b/ccdc77af9cd5082723574a1cc1bcae7a6acacc829d7c0a06201f7886a109/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c4d1e854aaf044487d31143f541f7aafe7b482ae72a022c664b2de2e466ed0ad", size = 2137115, upload-time = "2025-10-14T10:21:50.63Z" }, { url = "https://files.pythonhosted.org/packages/b6/8d/bbaf4c6721b668d44f01861f297eb01c9b35f612f6b8e14173cb204e6240/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e", size = 2242331, upload-time = "2025-04-23T18:32:47.618Z" },
{ url = "https://files.pythonhosted.org/packages/ca/ba/e7c7a02651a8f7c52dc2cff2b64a30c313e3b57c7d93703cecea76c09b71/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b568af94267729d76e6ee5ececda4e283d07bbb28e8148bb17adad93d025d25a", size = 2317400, upload-time = "2025-10-14T10:21:52.959Z" }, { url = "https://files.pythonhosted.org/packages/bb/93/3cc157026bca8f5006250e74515119fcaa6d6858aceee8f67ab6dc548c16/pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9", size = 1910571, upload-time = "2025-04-23T18:32:49.401Z" },
{ url = "https://files.pythonhosted.org/packages/2c/ba/6c533a4ee8aec6b812c643c49bb3bd88d3f01e3cebe451bb85512d37f00f/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6d55fb8b1e8929b341cc313a81a26e0d48aa3b519c1dbaadec3a6a2b4fcad025", size = 2312070, upload-time = "2025-10-14T10:21:55.419Z" }, { url = "https://files.pythonhosted.org/packages/5b/90/7edc3b2a0d9f0dda8806c04e511a67b0b7a41d2187e2003673a996fb4310/pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3", size = 1956504, upload-time = "2025-04-23T18:32:51.287Z" },
{ url = "https://files.pythonhosted.org/packages/22/ae/f10524fcc0ab8d7f96cf9a74c880243576fd3e72bd8ce4f81e43d22bcab7/pydantic_core-2.41.4-cp314-cp314-win32.whl", hash = "sha256:5b66584e549e2e32a1398df11da2e0a7eff45d5c2d9db9d5667c5e6ac764d77e", size = 1982277, upload-time = "2025-10-14T10:21:57.474Z" }, { url = "https://files.pythonhosted.org/packages/30/68/373d55e58b7e83ce371691f6eaa7175e3a24b956c44628eb25d7da007917/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa", size = 2023982, upload-time = "2025-04-23T18:32:53.14Z" },
{ url = "https://files.pythonhosted.org/packages/b4/dc/e5aa27aea1ad4638f0c3fb41132f7eb583bd7420ee63204e2d4333a3bbf9/pydantic_core-2.41.4-cp314-cp314-win_amd64.whl", hash = "sha256:557a0aab88664cc552285316809cab897716a372afaf8efdbef756f8b890e894", size = 2024608, upload-time = "2025-10-14T10:21:59.557Z" }, { url = "https://files.pythonhosted.org/packages/a4/16/145f54ac08c96a63d8ed6442f9dec17b2773d19920b627b18d4f10a061ea/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29", size = 1858412, upload-time = "2025-04-23T18:32:55.52Z" },
{ url = "https://files.pythonhosted.org/packages/3e/61/51d89cc2612bd147198e120a13f150afbf0bcb4615cddb049ab10b81b79e/pydantic_core-2.41.4-cp314-cp314-win_arm64.whl", hash = "sha256:3f1ea6f48a045745d0d9f325989d8abd3f1eaf47dd00485912d1a3a63c623a8d", size = 1967614, upload-time = "2025-10-14T10:22:01.847Z" }, { url = "https://files.pythonhosted.org/packages/41/b1/c6dc6c3e2de4516c0bb2c46f6a373b91b5660312342a0cf5826e38ad82fa/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d", size = 1892749, upload-time = "2025-04-23T18:32:57.546Z" },
{ url = "https://files.pythonhosted.org/packages/0d/c2/472f2e31b95eff099961fa050c376ab7156a81da194f9edb9f710f68787b/pydantic_core-2.41.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6c1fe4c5404c448b13188dd8bd2ebc2bdd7e6727fa61ff481bcc2cca894018da", size = 1876904, upload-time = "2025-10-14T10:22:04.062Z" }, { url = "https://files.pythonhosted.org/packages/12/73/8cd57e20afba760b21b742106f9dbdfa6697f1570b189c7457a1af4cd8a0/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e", size = 2067527, upload-time = "2025-04-23T18:32:59.771Z" },
{ url = "https://files.pythonhosted.org/packages/4a/07/ea8eeb91173807ecdae4f4a5f4b150a520085b35454350fc219ba79e66a3/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:523e7da4d43b113bf8e7b49fa4ec0c35bf4fe66b2230bfc5c13cc498f12c6c3e", size = 1882538, upload-time = "2025-10-14T10:22:06.39Z" }, { url = "https://files.pythonhosted.org/packages/e3/d5/0bb5d988cc019b3cba4a78f2d4b3854427fc47ee8ec8e9eaabf787da239c/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c", size = 2108225, upload-time = "2025-04-23T18:33:04.51Z" },
{ url = "https://files.pythonhosted.org/packages/1e/29/b53a9ca6cd366bfc928823679c6a76c7a4c69f8201c0ba7903ad18ebae2f/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5729225de81fb65b70fdb1907fcf08c75d498f4a6f15af005aabb1fdadc19dfa", size = 2041183, upload-time = "2025-10-14T10:22:08.812Z" }, { url = "https://files.pythonhosted.org/packages/f1/c5/00c02d1571913d496aabf146106ad8239dc132485ee22efe08085084ff7c/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec", size = 2069490, upload-time = "2025-04-23T18:33:06.391Z" },
{ url = "https://files.pythonhosted.org/packages/c7/3d/f8c1a371ceebcaf94d6dd2d77c6cf4b1c078e13a5837aee83f760b4f7cfd/pydantic_core-2.41.4-cp314-cp314t-win_amd64.whl", hash = "sha256:de2cfbb09e88f0f795fd90cf955858fc2c691df65b1f21f0aa00b99f3fbc661d", size = 1993542, upload-time = "2025-10-14T10:22:11.332Z" }, { url = "https://files.pythonhosted.org/packages/22/a8/dccc38768274d3ed3a59b5d06f59ccb845778687652daa71df0cab4040d7/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052", size = 2237525, upload-time = "2025-04-23T18:33:08.44Z" },
{ url = "https://files.pythonhosted.org/packages/8a/ac/9fc61b4f9d079482a290afe8d206b8f490e9fd32d4fc03ed4fc698214e01/pydantic_core-2.41.4-cp314-cp314t-win_arm64.whl", hash = "sha256:d34f950ae05a83e0ede899c595f312ca976023ea1db100cd5aa188f7005e3ab0", size = 1973897, upload-time = "2025-10-14T10:22:13.444Z" }, { url = "https://files.pythonhosted.org/packages/d4/e7/4f98c0b125dda7cf7ccd14ba936218397b44f50a56dd8c16a3091df116c3/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c", size = 2238446, upload-time = "2025-04-23T18:33:10.313Z" },
{ url = "https://files.pythonhosted.org/packages/b0/12/5ba58daa7f453454464f92b3ca7b9d7c657d8641c48e370c3ebc9a82dd78/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:a1b2cfec3879afb742a7b0bcfa53e4f22ba96571c9e54d6a3afe1052d17d843b", size = 2122139, upload-time = "2025-10-14T10:22:47.288Z" }, { url = "https://files.pythonhosted.org/packages/ce/91/2ec36480fdb0b783cd9ef6795753c1dea13882f2e68e73bce76ae8c21e6a/pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808", size = 2066678, upload-time = "2025-04-23T18:33:12.224Z" },
{ url = "https://files.pythonhosted.org/packages/21/fb/6860126a77725c3108baecd10fd3d75fec25191d6381b6eb2ac660228eac/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:d175600d975b7c244af6eb9c9041f10059f20b8bbffec9e33fdd5ee3f67cdc42", size = 1936674, upload-time = "2025-10-14T10:22:49.555Z" }, { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" },
{ url = "https://files.pythonhosted.org/packages/de/be/57dcaa3ed595d81f8757e2b44a38240ac5d37628bce25fb20d02c7018776/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f184d657fa4947ae5ec9c47bd7e917730fa1cbb78195037e32dcbab50aca5ee", size = 1956398, upload-time = "2025-10-14T10:22:52.19Z" }, { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" },
{ url = "https://files.pythonhosted.org/packages/2f/1d/679a344fadb9695f1a6a294d739fbd21d71fa023286daeea8c0ed49e7c2b/pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed810568aeffed3edc78910af32af911c835cc39ebbfacd1f0ab5dd53028e5c", size = 2138674, upload-time = "2025-10-14T10:22:54.499Z" }, { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" },
{ url = "https://files.pythonhosted.org/packages/c4/48/ae937e5a831b7c0dc646b2ef788c27cd003894882415300ed21927c21efa/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:4f5d640aeebb438517150fdeec097739614421900e4a08db4a3ef38898798537", size = 2112087, upload-time = "2025-10-14T10:22:56.818Z" }, { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" },
{ url = "https://files.pythonhosted.org/packages/5e/db/6db8073e3d32dae017da7e0d16a9ecb897d0a4d92e00634916e486097961/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:4a9ab037b71927babc6d9e7fc01aea9e66dc2a4a34dff06ef0724a4049629f94", size = 1920387, upload-time = "2025-10-14T10:22:59.342Z" }, { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" },
{ url = "https://files.pythonhosted.org/packages/0d/c1/dd3542d072fcc336030d66834872f0328727e3b8de289c662faa04aa270e/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4dab9484ec605c3016df9ad4fd4f9a390bc5d816a3b10c6550f8424bb80b18c", size = 1951495, upload-time = "2025-10-14T10:23:02.089Z" }, { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" },
{ url = "https://files.pythonhosted.org/packages/2b/c6/db8d13a1f8ab3f1eb08c88bd00fd62d44311e3456d1e85c0e59e0a0376e7/pydantic_core-2.41.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8a5028425820731d8c6c098ab642d7b8b999758e24acae03ed38a66eca8335", size = 2139008, upload-time = "2025-10-14T10:23:04.539Z" }, { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" },
{ url = "https://files.pythonhosted.org/packages/5d/d4/912e976a2dd0b49f31c98a060ca90b353f3b73ee3ea2fd0030412f6ac5ec/pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e5ab4fc177dd41536b3c32b2ea11380dd3d4619a385860621478ac2d25ceb00", size = 2106739, upload-time = "2025-10-14T10:23:06.934Z" }, { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" },
{ url = "https://files.pythonhosted.org/packages/71/f0/66ec5a626c81eba326072d6ee2b127f8c139543f1bf609b4842978d37833/pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3d88d0054d3fa11ce936184896bed3c1c5441d6fa483b498fac6a5d0dd6f64a9", size = 1932549, upload-time = "2025-10-14T10:23:09.24Z" }, { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" },
{ url = "https://files.pythonhosted.org/packages/c4/af/625626278ca801ea0a658c2dcf290dc9f21bb383098e99e7c6a029fccfc0/pydantic_core-2.41.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b2a054a8725f05b4b6503357e0ac1c4e8234ad3b0c2ac130d6ffc66f0e170e2", size = 2135093, upload-time = "2025-10-14T10:23:11.626Z" }, { url = "https://files.pythonhosted.org/packages/08/98/dbf3fdfabaf81cda5622154fda78ea9965ac467e3239078e0dcd6df159e7/pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101", size = 2024034, upload-time = "2025-04-23T18:33:32.843Z" },
{ url = "https://files.pythonhosted.org/packages/20/f6/2fba049f54e0f4975fef66be654c597a1d005320fa141863699180c7697d/pydantic_core-2.41.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0d9db5a161c99375a0c68c058e227bee1d89303300802601d76a3d01f74e258", size = 2187971, upload-time = "2025-10-14T10:23:14.437Z" }, { url = "https://files.pythonhosted.org/packages/8d/99/7810aa9256e7f2ccd492590f86b79d370df1e9292f1f80b000b6a75bd2fb/pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64", size = 1858578, upload-time = "2025-04-23T18:33:34.912Z" },
{ url = "https://files.pythonhosted.org/packages/0e/80/65ab839a2dfcd3b949202f9d920c34f9de5a537c3646662bdf2f7d999680/pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:6273ea2c8ffdac7b7fda2653c49682db815aebf4a89243a6feccf5e36c18c347", size = 2147939, upload-time = "2025-10-14T10:23:16.831Z" }, { url = "https://files.pythonhosted.org/packages/d8/60/bc06fa9027c7006cc6dd21e48dbf39076dc39d9abbaf718a1604973a9670/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d", size = 1892858, upload-time = "2025-04-23T18:33:36.933Z" },
{ url = "https://files.pythonhosted.org/packages/44/58/627565d3d182ce6dfda18b8e1c841eede3629d59c9d7cbc1e12a03aeb328/pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:4c973add636efc61de22530b2ef83a65f39b6d6f656df97f678720e20de26caa", size = 2311400, upload-time = "2025-10-14T10:23:19.234Z" }, { url = "https://files.pythonhosted.org/packages/f2/40/9d03997d9518816c68b4dfccb88969756b9146031b61cd37f781c74c9b6a/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535", size = 2068498, upload-time = "2025-04-23T18:33:38.997Z" },
{ url = "https://files.pythonhosted.org/packages/24/06/8a84711162ad5a5f19a88cead37cca81b4b1f294f46260ef7334ae4f24d3/pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b69d1973354758007f46cf2d44a4f3d0933f10b6dc9bf15cf1356e037f6f731a", size = 2316840, upload-time = "2025-10-14T10:23:21.738Z" }, { url = "https://files.pythonhosted.org/packages/d8/62/d490198d05d2d86672dc269f52579cad7261ced64c2df213d5c16e0aecb1/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d", size = 2108428, upload-time = "2025-04-23T18:33:41.18Z" },
{ url = "https://files.pythonhosted.org/packages/aa/8b/b7bb512a4682a2f7fbfae152a755d37351743900226d29bd953aaf870eaa/pydantic_core-2.41.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3619320641fd212aaf5997b6ca505e97540b7e16418f4a241f44cdf108ffb50d", size = 2149135, upload-time = "2025-10-14T10:23:24.379Z" }, { url = "https://files.pythonhosted.org/packages/9a/ec/4cd215534fd10b8549015f12ea650a1a973da20ce46430b68fc3185573e8/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6", size = 2069854, upload-time = "2025-04-23T18:33:43.446Z" },
{ url = "https://files.pythonhosted.org/packages/7e/7d/138e902ed6399b866f7cfe4435d22445e16fff888a1c00560d9dc79a780f/pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:491535d45cd7ad7e4a2af4a5169b0d07bebf1adfd164b0368da8aa41e19907a5", size = 2104721, upload-time = "2025-10-14T10:23:26.906Z" }, { url = "https://files.pythonhosted.org/packages/1a/1a/abbd63d47e1d9b0d632fee6bb15785d0889c8a6e0a6c3b5a8e28ac1ec5d2/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca", size = 2237859, upload-time = "2025-04-23T18:33:45.56Z" },
{ url = "https://files.pythonhosted.org/packages/47/13/0525623cf94627f7b53b4c2034c81edc8491cbfc7c28d5447fa318791479/pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:54d86c0cada6aba4ec4c047d0e348cbad7063b87ae0f005d9f8c9ad04d4a92a2", size = 1931608, upload-time = "2025-10-14T10:23:29.306Z" }, { url = "https://files.pythonhosted.org/packages/80/1c/fa883643429908b1c90598fd2642af8839efd1d835b65af1f75fba4d94fe/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039", size = 2239059, upload-time = "2025-04-23T18:33:47.735Z" },
{ url = "https://files.pythonhosted.org/packages/d6/f9/744bc98137d6ef0a233f808bfc9b18cf94624bf30836a18d3b05d08bf418/pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca1124aced216b2500dc2609eade086d718e8249cb9696660ab447d50a758bd", size = 2132986, upload-time = "2025-10-14T10:23:32.057Z" }, { url = "https://files.pythonhosted.org/packages/d4/29/3cade8a924a61f60ccfa10842f75eb12787e1440e2b8660ceffeb26685e7/pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27", size = 2066661, upload-time = "2025-04-23T18:33:49.995Z" },
{ url = "https://files.pythonhosted.org/packages/17/c8/629e88920171173f6049386cc71f893dff03209a9ef32b4d2f7e7c264bcf/pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c9024169becccf0cb470ada03ee578d7348c119a0d42af3dcf9eda96e3a247c", size = 2187516, upload-time = "2025-10-14T10:23:34.871Z" },
{ url = "https://files.pythonhosted.org/packages/2e/0f/4f2734688d98488782218ca61bcc118329bf5de05bb7fe3adc7dd79b0b86/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:26895a4268ae5a2849269f4991cdc97236e4b9c010e51137becf25182daac405", size = 2146146, upload-time = "2025-10-14T10:23:37.342Z" },
{ url = "https://files.pythonhosted.org/packages/ed/f2/ab385dbd94a052c62224b99cf99002eee99dbec40e10006c78575aead256/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:ca4df25762cf71308c446e33c9b1fdca2923a3f13de616e2a949f38bf21ff5a8", size = 2311296, upload-time = "2025-10-14T10:23:40.145Z" },
{ url = "https://files.pythonhosted.org/packages/fc/8e/e4f12afe1beeb9823bba5375f8f258df0cc61b056b0195fb1cf9f62a1a58/pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5a28fcedd762349519276c36634e71853b4541079cab4acaaac60c4421827308", size = 2315386, upload-time = "2025-10-14T10:23:42.624Z" },
{ url = "https://files.pythonhosted.org/packages/48/f7/925f65d930802e3ea2eb4d5afa4cb8730c8dc0d2cb89a59dc4ed2fcb2d74/pydantic_core-2.41.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c173ddcd86afd2535e2b695217e82191580663a1d1928239f877f5a1649ef39f", size = 2147775, upload-time = "2025-10-14T10:23:45.406Z" },
] ]
[[package]] [[package]]
@@ -860,6 +836,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
{ url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
{ url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
{ url = "https://files.pythonhosted.org/packages/9f/62/67fc8e68a75f738c9200422bf65693fb79a4cd0dc5b23310e5202e978090/pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da", size = 184450, upload-time = "2025-09-25T21:33:00.618Z" },
{ url = "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917", size = 174319, upload-time = "2025-09-25T21:33:02.086Z" },
{ url = "https://files.pythonhosted.org/packages/d0/cd/f0cfc8c74f8a030017a2b9c771b7f47e5dd702c3e28e5b2071374bda2948/pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9", size = 737631, upload-time = "2025-09-25T21:33:03.25Z" },
{ url = "https://files.pythonhosted.org/packages/ef/b2/18f2bd28cd2055a79a46c9b0895c0b3d987ce40ee471cecf58a1a0199805/pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5", size = 836795, upload-time = "2025-09-25T21:33:05.014Z" },
{ url = "https://files.pythonhosted.org/packages/73/b9/793686b2d54b531203c160ef12bec60228a0109c79bae6c1277961026770/pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a", size = 750767, upload-time = "2025-09-25T21:33:06.398Z" },
{ url = "https://files.pythonhosted.org/packages/a9/86/a137b39a611def2ed78b0e66ce2fe13ee701a07c07aebe55c340ed2a050e/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926", size = 727982, upload-time = "2025-09-25T21:33:08.708Z" },
{ url = "https://files.pythonhosted.org/packages/dd/62/71c27c94f457cf4418ef8ccc71735324c549f7e3ea9d34aba50874563561/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7", size = 755677, upload-time = "2025-09-25T21:33:09.876Z" },
{ url = "https://files.pythonhosted.org/packages/29/3d/6f5e0d58bd924fb0d06c3a6bad00effbdae2de5adb5cda5648006ffbd8d3/pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0", size = 142592, upload-time = "2025-09-25T21:33:10.983Z" },
{ url = "https://files.pythonhosted.org/packages/f0/0c/25113e0b5e103d7f1490c0e947e303fe4a696c10b501dea7a9f49d4e876c/pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007", size = 158777, upload-time = "2025-09-25T21:33:15.55Z" },
] ]
[[package]] [[package]]
@@ -995,14 +980,14 @@ wheels = [
[[package]] [[package]]
name = "typing-inspection" name = "typing-inspection"
version = "0.4.2" version = "0.4.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "typing-extensions" }, { name = "typing-extensions" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
] ]
[[package]] [[package]]
@@ -1032,8 +1017,13 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" },
{ url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" },
{ url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" },
{ url = "https://files.pythonhosted.org/packages/05/52/7223011bb760fce8ddc53416beb65b83a3ea6d7d13738dde75eeb2c89679/watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8", size = 96390, upload-time = "2024-11-01T14:06:49.325Z" },
{ url = "https://files.pythonhosted.org/packages/9c/62/d2b21bc4e706d3a9d467561f487c2938cbd881c69f3808c43ac1ec242391/watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a", size = 88386, upload-time = "2024-11-01T14:06:50.536Z" },
{ url = "https://files.pythonhosted.org/packages/ea/22/1c90b20eda9f4132e4603a26296108728a8bfe9584b006bd05dd94548853/watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c", size = 89017, upload-time = "2024-11-01T14:06:51.717Z" },
{ url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" }, { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" },
{ url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" }, { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" },
{ url = "https://files.pythonhosted.org/packages/5b/79/69f2b0e8d3f2afd462029031baafb1b75d11bb62703f0e1022b2e54d49ee/watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa", size = 87903, upload-time = "2024-11-01T14:06:57.052Z" },
{ url = "https://files.pythonhosted.org/packages/e2/2b/dc048dd71c2e5f0f7ebc04dd7912981ec45793a03c0dc462438e0591ba5d/watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e", size = 88381, upload-time = "2024-11-01T14:06:58.193Z" },
{ url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" },
{ url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" },
{ url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" },
@@ -1134,4 +1124,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" }, { url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" },
{ url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" }, { url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" },
{ url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" }, { url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" },
{ url = "https://files.pythonhosted.org/packages/14/0d/d0a405dad6ab6f9f759c26d866cca66cb209bff6f8db656074d662a953dd/zstandard-0.25.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b9af1fe743828123e12b41dd8091eca1074d0c1569cc42e6e1eee98027f2bbd0", size = 795263, upload-time = "2025-09-14T22:18:21.683Z" },
{ url = "https://files.pythonhosted.org/packages/ca/aa/ceb8d79cbad6dabd4cb1178ca853f6a4374d791c5e0241a0988173e2a341/zstandard-0.25.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b14abacf83dfb5c25eb4e4a79520de9e7e205f72c9ee7702f91233ae57d33a2", size = 640560, upload-time = "2025-09-14T22:18:22.867Z" },
{ url = "https://files.pythonhosted.org/packages/88/cd/2cf6d476131b509cc122d25d3416a2d0aa17687ddbada7599149f9da620e/zstandard-0.25.0-cp39-cp39-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:a51ff14f8017338e2f2e5dab738ce1ec3b5a851f23b18c1ae1359b1eecbee6df", size = 5344244, upload-time = "2025-09-14T22:18:24.724Z" },
{ url = "https://files.pythonhosted.org/packages/5c/71/e14820b61a1c137966b7667b400b72fa4a45c836257e443f3d77607db268/zstandard-0.25.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3b870ce5a02d4b22286cf4944c628e0f0881b11b3f14667c1d62185a99e04f53", size = 5054550, upload-time = "2025-09-14T22:18:26.445Z" },
{ url = "https://files.pythonhosted.org/packages/f9/ce/26dc5a6fa956be41d0e984909224ed196ee6f91d607f0b3fd84577741a77/zstandard-0.25.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:05353cef599a7b0b98baca9b068dd36810c3ef0f42bf282583f438caf6ddcee3", size = 5401150, upload-time = "2025-09-14T22:18:28.745Z" },
{ url = "https://files.pythonhosted.org/packages/f2/1b/402cab5edcfe867465daf869d5ac2a94930931c0989633bc01d6a7d8bd68/zstandard-0.25.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:19796b39075201d51d5f5f790bf849221e58b48a39a5fc74837675d8bafc7362", size = 5448595, upload-time = "2025-09-14T22:18:30.475Z" },
{ url = "https://files.pythonhosted.org/packages/86/b2/fc50c58271a1ead0e5a0a0e6311f4b221f35954dce438ce62751b3af9b68/zstandard-0.25.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:53e08b2445a6bc241261fea89d065536f00a581f02535f8122eba42db9375530", size = 5555290, upload-time = "2025-09-14T22:18:32.336Z" },
{ url = "https://files.pythonhosted.org/packages/d2/20/5f72d6ba970690df90fdd37195c5caa992e70cb6f203f74cc2bcc0b8cf30/zstandard-0.25.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1f3689581a72eaba9131b1d9bdbfe520ccd169999219b41000ede2fca5c1bfdb", size = 5043898, upload-time = "2025-09-14T22:18:34.215Z" },
{ url = "https://files.pythonhosted.org/packages/e4/f1/131a0382b8b8d11e84690574645f528f5c5b9343e06cefd77f5fd730cd2b/zstandard-0.25.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d8c56bb4e6c795fc77d74d8e8b80846e1fb8292fc0b5060cd8131d522974b751", size = 5571173, upload-time = "2025-09-14T22:18:36.117Z" },
{ url = "https://files.pythonhosted.org/packages/53/f6/2a37931023f737fd849c5c28def57442bbafadb626da60cf9ed58461fe24/zstandard-0.25.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:53f94448fe5b10ee75d246497168e5825135d54325458c4bfffbaafabcc0a577", size = 4958261, upload-time = "2025-09-14T22:18:38.098Z" },
{ url = "https://files.pythonhosted.org/packages/b5/52/ca76ed6dbfd8845a5563d3af4e972da3b9da8a9308ca6b56b0b929d93e23/zstandard-0.25.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c2ba942c94e0691467ab901fc51b6f2085ff48f2eea77b1a48240f011e8247c7", size = 5265680, upload-time = "2025-09-14T22:18:39.834Z" },
{ url = "https://files.pythonhosted.org/packages/7a/59/edd117dedb97a768578b49fb2f1156defb839d1aa5b06200a62be943667f/zstandard-0.25.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:07b527a69c1e1c8b5ab1ab14e2afe0675614a09182213f21a0717b62027b5936", size = 5439747, upload-time = "2025-09-14T22:18:41.647Z" },
{ url = "https://files.pythonhosted.org/packages/75/71/c2e9234643dcfbd6c5e975e9a2b0050e1b2afffda6c3a959e1b87997bc80/zstandard-0.25.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:51526324f1b23229001eb3735bc8c94f9c578b1bd9e867a0a646a3b17109f388", size = 5818805, upload-time = "2025-09-14T22:18:43.602Z" },
{ url = "https://files.pythonhosted.org/packages/f5/93/8ebc19f0a31c44ea0e7348f9b0d4b326ed413b6575a3c6ff4ed50222abb6/zstandard-0.25.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89c4b48479a43f820b749df49cd7ba2dbc2b1b78560ecb5ab52985574fd40b27", size = 5362280, upload-time = "2025-09-14T22:18:45.625Z" },
{ url = "https://files.pythonhosted.org/packages/b8/e9/29cc59d4a9d51b3fd8b477d858d0bd7ab627f700908bf1517f46ddd470ae/zstandard-0.25.0-cp39-cp39-win32.whl", hash = "sha256:1cd5da4d8e8ee0e88be976c294db744773459d51bb32f707a0f166e5ad5c8649", size = 436460, upload-time = "2025-09-14T22:18:49.077Z" },
{ url = "https://files.pythonhosted.org/packages/41/b5/bc7a92c116e2ef32dc8061c209d71e97ff6df37487d7d39adb51a343ee89/zstandard-0.25.0-cp39-cp39-win_amd64.whl", hash = "sha256:37daddd452c0ffb65da00620afb8e17abd4adaae6ce6310702841760c2c26860", size = 506097, upload-time = "2025-09-14T22:18:47.342Z" },
] ]
+1 -3
View File
@@ -38,10 +38,8 @@ Each checkpointer should conform to `langgraph.checkpoint.base.BaseCheckpointSav
- `.put_writes` - Store intermediate writes linked to a checkpoint (i.e. pending writes). - `.put_writes` - Store intermediate writes linked to a checkpoint (i.e. pending writes).
- `.get_tuple` - Fetch a checkpoint tuple using for a given configuration (`thread_id` and `checkpoint_id`). - `.get_tuple` - Fetch a checkpoint tuple using for a given configuration (`thread_id` and `checkpoint_id`).
- `.list` - List checkpoints that match a given configuration and filter criteria. - `.list` - List checkpoints that match a given configuration and filter criteria.
- `.delete_thread()` - Delete all checkpoints and writes associated with a thread.
- `.get_next_version()` - Generate the next version ID for a channel.
If the checkpointer will be used with asynchronous graph execution (i.e. executing the graph via `.ainvoke`, `.astream`, `.abatch`), checkpointer must implement asynchronous versions of the above methods (`.aput`, `.aput_writes`, `.aget_tuple`, `.alist`). Similarly, the checkpointer must implement `.adelete_thread()` if asynchronous thread cleanup is desired. The base class provides a default implementation of `.get_next_version()` that generates an integer sequence starting from 1, but this method should be overridden for custom versioning schemes. If the checkpointer will be used with asynchronous graph execution (i.e. executing the graph via `.ainvoke`, `.astream`, `.abatch`), checkpointer must implement asynchronous versions of the above methods (`.aput`, `.aput_writes`, `.aget_tuple`, `.alist`).
## Usage ## Usage
@@ -8,6 +8,7 @@ from typing import ( # noqa: UP035
NamedTuple, NamedTuple,
TypedDict, TypedDict,
TypeVar, TypeVar,
Union,
) )
from langchain_core.runnables import RunnableConfig from langchain_core.runnables import RunnableConfig
@@ -34,17 +35,17 @@ class CheckpointMetadata(TypedDict, total=False):
source: Literal["input", "loop", "update", "fork"] source: Literal["input", "loop", "update", "fork"]
"""The source of the checkpoint. """The source of the checkpoint.
- `"input"`: The checkpoint was created from an input to invoke/stream/batch. - "input": The checkpoint was created from an input to invoke/stream/batch.
- `"loop"`: The checkpoint was created from inside the pregel loop. - "loop": The checkpoint was created from inside the pregel loop.
- `"update"`: The checkpoint was created from a manual state update. - "update": The checkpoint was created from a manual state update.
- `"fork"`: The checkpoint was created as a copy of another checkpoint. - "fork": The checkpoint was created as a copy of another checkpoint.
""" """
step: int step: int
"""The step number of the checkpoint. """The step number of the checkpoint.
`-1` for the first `"input"` checkpoint. -1 for the first "input" checkpoint.
`0` for the first `"loop"` checkpoint. 0 for the first "loop" checkpoint.
`...` for the `nth` checkpoint afterwards. ... for the nth checkpoint afterwards.
""" """
parents: dict[str, str] parents: dict[str, str]
"""The IDs of the parent checkpoints. """The IDs of the parent checkpoints.
@@ -53,7 +54,7 @@ class CheckpointMetadata(TypedDict, total=False):
""" """
ChannelVersions = dict[str, str | int | float] ChannelVersions = dict[str, Union[str, int, float]]
class Checkpoint(TypedDict): class Checkpoint(TypedDict):
@@ -147,7 +148,7 @@ class BaseCheckpointSaver(Generic[V]):
config: Configuration specifying which checkpoint to retrieve. config: Configuration specifying which checkpoint to retrieve.
Returns: Returns:
The requested checkpoint, or `None` if not found. Optional[Checkpoint]: The requested checkpoint, or None if not found.
""" """
if value := self.get_tuple(config): if value := self.get_tuple(config):
return value.checkpoint return value.checkpoint
@@ -159,7 +160,7 @@ class BaseCheckpointSaver(Generic[V]):
config: Configuration specifying which checkpoint to retrieve. config: Configuration specifying which checkpoint to retrieve.
Returns: Returns:
The requested checkpoint tuple, or `None` if not found. Optional[CheckpointTuple]: The requested checkpoint tuple, or None if not found.
Raises: Raises:
NotImplementedError: Implement this method in your custom checkpoint saver. NotImplementedError: Implement this method in your custom checkpoint saver.
@@ -183,7 +184,7 @@ class BaseCheckpointSaver(Generic[V]):
limit: Maximum number of checkpoints to return. limit: Maximum number of checkpoints to return.
Returns: Returns:
Iterator of matching checkpoint tuples. Iterator[CheckpointTuple]: Iterator of matching checkpoint tuples.
Raises: Raises:
NotImplementedError: Implement this method in your custom checkpoint saver. NotImplementedError: Implement this method in your custom checkpoint saver.
@@ -251,7 +252,7 @@ class BaseCheckpointSaver(Generic[V]):
config: Configuration specifying which checkpoint to retrieve. config: Configuration specifying which checkpoint to retrieve.
Returns: Returns:
The requested checkpoint, or `None` if not found. Optional[Checkpoint]: The requested checkpoint, or None if not found.
""" """
if value := await self.aget_tuple(config): if value := await self.aget_tuple(config):
return value.checkpoint return value.checkpoint
@@ -263,7 +264,7 @@ class BaseCheckpointSaver(Generic[V]):
config: Configuration specifying which checkpoint to retrieve. config: Configuration specifying which checkpoint to retrieve.
Returns: Returns:
The requested checkpoint tuple, or `None` if not found. Optional[CheckpointTuple]: The requested checkpoint tuple, or None if not found.
Raises: Raises:
NotImplementedError: Implement this method in your custom checkpoint saver. NotImplementedError: Implement this method in your custom checkpoint saver.
@@ -287,7 +288,7 @@ class BaseCheckpointSaver(Generic[V]):
limit: Maximum number of checkpoints to return. limit: Maximum number of checkpoints to return.
Returns: Returns:
Async iterator of matching checkpoint tuples. AsyncIterator[CheckpointTuple]: Async iterator of matching checkpoint tuples.
Raises: Raises:
NotImplementedError: Implement this method in your custom checkpoint saver. NotImplementedError: Implement this method in your custom checkpoint saver.
@@ -352,11 +353,11 @@ class BaseCheckpointSaver(Generic[V]):
def get_next_version(self, current: V | None, channel: None) -> V: def get_next_version(self, current: V | None, channel: None) -> V:
"""Generate the next version ID for a channel. """Generate the next version ID for a channel.
Default is to use integer versions, incrementing by `1`. If you override, you can use `str`/`int`/`float` Default is to use integer versions, incrementing by 1. If you override, you can use str/int/float versions,
versions, as long as they are monotonically increasing. as long as they are monotonically increasing.
Args: Args:
current: The current version identifier (`int`, `float`, or `str`). current: The current version identifier (int, float, or str).
channel: Deprecated argument, kept for backwards compatibility. channel: Deprecated argument, kept for backwards compatibility.
Returns: Returns:
@@ -39,10 +39,10 @@ class InMemorySaver(
Only use `InMemorySaver` for debugging or testing purposes. Only use `InMemorySaver` for debugging or testing purposes.
For production use cases we recommend installing [langgraph-checkpoint-postgres](https://pypi.org/project/langgraph-checkpoint-postgres/) and using `PostgresSaver` / `AsyncPostgresSaver`. For production use cases we recommend installing [langgraph-checkpoint-postgres](https://pypi.org/project/langgraph-checkpoint-postgres/) and using `PostgresSaver` / `AsyncPostgresSaver`.
If you are using LangSmith Deployment, no checkpointer needs to be specified. The correct managed checkpointer will be used automatically. If you are using the LangGraph Platform, no checkpointer needs to be specified. The correct managed checkpointer will be used automatically.
Args: Args:
serde: The serializer to use for serializing and deserializing checkpoints. serde: The serializer to use for serializing and deserializing checkpoints. Defaults to None.
Examples: Examples:
@@ -133,7 +133,7 @@ class InMemorySaver(
"""Get a checkpoint tuple from the in-memory storage. """Get a checkpoint tuple from the in-memory storage.
This method retrieves a checkpoint tuple from the in-memory storage based on the This method retrieves a checkpoint tuple from the in-memory storage based on the
provided config. If the config contains a `checkpoint_id` key, the checkpoint with provided config. If the config contains a "checkpoint_id" key, the checkpoint with
the matching thread ID and timestamp is retrieved. Otherwise, the latest checkpoint the matching thread ID and timestamp is retrieved. Otherwise, the latest checkpoint
for the given thread ID is retrieved. for the given thread ID is retrieved.
@@ -141,7 +141,7 @@ class InMemorySaver(
config: The config to use for retrieving the checkpoint. config: The config to use for retrieving the checkpoint.
Returns: Returns:
The retrieved checkpoint tuple, or None if no matching checkpoint was found. Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.
""" """
thread_id: str = config["configurable"]["thread_id"] thread_id: str = config["configurable"]["thread_id"]
checkpoint_ns: str = config["configurable"].get("checkpoint_ns", "") checkpoint_ns: str = config["configurable"].get("checkpoint_ns", "")
@@ -231,7 +231,7 @@ class InMemorySaver(
limit: Maximum number of checkpoints to return. limit: Maximum number of checkpoints to return.
Yields: Yields:
An iterator of matching checkpoint tuples. Iterator[CheckpointTuple]: An iterator of matching checkpoint tuples.
""" """
thread_ids = (config["configurable"]["thread_id"],) if config else self.storage thread_ids = (config["configurable"]["thread_id"],) if config else self.storage
config_checkpoint_ns = ( config_checkpoint_ns = (
@@ -423,16 +423,16 @@ class InMemorySaver(
del self.blobs[k] del self.blobs[k]
async def aget_tuple(self, config: RunnableConfig) -> CheckpointTuple | None: async def aget_tuple(self, config: RunnableConfig) -> CheckpointTuple | None:
"""Asynchronous version of `get_tuple`. """Asynchronous version of get_tuple.
This method is an asynchronous wrapper around `get_tuple` that runs the synchronous This method is an asynchronous wrapper around get_tuple that runs the synchronous
method in a separate thread using asyncio. method in a separate thread using asyncio.
Args: Args:
config: The config to use for retrieving the checkpoint. config: The config to use for retrieving the checkpoint.
Returns: Returns:
The retrieved checkpoint tuple, or None if no matching checkpoint was found. Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.
""" """
return self.get_tuple(config) return self.get_tuple(config)
@@ -444,16 +444,16 @@ class InMemorySaver(
before: RunnableConfig | None = None, before: RunnableConfig | None = None,
limit: int | None = None, limit: int | None = None,
) -> AsyncIterator[CheckpointTuple]: ) -> AsyncIterator[CheckpointTuple]:
"""Asynchronous version of `list`. """Asynchronous version of list.
This method is an asynchronous wrapper around `list` that runs the synchronous This method is an asynchronous wrapper around list that runs the synchronous
method in a separate thread using asyncio. method in a separate thread using asyncio.
Args: Args:
config: The config to use for listing the checkpoints. config: The config to use for listing the checkpoints.
Yields: Yields:
An asynchronous iterator of checkpoint tuples. AsyncIterator[CheckpointTuple]: An asynchronous iterator of checkpoint tuples.
""" """
for item in self.list(config, filter=filter, before=before, limit=limit): for item in self.list(config, filter=filter, before=before, limit=limit):
yield item yield item
@@ -465,7 +465,7 @@ class InMemorySaver(
metadata: CheckpointMetadata, metadata: CheckpointMetadata,
new_versions: ChannelVersions, new_versions: ChannelVersions,
) -> RunnableConfig: ) -> RunnableConfig:
"""Asynchronous version of `put`. """Asynchronous version of put.
Args: Args:
config: The config to associate with the checkpoint. config: The config to associate with the checkpoint.
@@ -485,9 +485,9 @@ class InMemorySaver(
task_id: str, task_id: str,
task_path: str = "", task_path: str = "",
) -> None: ) -> None:
"""Asynchronous version of `put_writes`. """Asynchronous version of put_writes.
This method is an asynchronous wrapper around `put_writes` that runs the synchronous This method is an asynchronous wrapper around put_writes that runs the synchronous
method in a separate thread using asyncio. method in a separate thread using asyncio.
Args: Args:
@@ -1,6 +1,6 @@
from __future__ import annotations from __future__ import annotations
from typing import Any, Protocol, runtime_checkable from typing import Any, Protocol
class UntypedSerializerProtocol(Protocol): class UntypedSerializerProtocol(Protocol):
@@ -11,14 +11,13 @@ class UntypedSerializerProtocol(Protocol):
def loads(self, data: bytes) -> Any: ... def loads(self, data: bytes) -> Any: ...
@runtime_checkable class SerializerProtocol(UntypedSerializerProtocol, Protocol):
class SerializerProtocol(Protocol):
"""Protocol for serialization and deserialization of objects. """Protocol for serialization and deserialization of objects.
- `dumps`: Serialize an object to bytes. - `dumps`: Serialize an object to bytes.
- `dumps_typed`: Serialize an object to a tuple `(type, bytes)`. - `dumps_typed`: Serialize an object to a tuple (type, bytes).
- `loads`: Deserialize an object from bytes. - `loads`: Deserialize an object from bytes.
- `loads_typed`: Deserialize an object from a tuple `(type, bytes)`. - `loads_typed`: Deserialize an object from a tuple (type, bytes).
Valid implementations include the `pickle`, `json` and `orjson` modules. Valid implementations include the `pickle`, `json` and `orjson` modules.
""" """
@@ -32,6 +31,12 @@ class SerializerCompat(SerializerProtocol):
def __init__(self, serde: UntypedSerializerProtocol) -> None: def __init__(self, serde: UntypedSerializerProtocol) -> None:
self.serde = serde self.serde = serde
def dumps(self, obj: Any) -> bytes:
return self.serde.dumps(obj)
def loads(self, data: bytes) -> Any:
return self.serde.loads(data)
def dumps_typed(self, obj: Any) -> tuple[str, bytes]: def dumps_typed(self, obj: Any) -> tuple[str, bytes]:
return type(obj).__name__, self.serde.dumps(obj) return type(obj).__name__, self.serde.dumps(obj)
@@ -44,7 +49,7 @@ def maybe_add_typed_methods(
) -> SerializerProtocol: ) -> SerializerProtocol:
"""Wrap serde old serde implementations in a class with loads_typed and dumps_typed for backwards compatibility.""" """Wrap serde old serde implementations in a class with loads_typed and dumps_typed for backwards compatibility."""
if not isinstance(serde, SerializerProtocol): if not hasattr(serde, "loads_typed") or not hasattr(serde, "dumps_typed"):
return SerializerCompat(serde) return SerializerCompat(serde)
return serde return serde
@@ -14,8 +14,14 @@ class EncryptedSerializer(SerializerProtocol):
self.cipher = cipher self.cipher = cipher
self.serde = serde self.serde = serde
def dumps(self, obj: Any) -> bytes:
return self.serde.dumps(obj)
def loads(self, data: bytes) -> Any:
return self.serde.loads(data)
def dumps_typed(self, obj: Any) -> tuple[str, bytes]: def dumps_typed(self, obj: Any) -> tuple[str, bytes]:
"""Serialize an object to a tuple `(type, bytes)` and encrypt the bytes.""" """Serialize an object to a tuple (type, bytes) and encrypt the bytes."""
# serialize data # serialize data
typ, data = self.serde.dumps_typed(obj) typ, data = self.serde.dumps_typed(obj)
# encrypt data # encrypt data
@@ -39,7 +45,7 @@ class EncryptedSerializer(SerializerProtocol):
def from_pycryptodome_aes( def from_pycryptodome_aes(
cls, serde: SerializerProtocol = JsonPlusSerializer(), **kwargs: Any cls, serde: SerializerProtocol = JsonPlusSerializer(), **kwargs: Any
) -> "EncryptedSerializer": ) -> "EncryptedSerializer":
"""Create an `EncryptedSerializer` using AES encryption.""" """Create an EncryptedSerializer using AES encryption."""
try: try:
from Crypto.Cipher import AES # type: ignore from Crypto.Cipher import AES # type: ignore
except ImportError: except ImportError:
@@ -4,13 +4,12 @@ import dataclasses
import decimal import decimal
import importlib import importlib
import json import json
import logging
import pathlib import pathlib
import pickle import pickle
import re import re
import sys import sys
from collections import deque from collections import deque
from collections.abc import Callable, Sequence from collections.abc import Sequence
from datetime import date, datetime, time, timedelta, timezone from datetime import date, datetime, time, timedelta, timezone
from enum import Enum from enum import Enum
from inspect import isclass from inspect import isclass
@@ -22,12 +21,13 @@ from ipaddress import (
IPv6Interface, IPv6Interface,
IPv6Network, IPv6Network,
) )
from typing import Any, Literal from typing import Any, Callable, cast
from uuid import UUID from uuid import UUID
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
import ormsgpack import ormsgpack
from langchain_core.load.load import Reviver from langchain_core.load.load import Reviver
from langchain_core.load.serializable import Serializable
from langgraph.checkpoint.serde.base import SerializerProtocol from langgraph.checkpoint.serde.base import SerializerProtocol
from langgraph.checkpoint.serde.types import SendProtocol from langgraph.checkpoint.serde.types import SendProtocol
@@ -35,31 +35,18 @@ from langgraph.store.base import Item
LC_REVIVER = Reviver() LC_REVIVER = Reviver()
EMPTY_BYTES = b"" EMPTY_BYTES = b""
logger = logging.getLogger(__name__)
class JsonPlusSerializer(SerializerProtocol): class JsonPlusSerializer(SerializerProtocol):
"""Serializer that uses ormsgpack, with optional fallbacks. """Serializer that uses ormsgpack, with a fallback to extended JSON serializer."""
Security note: this serializer is intended for use within the BaseCheckpointSaver
class and called within the Pregel loop. It should not be used on untrusted
python objects. If an attacker can write directly to your checkpoint database,
they may be able to trigger code execution when data is deserialized.
"""
def __init__( def __init__(
self, self,
*, *,
pickle_fallback: bool = False, pickle_fallback: bool = False,
allowed_json_modules: Sequence[tuple[str, ...]] | Literal[True] | None = None,
__unpack_ext_hook__: Callable[[int, bytes], Any] | None = None, __unpack_ext_hook__: Callable[[int, bytes], Any] | None = None,
) -> None: ) -> None:
self.pickle_fallback = pickle_fallback self.pickle_fallback = pickle_fallback
self._allowed_modules = (
{mod_and_name for mod_and_name in allowed_json_modules}
if allowed_json_modules and allowed_json_modules is not True
else (allowed_json_modules if allowed_json_modules is True else None)
)
self._unpack_ext_hook = ( self._unpack_ext_hook = (
__unpack_ext_hook__ __unpack_ext_hook__
if __unpack_ext_hook__ is not None if __unpack_ext_hook__ is not None
@@ -87,90 +74,134 @@ class JsonPlusSerializer(SerializerProtocol):
out["kwargs"] = kwargs out["kwargs"] = kwargs
return out return out
def _default(self, obj: Any) -> str | dict[str, Any]:
if isinstance(obj, Serializable):
return cast(dict[str, Any], obj.to_json())
elif hasattr(obj, "model_dump") and callable(obj.model_dump):
return self._encode_constructor_args(
obj.__class__, method=(None, "model_construct"), kwargs=obj.model_dump()
)
elif hasattr(obj, "dict") and callable(obj.dict):
return self._encode_constructor_args(
obj.__class__, method=(None, "construct"), kwargs=obj.dict()
)
elif hasattr(obj, "_asdict") and callable(obj._asdict):
return self._encode_constructor_args(obj.__class__, kwargs=obj._asdict())
elif isinstance(obj, pathlib.Path):
return self._encode_constructor_args(pathlib.Path, args=obj.parts)
elif isinstance(obj, re.Pattern):
return self._encode_constructor_args(
re.compile, args=(obj.pattern, obj.flags)
)
elif isinstance(obj, UUID):
return self._encode_constructor_args(UUID, args=(obj.hex,))
elif isinstance(obj, decimal.Decimal):
return self._encode_constructor_args(decimal.Decimal, args=(str(obj),))
elif isinstance(obj, (set, frozenset, deque)):
return self._encode_constructor_args(type(obj), args=(tuple(obj),))
elif isinstance(obj, (IPv4Address, IPv4Interface, IPv4Network)):
return self._encode_constructor_args(obj.__class__, args=(str(obj),))
elif isinstance(obj, (IPv6Address, IPv6Interface, IPv6Network)):
return self._encode_constructor_args(obj.__class__, args=(str(obj),))
elif isinstance(obj, datetime):
return self._encode_constructor_args(
datetime, method="fromisoformat", args=(obj.isoformat(),)
)
elif isinstance(obj, timezone):
return self._encode_constructor_args(
timezone,
args=obj.__getinitargs__(), # type: ignore[attr-defined]
)
elif isinstance(obj, ZoneInfo):
return self._encode_constructor_args(ZoneInfo, args=(obj.key,))
elif isinstance(obj, timedelta):
return self._encode_constructor_args(
timedelta, args=(obj.days, obj.seconds, obj.microseconds)
)
elif isinstance(obj, date):
return self._encode_constructor_args(
date, args=(obj.year, obj.month, obj.day)
)
elif isinstance(obj, time):
return self._encode_constructor_args(
time,
args=(obj.hour, obj.minute, obj.second, obj.microsecond, obj.tzinfo),
kwargs={"fold": obj.fold},
)
elif dataclasses.is_dataclass(obj):
return self._encode_constructor_args(
obj.__class__,
kwargs={
field.name: getattr(obj, field.name)
for field in dataclasses.fields(obj)
},
)
elif isinstance(obj, Enum):
return self._encode_constructor_args(obj.__class__, args=(obj.value,))
elif isinstance(obj, SendProtocol):
return self._encode_constructor_args(
obj.__class__, kwargs={"node": obj.node, "arg": obj.arg}
)
elif isinstance(obj, (bytes, bytearray)):
return self._encode_constructor_args(
obj.__class__, method="fromhex", args=(obj.hex(),)
)
elif isinstance(obj, BaseException):
return repr(obj)
else:
raise TypeError(
f"Object of type {obj.__class__.__name__} is not JSON serializable"
)
def _reviver(self, value: dict[str, Any]) -> Any: def _reviver(self, value: dict[str, Any]) -> Any:
if self._allowed_modules and ( if (
value.get("lc", None) == 2 value.get("lc", None) == 2
and value.get("type", None) == "constructor" and value.get("type", None) == "constructor"
and value.get("id", None) is not None and value.get("id", None) is not None
): ):
try: try:
return self._revive_lc2(value) # Get module and class name
except InvalidModuleError as e: [*module, name] = value["id"]
logger.warning( # Import module
"Object %s is not in the deserialization allowlist.\n%s", mod = importlib.import_module(".".join(module))
value["id"], # Import class
e.message, cls = getattr(mod, name)
) # Instantiate class
method = value.get("method")
if isinstance(method, str):
methods = [getattr(cls, method)]
elif isinstance(method, list):
methods = [
cls if method is None else getattr(cls, method)
for method in method
]
else:
methods = [cls]
args = value.get("args")
kwargs = value.get("kwargs")
for method in methods:
try:
if isclass(method) and issubclass(method, BaseException):
return None
if args and kwargs:
return method(*args, **kwargs)
elif args:
return method(*args)
elif kwargs:
return method(**kwargs)
else:
return method()
except Exception:
continue
except Exception:
return None
return LC_REVIVER(value) return LC_REVIVER(value)
def _revive_lc2(self, value: dict[str, Any]) -> Any: def dumps(self, obj: Any) -> bytes:
self._check_allowed_modules(value) return json.dumps(obj, default=self._default, ensure_ascii=False).encode(
"utf-8", "ignore"
[*module, name] = value["id"]
try:
mod = importlib.import_module(".".join(module))
cls = getattr(mod, name)
method = value.get("method")
if isinstance(method, str):
methods = [getattr(cls, method)]
elif isinstance(method, list):
methods = [cls if m is None else getattr(cls, m) for m in method]
else:
methods = [cls]
args = value.get("args")
kwargs = value.get("kwargs")
for method in methods:
try:
if isclass(method) and issubclass(method, BaseException):
return None
if args and kwargs:
return method(*args, **kwargs)
elif args:
return method(*args)
elif kwargs:
return method(**kwargs)
else:
return method()
except Exception:
continue
except Exception:
return None
def _check_allowed_modules(self, value: dict[str, Any]) -> None:
needed = tuple(value["id"])
method = value.get("method")
if isinstance(method, list):
method_display = ",".join(m or "<init>" for m in method)
elif isinstance(method, str):
method_display = method
else:
method_display = "<init>"
dotted = ".".join(needed)
if not self._allowed_modules:
raise InvalidModuleError(
f"Refused to deserialize JSON constructor: {dotted} (method: {method_display}). "
"No allowed_json_modules configured.\n\n"
"Unblock with ONE of:\n"
f" • JsonPlusSerializer(allowed_json_modules=[{needed!r}, ...])\n"
" • (DANGEROUS) JsonPlusSerializer(allowed_json_modules=True)\n\n"
"Note: Prefix allowlists are intentionally unsupported; prefer exact symbols "
"or plain-JSON representations revived without import-time side effects."
)
if self._allowed_modules is True:
return
if needed in self._allowed_modules:
return
raise InvalidModuleError(
f"Refused to deserialize JSON constructor: {dotted} (method: {method_display}). "
"Symbol is not in the deserialization allowlist.\n\n"
"Add exactly this symbol to unblock:\n"
f" JsonPlusSerializer(allowed_json_modules=[{needed!r}, ...])\n"
"Or, as a last resort (DANGEROUS):\n"
" JsonPlusSerializer(allowed_json_modules=True)"
) )
def dumps_typed(self, obj: Any) -> tuple[str, bytes]: def dumps_typed(self, obj: Any) -> tuple[str, bytes]:
@@ -184,10 +215,15 @@ class JsonPlusSerializer(SerializerProtocol):
try: try:
return "msgpack", _msgpack_enc(obj) return "msgpack", _msgpack_enc(obj)
except ormsgpack.MsgpackEncodeError as exc: except ormsgpack.MsgpackEncodeError as exc:
if self.pickle_fallback: if "valid UTF-8" in str(exc):
return "json", self.dumps(obj)
elif self.pickle_fallback:
return "pickle", pickle.dumps(obj) return "pickle", pickle.dumps(obj)
raise exc raise exc
def loads(self, data: bytes) -> Any:
return json.loads(data, object_hook=self._reviver)
def loads_typed(self, data: tuple[str, bytes]) -> Any: def loads_typed(self, data: tuple[str, bytes]) -> Any:
type_, data_ = data type_, data_ = data
if type_ == "null": if type_ == "null":
@@ -197,7 +233,7 @@ class JsonPlusSerializer(SerializerProtocol):
elif type_ == "bytearray": elif type_ == "bytearray":
return bytearray(data_) return bytearray(data_)
elif type_ == "json": elif type_ == "json":
return json.loads(data_, object_hook=self._reviver) return self.loads(data_)
elif type_ == "msgpack": elif type_ == "msgpack":
return ormsgpack.unpackb( return ormsgpack.unpackb(
data_, ext_hook=self._unpack_ext_hook, option=ormsgpack.OPT_NON_STR_KEYS data_, ext_hook=self._unpack_ext_hook, option=ormsgpack.OPT_NON_STR_KEYS
@@ -627,20 +663,12 @@ def _msgpack_ext_hook_to_json(code: int, data: bytes) -> Any:
return return
class InvalidModuleError(Exception):
"""Exception raised when a module is not in the allowlist."""
def __init__(self, message: str):
self.message = message
_option = ( _option = (
ormsgpack.OPT_NON_STR_KEYS ormsgpack.OPT_NON_STR_KEYS
| ormsgpack.OPT_PASSTHROUGH_DATACLASS | ormsgpack.OPT_PASSTHROUGH_DATACLASS
| ormsgpack.OPT_PASSTHROUGH_DATETIME | ormsgpack.OPT_PASSTHROUGH_DATETIME
| ormsgpack.OPT_PASSTHROUGH_ENUM | ormsgpack.OPT_PASSTHROUGH_ENUM
| ormsgpack.OPT_PASSTHROUGH_UUID | ormsgpack.OPT_PASSTHROUGH_UUID
| ormsgpack.OPT_REPLACE_SURROGATES
) )
@@ -1,6 +1,7 @@
from collections.abc import Sequence from collections.abc import Sequence
from typing import ( from typing import (
Any, Any,
Optional,
Protocol, Protocol,
TypeVar, TypeVar,
runtime_checkable, runtime_checkable,
@@ -27,9 +28,9 @@ class ChannelProtocol(Protocol[Value, Update, C]):
@property @property
def UpdateType(self) -> Any: ... def UpdateType(self) -> Any: ...
def checkpoint(self) -> C | None: ... def checkpoint(self) -> Optional[C]: ...
def from_checkpoint(self, checkpoint: C | None) -> Self: ... def from_checkpoint(self, checkpoint: Optional[C]) -> Self: ...
def update(self, values: Sequence[Update]) -> bool: ... def update(self, values: Sequence[Update]) -> bool: ...
+97 -146
View File
@@ -4,9 +4,9 @@ Stores provide long-term memory that persists across threads and conversations.
Supports hierarchical namespaces, key-value storage, and optional vector search. Supports hierarchical namespaces, key-value storage, and optional vector search.
Core types: Core types:
- `BaseStore`: Store interface with sync/async operations - BaseStore: Store interface with sync/async operations
- `Item`: Stored key-value pairs with metadata - Item: Stored key-value pairs with metadata
- `Op`: Get/Put/Search/List operations - Op: Get/Put/Search/List operations
""" """
from __future__ import annotations from __future__ import annotations
@@ -19,6 +19,7 @@ from typing import (
Literal, Literal,
NamedTuple, NamedTuple,
TypedDict, TypedDict,
Union,
cast, cast,
) )
@@ -56,7 +57,7 @@ class Item:
key: Unique identifier within the namespace. key: Unique identifier within the namespace.
namespace: Hierarchical path defining the collection in which this document resides. namespace: Hierarchical path defining the collection in which this document resides.
Represented as a tuple of strings, allowing for nested categorization. Represented as a tuple of strings, allowing for nested categorization.
For example: `("documents", 'user123')` For example: ("documents", 'user123')
created_at: Timestamp of item creation. created_at: Timestamp of item creation.
updated_at: Timestamp of last update. updated_at: Timestamp of last update.
""" """
@@ -163,7 +164,6 @@ class GetOp(NamedTuple):
???+ example "Examples" ???+ example "Examples"
Basic item retrieval: Basic item retrieval:
```python ```python
GetOp(namespace=("users", "profiles"), key="user123") GetOp(namespace=("users", "profiles"), key="user123")
GetOp(namespace=("cache", "embeddings"), key="doc456") GetOp(namespace=("cache", "embeddings"), key="doc456")
@@ -207,14 +207,11 @@ class SearchOp(NamedTuple):
within a given namespace prefix. It provides pagination through limit and offset within a given namespace prefix. It provides pagination through limit and offset
parameters. parameters.
!!! note Note:
Natural language search support depends on your store implementation. Natural language search support depends on your store implementation.
???+ example "Examples" ???+ example "Examples"
Search with filters and pagination: Search with filters and pagination:
```python ```python
SearchOp( SearchOp(
namespace_prefix=("documents",), namespace_prefix=("documents",),
@@ -225,7 +222,6 @@ class SearchOp(NamedTuple):
``` ```
Natural language search: Natural language search:
```python ```python
SearchOp( SearchOp(
namespace_prefix=("users", "content"), namespace_prefix=("users", "content"),
@@ -253,15 +249,14 @@ class SearchOp(NamedTuple):
The filter supports both exact matches and operator-based comparisons. The filter supports both exact matches and operator-based comparisons.
Supported Operators: Supported Operators:
- `$eq`: Equal to (same as direct value comparison) - $eq: Equal to (same as direct value comparison)
- `$ne`: Not equal to - $ne: Not equal to
- `$gt`: Greater than - $gt: Greater than
- `$gte`: Greater than or equal to - $gte: Greater than or equal to
- `$lt`: Less than - $lt: Less than
- `$lte`: Less than or equal to - $lte: Less than or equal to
???+ example "Examples" ???+ example "Examples"
Simple exact match: Simple exact match:
```python ```python
@@ -294,7 +289,6 @@ class SearchOp(NamedTuple):
"""Natural language search query for semantic search capabilities. """Natural language search query for semantic search capabilities.
???+ example "Examples" ???+ example "Examples"
- "technical documentation about REST APIs" - "technical documentation about REST APIs"
- "machine learning papers from 2023" - "machine learning papers from 2023"
""" """
@@ -308,11 +302,10 @@ class SearchOp(NamedTuple):
# Type representing a namespace path that can include wildcards # Type representing a namespace path that can include wildcards
NamespacePath = tuple[str | Literal["*"], ...] NamespacePath = tuple[Union[str, Literal["*"]], ...]
"""A tuple representing a namespace path that can include wildcards. """A tuple representing a namespace path that can include wildcards.
???+ example "Examples" ???+ example "Examples"
```python ```python
("users",) # Exact users namespace ("users",) # Exact users namespace
("documents", "*") # Any sub-namespace under documents ("documents", "*") # Any sub-namespace under documents
@@ -338,21 +331,17 @@ class MatchCondition(NamedTuple):
hierarchies. hierarchies.
???+ example "Examples" ???+ example "Examples"
Prefix matching: Prefix matching:
```python ```python
MatchCondition(match_type="prefix", path=("users", "profiles")) MatchCondition(match_type="prefix", path=("users", "profiles"))
``` ```
Suffix matching with wildcard: Suffix matching with wildcard:
```python ```python
MatchCondition(match_type="suffix", path=("cache", "*")) MatchCondition(match_type="suffix", path=("cache", "*"))
``` ```
Simple suffix matching: Simple suffix matching:
```python ```python
MatchCondition(match_type="suffix", path=("v1",)) MatchCondition(match_type="suffix", path=("v1",))
``` ```
@@ -373,8 +362,7 @@ class ListNamespacesOp(NamedTuple):
???+ example "Examples" ???+ example "Examples"
List all namespaces under the `"documents"` path: List all namespaces under the "documents" path:
```python ```python
ListNamespacesOp( ListNamespacesOp(
match_conditions=(MatchCondition(match_type="prefix", path=("documents",)),), match_conditions=(MatchCondition(match_type="prefix", path=("documents",)),),
@@ -382,8 +370,7 @@ class ListNamespacesOp(NamedTuple):
) )
``` ```
List all namespaces that end with `"v1"`: List all namespaces that end with "v1":
```python ```python
ListNamespacesOp( ListNamespacesOp(
match_conditions=(MatchCondition(match_type="suffix", path=("v1",)),), match_conditions=(MatchCondition(match_type="suffix", path=("v1",)),),
@@ -397,15 +384,12 @@ class ListNamespacesOp(NamedTuple):
"""Optional conditions for filtering namespaces. """Optional conditions for filtering namespaces.
???+ example "Examples" ???+ example "Examples"
All user namespaces: All user namespaces:
```python ```python
(MatchCondition(match_type="prefix", path=("users",)),) (MatchCondition(match_type="prefix", path=("users",)),)
``` ```
All namespaces that start with `"docs"` and end with `"draft"`: All namespaces that start with "docs" and end with "draft":
```python ```python
( (
MatchCondition(match_type="prefix", path=("docs",)), MatchCondition(match_type="prefix", path=("docs",)),
@@ -442,21 +426,17 @@ class PutOp(NamedTuple):
Each element in the tuple represents one level in the hierarchy. Each element in the tuple represents one level in the hierarchy.
???+ example "Examples" ???+ example "Examples"
Root level documents
Root level documents:
```python ```python
("documents",) ("documents",)
``` ```
User-specific documents: User-specific documents
```python ```python
("documents", "user123") ("documents", "user123")
``` ```
Nested cache structure: Nested cache structure
```python ```python
("cache", "embeddings", "v1") ("cache", "embeddings", "v1")
``` ```
@@ -469,15 +449,15 @@ class PutOp(NamedTuple):
Together with the namespace, it forms a complete path to the item. Together with the namespace, it forms a complete path to the item.
Example: Example:
If namespace is `("documents", "user123")` and key is `"report1"`, If namespace is ("documents", "user123") and key is "report1",
the full path would effectively be `"documents/user123/report1"` the full path would effectively be "documents/user123/report1"
""" """
value: dict[str, Any] | None value: dict[str, Any] | None
"""The data to store, or `None` to mark the item for deletion. """The data to store, or None to mark the item for deletion.
The value must be a dictionary with string keys and JSON-serializable values. The value must be a dictionary with string keys and JSON-serializable values.
Setting this to `None` signals that the item should be deleted. Setting this to None signals that the item should be deleted.
Example: Example:
{ {
@@ -491,26 +471,25 @@ class PutOp(NamedTuple):
"""Controls how the item's fields are indexed for search operations. """Controls how the item's fields are indexed for search operations.
Indexing configuration determines how the item can be found through search: Indexing configuration determines how the item can be found through search:
- `None` (default): Uses the store's default indexing configuration (if provided) - None (default): Uses the store's default indexing configuration (if provided)
- `False`: Disables indexing for this item - False: Disables indexing for this item
- `list[str]`: Specifies which json path fields to index for search - list[str]: Specifies which json path fields to index for search
The item remains accessible through direct get() operations regardless of indexing. The item remains accessible through direct get() operations regardless of indexing.
When indexed, fields can be searched using natural language queries through When indexed, fields can be searched using natural language queries through
vector similarity search (if supported by the store implementation). vector similarity search (if supported by the store implementation).
Path Syntax: Path Syntax:
- Simple field access: `"field"` - Simple field access: "field"
- Nested fields: `"parent.child.grandchild"` - Nested fields: "parent.child.grandchild"
- Array indexing: - Array indexing:
- Specific index: `"array[0]"` - Specific index: "array[0]"
- Last element: `"array[-1]"` - Last element: "array[-1]"
- All elements (each individually): `"array[*]"` - All elements (each individually): "array[*]"
???+ example "Examples" ???+ example "Examples"
- None - Use store defaults (whole item)
- `None` - Use store defaults (whole item) - list[str] - List of fields to index
- `list[str]` - List of fields to index
```python ```python
[ [
@@ -530,12 +509,12 @@ class PutOp(NamedTuple):
will expire this many minutes after it was last accessed. The expiration timer will expire this many minutes after it was last accessed. The expiration timer
refreshes on both read operations (get/search) and write operations (put/update). refreshes on both read operations (get/search) and write operations (put/update).
When the TTL expires, the item will be scheduled for deletion on a best-effort basis. When the TTL expires, the item will be scheduled for deletion on a best-effort basis.
Defaults to `None` (no expiration). Defaults to None (no expiration).
""" """
Op = GetOp | SearchOp | PutOp | ListNamespacesOp Op = Union[GetOp, SearchOp, PutOp, ListNamespacesOp]
Result = Item | list[Item] | list[SearchItem] | list[tuple[str, ...]] | None Result = Union[Item, list[Item], list[SearchItem], list[tuple[str, ...]], None]
class InvalidNamespaceError(ValueError): class InvalidNamespaceError(ValueError):
@@ -546,18 +525,18 @@ class TTLConfig(TypedDict, total=False):
"""Configuration for TTL (time-to-live) behavior in the store.""" """Configuration for TTL (time-to-live) behavior in the store."""
refresh_on_read: bool refresh_on_read: bool
"""Default behavior for refreshing TTLs on read operations (`GET` and `SEARCH`). """Default behavior for refreshing TTLs on read operations (GET and SEARCH).
If `True`, TTLs will be refreshed on read operations (get/search) by default. If True, TTLs will be refreshed on read operations (get/search) by default.
This can be overridden per-operation by explicitly setting `refresh_ttl`. This can be overridden per-operation by explicitly setting refresh_ttl.
Defaults to `True` if not configured. Defaults to True if not configured.
""" """
default_ttl: float | None default_ttl: float | None
"""Default TTL (time-to-live) in minutes for new items. """Default TTL (time-to-live) in minutes for new items.
If provided, new items will expire after this many minutes after their last access. If provided, new items will expire after this many minutes after their last access.
The expiration timer refreshes on both read and write operations. The expiration timer refreshes on both read and write operations.
Defaults to `None` (no expiration). Defaults to None (no expiration).
""" """
sweep_interval_minutes: int | None sweep_interval_minutes: int | None
"""Interval in minutes between TTL sweep operations. """Interval in minutes between TTL sweep operations.
@@ -571,35 +550,33 @@ class IndexConfig(TypedDict, total=False):
"""Configuration for indexing documents for semantic search in the store. """Configuration for indexing documents for semantic search in the store.
If not provided to the store, the store will not support vector search. If not provided to the store, the store will not support vector search.
In that case, all `index` arguments to `put()` and `aput()` operations will be ignored. In that case, all `index` arguments to put() and `aput()` operations will be ignored.
""" """
dims: int dims: int
"""Number of dimensions in the embedding vectors. """Number of dimensions in the embedding vectors.
Common embedding models have the following dimensions: Common embedding models have the following dimensions:
- `openai:text-embedding-3-large`: `3072` - openai:text-embedding-3-large: 3072
- `openai:text-embedding-3-small`: `1536` - openai:text-embedding-3-small: 1536
- `openai:text-embedding-ada-002`: `1536` - openai:text-embedding-ada-002: 1536
- `cohere:embed-english-v3.0`: `1024` - cohere:embed-english-v3.0: 1024
- `cohere:embed-english-light-v3.0`: `384` - cohere:embed-english-light-v3.0: 384
- `cohere:embed-multilingual-v3.0`: `1024` - cohere:embed-multilingual-v3.0: 1024
- `cohere:embed-multilingual-light-v3.0`: `384` - cohere:embed-multilingual-light-v3.0: 384
""" """
embed: Embeddings | EmbeddingsFunc | AEmbeddingsFunc | str embed: Embeddings | EmbeddingsFunc | AEmbeddingsFunc | str
"""Optional function to generate embeddings from text. """Optional function to generate embeddings from text.
Can be specified in three ways: Can be specified in three ways:
1. A LangChain `Embeddings` instance 1. A LangChain Embeddings instance
2. A synchronous embedding function (`EmbeddingsFunc`) 2. A synchronous embedding function (EmbeddingsFunc)
3. An asynchronous embedding function (`AEmbeddingsFunc`) 3. An asynchronous embedding function (AEmbeddingsFunc)
4. A provider string (e.g., `"openai:text-embedding-3-small"`) 4. A provider string (e.g., "openai:text-embedding-3-small")
???+ example "Examples" ???+ example "Examples"
Using LangChain's initialization with InMemoryStore:
Using LangChain's initialization with `InMemoryStore`:
```python ```python
from langchain.embeddings import init_embeddings from langchain.embeddings import init_embeddings
from langgraph.store.memory import InMemoryStore from langgraph.store.memory import InMemoryStore
@@ -612,8 +589,7 @@ class IndexConfig(TypedDict, total=False):
) )
``` ```
Using a custom embedding function with `InMemoryStore`: Using a custom embedding function with InMemoryStore:
```python ```python
from openai import OpenAI from openai import OpenAI
from langgraph.store.memory import InMemoryStore from langgraph.store.memory import InMemoryStore
@@ -635,8 +611,7 @@ class IndexConfig(TypedDict, total=False):
) )
``` ```
Using an asynchronous embedding function with `InMemoryStore`: Using an asynchronous embedding function with InMemoryStore:
```python ```python
from openai import AsyncOpenAI from openai import AsyncOpenAI
from langgraph.store.memory import InMemoryStore from langgraph.store.memory import InMemoryStore
@@ -664,17 +639,16 @@ class IndexConfig(TypedDict, total=False):
Controls which parts of stored items are embedded for semantic search. Follows JSON path syntax: Controls which parts of stored items are embedded for semantic search. Follows JSON path syntax:
- `["$"]`: Embeds the entire JSON object as one vector (default) - ["$"]: Embeds the entire JSON object as one vector (default)
- `["field1", "field2"]`: Embeds specific top-level fields - ["field1", "field2"]: Embeds specific top-level fields
- `["parent.child"]`: Embeds nested fields using dot notation - ["parent.child"]: Embeds nested fields using dot notation
- `["array[*].field"]`: Embeds field from each array element separately - ["array[*].field"]: Embeds field from each array element separately
Note: Note:
You can always override this behavior when storing an item using the You can always override this behavior when storing an item using the
`index` parameter in the `put` or `aput` operations. `index` parameter in the `put` or `aput` operations.
???+ example "Examples" ???+ example "Examples"
```python ```python
# Embed entire document (default) # Embed entire document (default)
fields=["$"] fields=["$"]
@@ -693,7 +667,7 @@ class IndexConfig(TypedDict, total=False):
Note: Note:
- Fields missing from a document are skipped - Fields missing from a document are skipped
- Array notation creates separate embeddings for each element - Array notation creates separate embeddings for each element
- Complex nested paths are supported (e.g., `"a.b[*].c.d"`) - Complex nested paths are supported (e.g., "a.b[*].c.d")
""" """
@@ -758,11 +732,11 @@ class BaseStore(ABC):
namespace: Hierarchical path for the item. namespace: Hierarchical path for the item.
key: Unique identifier within the namespace. key: Unique identifier within the namespace.
refresh_ttl: Whether to refresh TTLs for the returned item. refresh_ttl: Whether to refresh TTLs for the returned item.
If `None`, uses the store's default `refresh_ttl` setting. If None (default), uses the store's default refresh_ttl setting.
If no TTL is specified, this argument is ignored. If no TTL is specified, this argument is ignored.
Returns: Returns:
The retrieved item or `None` if not found. The retrieved item or None if not found.
""" """
return self.batch( return self.batch(
[GetOp(namespace, str(key), _ensure_refresh(self.ttl_config, refresh_ttl))] [GetOp(namespace, str(key), _ensure_refresh(self.ttl_config, refresh_ttl))]
@@ -794,9 +768,7 @@ class BaseStore(ABC):
List of items matching the search criteria. List of items matching the search criteria.
???+ example "Examples" ???+ example "Examples"
Basic filtering: Basic filtering:
```python ```python
# Search for documents with specific metadata # Search for documents with specific metadata
results = store.search( results = store.search(
@@ -806,7 +778,6 @@ class BaseStore(ABC):
``` ```
Natural language search (requires vector store implementation): Natural language search (requires vector store implementation):
```python ```python
# Initialize store with embedding configuration # Initialize store with embedding configuration
store = YourStore( # e.g., InMemoryStore, AsyncPostgresStore store = YourStore( # e.g., InMemoryStore, AsyncPostgresStore
@@ -818,7 +789,6 @@ class BaseStore(ABC):
) )
# Search for semantically similar documents # Search for semantically similar documents
results = store.search( results = store.search(
("docs",), ("docs",),
query="machine learning applications in healthcare", query="machine learning applications in healthcare",
@@ -827,10 +797,8 @@ class BaseStore(ABC):
) )
``` ```
!!! note Note: Natural language search support depends on your store implementation
and requires proper embedding configuration.
Natural language search support depends on your store implementation
and requires proper embedding configuration.
""" """
return self.batch( return self.batch(
[ [
@@ -858,7 +826,7 @@ class BaseStore(ABC):
Args: Args:
namespace: Hierarchical path for the item, represented as a tuple of strings. namespace: Hierarchical path for the item, represented as a tuple of strings.
Example: `("documents", "user123")` Example: ("documents", "user123")
key: Unique identifier within the namespace. Together with namespace forms key: Unique identifier within the namespace. Together with namespace forms
the complete path to the item. the complete path to the item.
value: Dictionary containing the item's data. Must contain string keys value: Dictionary containing the item's data. Must contain string keys
@@ -869,10 +837,10 @@ class BaseStore(ABC):
If you do not initialize the store with indexing capabilities, If you do not initialize the store with indexing capabilities,
the `index` parameter will be ignored the `index` parameter will be ignored
- False: Disable indexing for this item - False: Disable indexing for this item
- `list[str]`: List of field paths to index, supporting: - list[str]: List of field paths to index, supporting:
- Nested fields: `"metadata.title"` - Nested fields: "metadata.title"
- Array access: `"chapters[*].content"` (each indexed separately) - Array access: "chapters[*].content" (each indexed separately)
- Specific indices: `"authors[0].name"` - Specific indices: "authors[0].name"
ttl: Time to live in minutes. Support for this argument depends on your store adapter. ttl: Time to live in minutes. Support for this argument depends on your store adapter.
If specified, the item will expire after this many minutes from when it was last accessed. If specified, the item will expire after this many minutes from when it was last accessed.
None means no expiration. Expired runs will be deleted opportunistically. None means no expiration. Expired runs will be deleted opportunistically.
@@ -888,22 +856,18 @@ class BaseStore(ABC):
Some implementations may not support expiration of items. Some implementations may not support expiration of items.
???+ example "Examples" ???+ example "Examples"
Store item. Indexing depends on how you configure the store.
Store item. Indexing depends on how you configure the store:
```python ```python
store.put(("docs",), "report", {"memory": "Will likes ai"}) store.put(("docs",), "report", {"memory": "Will likes ai"})
``` ```
Do not index item for semantic search. Still accessible through `get()` Do not index item for semantic search. Still accessible through get()
and `search()` operations but won't have a vector representation. and search() operations but won't have a vector representation.
```python ```python
store.put(("docs",), "report", {"memory": "Will likes ai"}, index=False) store.put(("docs",), "report", {"memory": "Will likes ai"}, index=False)
``` ```
Index specific fields for search: Index specific fields for search.
```python ```python
store.put(("docs",), "report", {"memory": "Will likes ai"}, index=["memory"]) store.put(("docs",), "report", {"memory": "Will likes ai"}, index=["memory"])
``` ```
@@ -954,17 +918,15 @@ class BaseStore(ABC):
suffix: Filter namespaces that end with this path. suffix: Filter namespaces that end with this path.
max_depth: Return namespaces up to this depth in the hierarchy. max_depth: Return namespaces up to this depth in the hierarchy.
Namespaces deeper than this level will be truncated. Namespaces deeper than this level will be truncated.
limit: Maximum number of namespaces to return. limit: Maximum number of namespaces to return (default 100).
offset: Number of namespaces to skip for pagination. offset: Number of namespaces to skip for pagination (default 0).
Returns: Returns:
A list of namespace tuples that match the criteria. Each tuple represents a List[Tuple[str, ...]]: A list of namespace tuples that match the criteria.
full namespace path up to `max_depth`. Each tuple represents a full namespace path up to `max_depth`.
???+ example "Examples": ???+ example "Examples":
Setting max_depth=3. Given the namespaces:
Setting `max_depth=3`. Given the namespaces:
```python ```python
# Example if you have the following namespaces: # Example if you have the following namespaces:
# ("a", "b", "c") # ("a", "b", "c")
@@ -1004,7 +966,7 @@ class BaseStore(ABC):
key: Unique identifier within the namespace. key: Unique identifier within the namespace.
Returns: Returns:
The retrieved item or `None` if not found. The retrieved item or None if not found.
""" """
return ( return (
await self.abatch( await self.abatch(
@@ -1038,16 +1000,14 @@ class BaseStore(ABC):
limit: Maximum number of items to return. limit: Maximum number of items to return.
offset: Number of items to skip before returning results. offset: Number of items to skip before returning results.
refresh_ttl: Whether to refresh TTLs for the returned items. refresh_ttl: Whether to refresh TTLs for the returned items.
If `None`, uses the store's `TTLConfig.refresh_default` setting. If None (default), uses the store's TTLConfig.refresh_default setting.
If `TTLConfig` is not provided or no TTL is specified, this argument is ignored. If TTLConfig is not provided or no TTL is specified, this argument is ignored.
Returns: Returns:
List of items matching the search criteria. List of items matching the search criteria.
???+ example "Examples" ???+ example "Examples"
Basic filtering: Basic filtering:
```python ```python
# Search for documents with specific metadata # Search for documents with specific metadata
results = await store.asearch( results = await store.asearch(
@@ -1057,7 +1017,6 @@ class BaseStore(ABC):
``` ```
Natural language search (requires vector store implementation): Natural language search (requires vector store implementation):
```python ```python
# Initialize store with embedding configuration # Initialize store with embedding configuration
store = YourStore( # e.g., InMemoryStore, AsyncPostgresStore store = YourStore( # e.g., InMemoryStore, AsyncPostgresStore
@@ -1069,7 +1028,6 @@ class BaseStore(ABC):
) )
# Search for semantically similar documents # Search for semantically similar documents
results = await store.asearch( results = await store.asearch(
("docs",), ("docs",),
query="machine learning applications in healthcare", query="machine learning applications in healthcare",
@@ -1078,10 +1036,8 @@ class BaseStore(ABC):
) )
``` ```
!!! note Note: Natural language search support depends on your store implementation
and requires proper embedding configuration.
Natural language search support depends on your store implementation
and requires proper embedding configuration.
""" """
return ( return (
await self.abatch( await self.abatch(
@@ -1111,7 +1067,7 @@ class BaseStore(ABC):
Args: Args:
namespace: Hierarchical path for the item, represented as a tuple of strings. namespace: Hierarchical path for the item, represented as a tuple of strings.
Example: `("documents", "user123")` Example: ("documents", "user123")
key: Unique identifier within the namespace. Together with namespace forms key: Unique identifier within the namespace. Together with namespace forms
the complete path to the item. the complete path to the item.
value: Dictionary containing the item's data. Must contain string keys value: Dictionary containing the item's data. Must contain string keys
@@ -1122,10 +1078,10 @@ class BaseStore(ABC):
If you do not initialize the store with indexing capabilities, If you do not initialize the store with indexing capabilities,
the `index` parameter will be ignored the `index` parameter will be ignored
- False: Disable indexing for this item - False: Disable indexing for this item
- `list[str]`: List of field paths to index, supporting: - list[str]: List of field paths to index, supporting:
- Nested fields: `"metadata.title"` - Nested fields: "metadata.title"
- Array access: `"chapters[*].content"` (each indexed separately) - Array access: "chapters[*].content" (each indexed separately)
- Specific indices: `"authors[0].name"` - Specific indices: "authors[0].name"
ttl: Time to live in minutes. Support for this argument depends on your store adapter. ttl: Time to live in minutes. Support for this argument depends on your store adapter.
If specified, the item will expire after this many minutes from when it was last accessed. If specified, the item will expire after this many minutes from when it was last accessed.
None means no expiration. Expired runs will be deleted opportunistically. None means no expiration. Expired runs will be deleted opportunistically.
@@ -1141,22 +1097,18 @@ class BaseStore(ABC):
Some implementations may not support expiration of items. Some implementations may not support expiration of items.
???+ example "Examples" ???+ example "Examples"
Store item. Indexing depends on how you configure the store.
Store item. Indexing depends on how you configure the store:
```python ```python
await store.aput(("docs",), "report", {"memory": "Will likes ai"}) await store.aput(("docs",), "report", {"memory": "Will likes ai"})
``` ```
Do not index item for semantic search. Still accessible through `get()` Do not index item for semantic search. Still accessible through get()
and `search()` operations but won't have a vector representation. and search() operations but won't have a vector representation.
```python ```python
await store.aput(("docs",), "report", {"memory": "Will likes ai"}, index=False) await store.aput(("docs",), "report", {"memory": "Will likes ai"}, index=False)
``` ```
Index specific fields for search (if store configured to index items): Index specific fields for search (if store configured to index items):
```python ```python
await store.aput( await store.aput(
("docs",), ("docs",),
@@ -1215,16 +1167,15 @@ class BaseStore(ABC):
suffix: Filter namespaces that end with this path. suffix: Filter namespaces that end with this path.
max_depth: Return namespaces up to this depth in the hierarchy. max_depth: Return namespaces up to this depth in the hierarchy.
Namespaces deeper than this level will be truncated to this depth. Namespaces deeper than this level will be truncated to this depth.
limit: Maximum number of namespaces to return. limit: Maximum number of namespaces to return (default 100).
offset: Number of namespaces to skip for pagination. offset: Number of namespaces to skip for pagination (default 0).
Returns: Returns:
A list of namespace tuples that match the criteria. Each tuple represents a List[Tuple[str, ...]]: A list of namespace tuples that match the criteria.
full namespace path up to `max_depth`. Each tuple represents a full namespace path up to `max_depth`.
???+ example "Examples" ???+ example "Examples"
Setting max_depth=3 with existing namespaces:
Setting `max_depth=3` with existing namespaces:
```python ```python
# Given the following namespaces: # Given the following namespaces:
# ("a", "b", "c") # ("a", "b", "c")
@@ -5,8 +5,8 @@ from __future__ import annotations
import asyncio import asyncio
import functools import functools
import weakref import weakref
from collections.abc import Callable, Iterable from collections.abc import Iterable
from typing import Any, Literal, TypeVar from typing import Any, Callable, Literal, TypeVar
from langgraph.store.base import ( from langgraph.store.base import (
NOT_PROVIDED, NOT_PROVIDED,
@@ -349,7 +349,7 @@ async def _run(
results = [results[ix] for ix in listen] results = [results[ix] for ix in listen]
# set the results of each operation # set the results of each operation
for fut, result in zip(futs, results, strict=False): for fut, result in zip(futs, results):
# guard against future being done (e.g. cancelled) # guard against future being done (e.g. cancelled)
if not fut.done(): if not fut.done():
fut.set_result(result) fut.set_result(result)
@@ -11,8 +11,8 @@ from __future__ import annotations
import asyncio import asyncio
import functools import functools
import json import json
from collections.abc import Awaitable, Callable, Sequence from collections.abc import Awaitable, Sequence
from typing import Any from typing import Any, Callable
from langchain_core.embeddings import Embeddings from langchain_core.embeddings import Embeddings
@@ -49,9 +49,7 @@ def ensure_embeddings(
An Embeddings instance that wraps the provided function(s). An Embeddings instance that wraps the provided function(s).
??? example "Examples" ??? example "Examples"
Wrap a synchronous embedding function: Wrap a synchronous embedding function:
```python ```python
def my_embed_fn(texts): def my_embed_fn(texts):
return [[0.1, 0.2] for _ in texts] return [[0.1, 0.2] for _ in texts]
@@ -61,7 +59,6 @@ def ensure_embeddings(
``` ```
Wrap an asynchronous embedding function: Wrap an asynchronous embedding function:
```python ```python
async def my_async_fn(texts): async def my_async_fn(texts):
return [[0.1, 0.2] for _ in texts] return [[0.1, 0.2] for _ in texts]
@@ -71,7 +68,6 @@ def ensure_embeddings(
``` ```
Initialize embeddings using a provider string: Initialize embeddings using a provider string:
```python ```python
# Requires langchain>=0.3.9 and langgraph-checkpoint>=2.0.11 # Requires langchain>=0.3.9 and langgraph-checkpoint>=2.0.11
embeddings = ensure_embeddings("openai:text-embedding-3-small") embeddings = ensure_embeddings("openai:text-embedding-3-small")
@@ -123,9 +119,7 @@ class EmbeddingsLambda(Embeddings):
will raise an error. If sync, it will be used for both sync and async operations. will raise an error. If sync, it will be used for both sync and async operations.
??? example "Examples" ??? example "Examples"
With a sync function: With a sync function:
```python ```python
def my_embed_fn(texts): def my_embed_fn(texts):
# Return 2D embeddings for each text # Return 2D embeddings for each text
@@ -137,7 +131,6 @@ class EmbeddingsLambda(Embeddings):
``` ```
With an async function: With an async function:
```python ```python
async def my_async_fn(texts): async def my_async_fn(texts):
return [[0.1, 0.2] for _ in texts] return [[0.1, 0.2] for _ in texts]
@@ -295,7 +295,7 @@ class InMemoryStore(BaseStore):
if queries: if queries:
coros = [self.embeddings.aembed_query(q) for q in list(queries)] coros = [self.embeddings.aembed_query(q) for q in list(queries)]
results = await asyncio.gather(*coros) results = await asyncio.gather(*coros)
queryinmem_store = dict(zip(queries, results, strict=False)) queryinmem_store = dict(zip(queries, results))
return queryinmem_store return queryinmem_store
@@ -323,9 +323,7 @@ class InMemoryStore(BaseStore):
scores = _cosine_similarity(query_embedding, flat_vectors) scores = _cosine_similarity(query_embedding, flat_vectors)
sorted_results = sorted( sorted_results = sorted(
zip(scores, flat_items, strict=False), zip(scores, flat_items), key=lambda x: x[0], reverse=True
key=lambda x: x[0],
reverse=True,
) )
# max pooling # max pooling
seen: set[tuple[tuple[str, ...], str]] = set() seen: set[tuple[tuple[str, ...], str]] = set()
@@ -454,7 +452,7 @@ class InMemoryStore(BaseStore):
f"Number of embeddings ({len(embeddings)}) does not" f"Number of embeddings ({len(embeddings)}) does not"
f" match number of indices ({len(indices)})" f" match number of indices ({len(indices)})"
) )
for embedding, (ns, key, path) in zip(embeddings, indices, strict=False): for embedding, (ns, key, path) in zip(embeddings, indices):
self._vectors[ns][key][path] = embedding self._vectors[ns][key][path] = embedding
def _handle_list_namespaces(self, op: ListNamespacesOp) -> list[tuple[str, ...]]: def _handle_list_namespaces(self, op: ListNamespacesOp) -> list[tuple[str, ...]]:
@@ -513,7 +511,7 @@ def _cosine_similarity(X: list[float], Y: list[list[float]]) -> list[float]:
similarities = [] similarities = []
for y in Y: for y in Y:
dot_product = sum(a * b for a, b in zip(X, y, strict=False)) dot_product = sum(a * b for a, b in zip(X, y))
norm1 = sum(a * a for a in X) ** 0.5 norm1 = sum(a * a for a in X) ** 0.5
norm2 = sum(a * a for a in y) ** 0.5 norm2 = sum(a * a for a in y) ** 0.5
similarity = dot_product / (norm1 * norm2) if norm1 > 0 and norm2 > 0 else 0.0 similarity = dot_product / (norm1 * norm2) if norm1 > 0 and norm2 > 0 else 0.0
@@ -531,14 +529,14 @@ def _does_match(match_condition: MatchCondition, key: tuple[str, ...]) -> bool:
return False return False
if match_type == "prefix": if match_type == "prefix":
for k_elem, p_elem in zip(key, path, strict=False): for k_elem, p_elem in zip(key, path):
if p_elem == "*": if p_elem == "*":
continue # Wildcard matches any element continue # Wildcard matches any element
if k_elem != p_elem: if k_elem != p_elem:
return False return False
return True return True
elif match_type == "suffix": elif match_type == "suffix":
for k_elem, p_elem in zip(reversed(key), reversed(path), strict=False): for k_elem, p_elem in zip(reversed(key), reversed(path)):
if p_elem == "*": if p_elem == "*":
continue # Wildcard matches any element continue # Wildcard matches any element
if k_elem != p_elem: if k_elem != p_elem:
@@ -565,10 +563,7 @@ def _compare_values(item_value: Any, filter_value: Any) -> bool:
return ( return (
isinstance(item_value, (list, tuple)) isinstance(item_value, (list, tuple))
and len(item_value) == len(filter_value) and len(item_value) == len(filter_value)
and all( and all(_compare_values(iv, fv) for iv, fv in zip(item_value, filter_value))
_compare_values(iv, fv)
for iv, fv in zip(item_value, filter_value, strict=False)
)
) )
else: else:
return item_value == filter_value return item_value == filter_value
+8 -19
View File
@@ -4,45 +4,36 @@ build-backend = "hatchling.build"
[project] [project]
name = "langgraph-checkpoint" name = "langgraph-checkpoint"
version = "3.0.1" version = "2.1.2"
description = "Library with base interfaces for LangGraph checkpoint savers." description = "Library with base interfaces for LangGraph checkpoint savers."
authors = [] authors = []
requires-python = ">=3.10" requires-python = ">=3.9"
readme = "README.md" readme = "README.md"
license = "MIT" license = "MIT"
license-files = ['LICENSE'] license-files = ['LICENSE']
dependencies = [ dependencies = [
"langchain-core>=0.2.38", "langchain-core>=0.2.38",
"ormsgpack>=1.12.0", "ormsgpack>=1.10.0",
] ]
[project.urls] [project.urls]
Source = "https://github.com/langchain-ai/langgraph/tree/main/libs/checkpoint" Repository = "https://www.github.com/langchain-ai/langgraph"
Twitter = "https://x.com/LangChainAI"
Slack = "https://www.langchain.com/join-community"
Reddit = "https://www.reddit.com/r/LangChain/"
[dependency-groups] [dependency-groups]
test = [ dev = [
"ruff",
"codespell",
"pytest", "pytest",
"pytest-asyncio", "pytest-asyncio",
"pytest-mock", "pytest-mock",
"pytest-watcher", "pytest-watcher",
"mypy",
"dataclasses-json", "dataclasses-json",
"numpy", "numpy",
"pandas", "pandas",
"pandas-stubs>=2.2.2.240807", "pandas-stubs>=2.2.2.240807",
"redis", "redis",
] ]
lint = [
"ruff",
"codespell",
"mypy",
]
dev = [
{include-group = "test"},
{include-group = "lint"},
]
[tool.hatch.build.targets.wheel] [tool.hatch.build.targets.wheel]
include = ["langgraph"] include = ["langgraph"]
@@ -58,10 +49,8 @@ lint.select = [
"UP", # pyupgrade "UP", # pyupgrade
"B", # flake8-bugbear "B", # flake8-bugbear
"I", # isort "I", # isort
"UP", # pyupgrade
] ]
lint.ignore = ["E501", "B008"] lint.ignore = ["E501", "B008"]
target-version = "py310"
[tool.pytest-watcher] [tool.pytest-watcher]
now = true now = true
+43 -88
View File
@@ -1,5 +1,4 @@
import dataclasses import dataclasses
import json
import pathlib import pathlib
import re import re
import sys import sys
@@ -20,7 +19,6 @@ from pydantic.v1 import BaseModel as BaseModelV1
from pydantic.v1 import SecretStr as SecretStrV1 from pydantic.v1 import SecretStr as SecretStrV1
from langgraph.checkpoint.serde.jsonplus import ( from langgraph.checkpoint.serde.jsonplus import (
InvalidModuleError,
JsonPlusSerializer, JsonPlusSerializer,
_msgpack_ext_hook_to_json, _msgpack_ext_hook_to_json,
) )
@@ -62,15 +60,22 @@ class MyDataclass:
pass pass
@dataclasses.dataclass(slots=True) if sys.version_info < (3, 10):
class MyDataclassWSlots:
foo: str
bar: int
inner: InnerDataclass
def something(self) -> None: class MyDataclassWSlots(MyDataclass):
pass pass
else:
@dataclasses.dataclass(slots=True)
class MyDataclassWSlots:
foo: str
bar: int
inner: InnerDataclass
def something(self) -> None:
pass
class MyEnum(Enum): class MyEnum(Enum):
FOO = "foo" FOO = "foo"
@@ -110,7 +115,11 @@ def test_serde_jsonplus() -> None:
"my_dataclass": MyDataclass("foo", 1, InnerDataclass("hello")), "my_dataclass": MyDataclass("foo", 1, InnerDataclass("hello")),
"my_enum": MyEnum.FOO, "my_enum": MyEnum.FOO,
"my_pydantic": MyPydantic(foo="foo", bar=1, inner=InnerPydantic(hello="hello")), "my_pydantic": MyPydantic(foo="foo", bar=1, inner=InnerPydantic(hello="hello")),
"my_pydantic_v1": MyPydanticV1(
foo="foo", bar=1, inner=InnerPydanticV1(hello="hello")
),
"my_secret_str": SecretStr("meow"), "my_secret_str": SecretStr("meow"),
"my_secret_str_v1": SecretStrV1("meow"),
"person": Person(name="foo"), "person": Person(name="foo"),
"a_bool": True, "a_bool": True,
"a_none": None, "a_none": None,
@@ -132,12 +141,6 @@ def test_serde_jsonplus() -> None:
), ),
} }
if sys.version_info < (3, 14):
to_serialize["my_pydantic_v1"] = MyPydanticV1(
foo="foo", bar=1, inner=InnerPydanticV1(hello="hello")
)
to_serialize["my_secret_str_v1"] = SecretStrV1("meow")
serde = JsonPlusSerializer() serde = JsonPlusSerializer()
dumped = serde.dumps_typed(to_serialize) dumped = serde.dumps_typed(to_serialize)
@@ -149,22 +152,23 @@ def test_serde_jsonplus() -> None:
assert serde.loads_typed(serde.dumps_typed(value)) == value assert serde.loads_typed(serde.dumps_typed(value)) == value
surrogates = [ surrogates = [
"Hello??", "Hello\ud83d\ude00",
"Python??", "Python\ud83d\udc0d",
"Surrogate??", "Surrogate\ud834\udd1e",
"Example??", "Example\ud83c\udf89",
"String??", "String\ud83c\udfa7",
"With??", "With\ud83c\udf08",
"Surrogates??", "Surrogates\ud83d\ude0e",
"Embedded??", "Embedded\ud83d\udcbb",
"In??", "In\ud83c\udf0e",
"The??", "The\ud83d\udcd6",
"Text??", "Text\ud83d\udcac",
"收花🙄·到", "收花🙄·到",
] ]
serde = JsonPlusSerializer(pickle_fallback=False)
assert serde.loads_typed(serde.dumps_typed(surrogates)) == surrogates assert serde.loads_typed(serde.dumps_typed(surrogates)) == [
v.encode("utf-8", "ignore").decode() for v in surrogates
]
def test_serde_jsonplus_json_mode() -> None: def test_serde_jsonplus_json_mode() -> None:
@@ -193,7 +197,11 @@ def test_serde_jsonplus_json_mode() -> None:
"my_dataclass": MyDataclass("foo", 1, InnerDataclass("hello")), "my_dataclass": MyDataclass("foo", 1, InnerDataclass("hello")),
"my_enum": MyEnum.FOO, "my_enum": MyEnum.FOO,
"my_pydantic": MyPydantic(foo="foo", bar=1, inner=InnerPydantic(hello="hello")), "my_pydantic": MyPydantic(foo="foo", bar=1, inner=InnerPydantic(hello="hello")),
"my_pydantic_v1": MyPydanticV1(
foo="foo", bar=1, inner=InnerPydanticV1(hello="hello")
),
"my_secret_str": SecretStr("meow"), "my_secret_str": SecretStr("meow"),
"my_secret_str_v1": SecretStrV1("meow"),
"person": Person(name="foo"), "person": Person(name="foo"),
"a_bool": True, "a_bool": True,
"a_none": None, "a_none": None,
@@ -215,20 +223,13 @@ def test_serde_jsonplus_json_mode() -> None:
), ),
} }
if sys.version_info < (3, 14):
to_serialize["my_pydantic_v1"] = MyPydanticV1(
foo="foo", bar=1, inner=InnerPydanticV1(hello="hello")
)
to_serialize["my_secret_str_v1"] = SecretStrV1("meow")
serde = JsonPlusSerializer(__unpack_ext_hook__=_msgpack_ext_hook_to_json) serde = JsonPlusSerializer(__unpack_ext_hook__=_msgpack_ext_hook_to_json)
dumped = serde.dumps_typed(to_serialize) dumped = serde.dumps_typed(to_serialize)
assert dumped[0] == "msgpack" assert dumped[0] == "msgpack"
result = serde.loads_typed(dumped) result = serde.loads_typed(dumped)
assert result == {
expected_result = {
"path": ["foo", "bar"], "path": ["foo", "bar"],
"re": ["foo", 48], "re": ["foo", 48],
"decimal": "1.10101", "decimal": "1.10101",
@@ -252,7 +253,9 @@ def test_serde_jsonplus_json_mode() -> None:
"my_dataclass": {"foo": "foo", "bar": 1, "inner": {"hello": "hello"}}, "my_dataclass": {"foo": "foo", "bar": 1, "inner": {"hello": "hello"}},
"my_enum": "foo", "my_enum": "foo",
"my_pydantic": {"foo": "foo", "bar": 1, "inner": {"hello": "hello"}}, "my_pydantic": {"foo": "foo", "bar": 1, "inner": {"hello": "hello"}},
"my_pydantic_v1": {"foo": "foo", "bar": 1, "inner": {"hello": "hello"}},
"my_secret_str": "meow", "my_secret_str": "meow",
"my_secret_str_v1": "meow",
"person": {"name": "foo"}, "person": {"name": "foo"},
"a_bool": True, "a_bool": True,
"a_none": None, "a_none": None,
@@ -274,16 +277,6 @@ def test_serde_jsonplus_json_mode() -> None:
}, },
} }
if sys.version_info < (3, 14):
expected_result["my_pydantic_v1"] = {
"foo": "foo",
"bar": 1,
"inner": {"hello": "hello"},
}
expected_result["my_secret_str_v1"] = "meow"
assert result == expected_result
def test_serde_jsonplus_bytes() -> None: def test_serde_jsonplus_bytes() -> None:
serde = JsonPlusSerializer() serde = JsonPlusSerializer()
@@ -295,20 +288,6 @@ def test_serde_jsonplus_bytes() -> None:
assert serde.loads_typed(dumped) == some_bytes assert serde.loads_typed(dumped) == some_bytes
def test_deserde_invalid_module() -> None:
serde = JsonPlusSerializer()
load = {
"lc": 2,
"type": "constructor",
"id": ["pprint", "pprint"],
"kwargs": {"object": "HELLO"},
}
with pytest.raises(InvalidModuleError):
serde._revive_lc2(load)
serde = JsonPlusSerializer(allowed_json_modules=[("pprint", "pprint")])
serde.loads_typed(("json", json.dumps(load).encode("utf-8")))
def test_serde_jsonplus_bytearray() -> None: def test_serde_jsonplus_bytearray() -> None:
serde = JsonPlusSerializer() serde = JsonPlusSerializer()
@@ -385,12 +364,7 @@ def test_serde_jsonplus_numpy_array_json_hook(arr: np.ndarray) -> None:
"str_col": ["a", None, "c"], "str_col": ["a", None, "c"],
} }
), ),
pytest.param( pd.DataFrame({"cat_col": pd.Categorical(["a", "b", "a", "c"])}),
pd.DataFrame({"cat_col": pd.Categorical(["a", "b", "a", "c"])}),
marks=pytest.mark.skipif(
sys.version_info >= (3, 14), reason="NotImplementedError on Python 3.14"
),
),
pd.DataFrame( pd.DataFrame(
{ {
"int8": pd.array([1, 2, 3], dtype="int8"), "int8": pd.array([1, 2, 3], dtype="int8"),
@@ -418,25 +392,11 @@ def test_serde_jsonplus_numpy_array_json_hook(arr: np.ndarray) -> None:
"col3": np.random.rand(1000), "col3": np.random.rand(1000),
} }
), ),
pytest.param( pd.DataFrame(
pd.DataFrame( {"tz_datetime": pd.date_range("2024-01-01", periods=3, freq="D", tz="UTC")}
{
"tz_datetime": pd.date_range(
"2024-01-01", periods=3, freq="D", tz="UTC"
)
}
),
marks=pytest.mark.skipif(
sys.version_info >= (3, 14), reason="NotImplementedError on Python 3.14"
),
), ),
pd.DataFrame({"timedelta": pd.to_timedelta([1, 2, 3], unit="D")}), pd.DataFrame({"timedelta": pd.to_timedelta([1, 2, 3], unit="D")}),
pytest.param( pd.DataFrame({"period": pd.period_range("2024-01", periods=3, freq="M")}),
pd.DataFrame({"period": pd.period_range("2024-01", periods=3, freq="M")}),
marks=pytest.mark.skipif(
sys.version_info >= (3, 14), reason="NotImplementedError on Python 3.14"
),
),
pd.DataFrame({"interval": pd.interval_range(start=0, end=3, periods=3)}), pd.DataFrame({"interval": pd.interval_range(start=0, end=3, periods=3)}),
pd.DataFrame({"unicode": ["Hello 🌍", "Python 🐍", "Data 📊"]}), pd.DataFrame({"unicode": ["Hello 🌍", "Python 🐍", "Data 📊"]}),
pd.DataFrame({"mixed": [1, "string", [1, 2, 3], {"key": "value"}]}), pd.DataFrame({"mixed": [1, "string", [1, 2, 3], {"key": "value"}]}),
@@ -473,12 +433,7 @@ def test_serde_jsonplus_pandas_dataframe(df: pd.DataFrame) -> None:
pd.Series([1, 2, None]), pd.Series([1, 2, None]),
pd.Series([1.1, None, 3.3]), pd.Series([1.1, None, 3.3]),
pd.Series(["a", None, "c"]), pd.Series(["a", None, "c"]),
pytest.param( pd.Series(pd.Categorical(["a", "b", "a", "c"])),
pd.Series(pd.Categorical(["a", "b", "a", "c"])),
marks=pytest.mark.skipif(
sys.version_info >= (3, 14), reason="NotImplementedError on Python 3.14"
),
),
pd.Series([1, 2, 3], dtype="int8"), pd.Series([1, 2, 3], dtype="int8"),
pd.Series([10, 20, 30], dtype="int16"), pd.Series([10, 20, 30], dtype="int16"),
pd.Series([100, 200, 300], dtype="int32"), pd.Series([100, 200, 300], dtype="int32"),
+1 -1
View File
@@ -845,7 +845,7 @@ async def test_async_batched_vector_search_concurrent(
] ]
) )
for results, (query, filter_) in zip(all_results, search_queries, strict=False): for results, (query, filter_) in zip(all_results, search_queries):
assert len(results) > 0, f"No results for query '{query}' with filter {filter_}" assert len(results) > 0, f"No results for query '{query}' with filter {filter_}"
for result in results: for result in results:
+619 -569
View File
File diff suppressed because it is too large Load Diff
@@ -1,12 +1,13 @@
from collections.abc import Sequence from collections.abc import Sequence
from typing import Annotated, Literal, TypedDict from typing import Annotated, Literal, TypedDict
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import BaseMessage from langchain_core.messages import BaseMessage
from langchain_openai import ChatOpenAI from langchain_openai import ChatOpenAI
from langgraph.graph import END, StateGraph, add_messages from langgraph.graph import END, StateGraph, add_messages
from langgraph.prebuilt import ToolNode from langgraph.prebuilt import ToolNode
tools = [] tools = [TavilySearchResults(max_results=1)]
model_oai = ChatOpenAI(temperature=0) model_oai = ChatOpenAI(temperature=0)
@@ -5,5 +5,5 @@ description = "Test for prerelease stuff"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"
dependencies = [ dependencies = [
"langgraph==1.0.2" "langgraph==0.6.0"
] ]
@@ -5,5 +5,5 @@ description = "Test for prerelease stuff"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"
dependencies = [ dependencies = [
"langchain-openai==1.0.1" "langchain-openai==0.3.0"
] ]
@@ -6,8 +6,8 @@ readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"
dependencies = [ dependencies = [
"langchain-openai==1.0.0a2", "langchain-openai==1.0.0a2",
"langchain-anthropic==1.0.0a5", "langgraph==1.0.0a2",
"langgraph==1.0.2" "langchain_community>=0.3.0",
] ]
[tool.uv] [tool.uv]
+6 -6
View File
@@ -1,6 +1,6 @@
import asyncio import asyncio
import json import json
from typing import Annotated from typing import Annotated, Optional
from langchain_community.retrievers import WikipediaRetriever from langchain_community.retrievers import WikipediaRetriever
from langchain_community.tools.tavily_search import TavilySearchResults from langchain_community.tools.tavily_search import TavilySearchResults
@@ -51,7 +51,7 @@ class Subsection(BaseModel):
class Section(BaseModel): class Section(BaseModel):
section_title: str = Field(..., title="Title of the section") section_title: str = Field(..., title="Title of the section")
description: str = Field(..., title="Content of the section") description: str = Field(..., title="Content of the section")
subsections: list[Subsection] | None = Field( subsections: Optional[list[Subsection]] = Field(
default=None, default=None,
title="Titles and descriptions for each subsection of the Wikipedia page.", title="Titles and descriptions for each subsection of the Wikipedia page.",
) )
@@ -201,8 +201,8 @@ def update_editor(editor, new_editor):
class InterviewState(TypedDict): class InterviewState(TypedDict):
messages: Annotated[list[AnyMessage], add_messages] messages: Annotated[list[AnyMessage], add_messages]
references: Annotated[dict | None, update_references] references: Annotated[Optional[dict], update_references]
editor: Annotated[Editor | None, update_editor] editor: Annotated[Optional[Editor], update_editor]
gen_qn_prompt = ChatPromptTemplate.from_messages( gen_qn_prompt = ChatPromptTemplate.from_messages(
@@ -321,7 +321,7 @@ async def search_engine(query: str):
async def gen_answer( async def gen_answer(
state: InterviewState, state: InterviewState,
config: RunnableConfig | None = None, config: Optional[RunnableConfig] = None,
name: str = "Subject_Matter_Expert", name: str = "Subject_Matter_Expert",
max_str_len: int = 15000, max_str_len: int = 15000,
): ):
@@ -437,7 +437,7 @@ class SubSection(BaseModel):
class WikiSection(BaseModel): class WikiSection(BaseModel):
section_title: str = Field(..., title="Title of the section") section_title: str = Field(..., title="Title of the section")
content: str = Field(..., title="Full content of the section") content: str = Field(..., title="Full content of the section")
subsections: list[Subsection] | None = Field( subsections: Optional[list[Subsection]] = Field(
default=None, default=None,
title="Titles and descriptions for each subsection of the Wikipedia page.", title="Titles and descriptions for each subsection of the Wikipedia page.",
) )
+1 -1
View File
@@ -7,7 +7,7 @@ name = "langgraph-examples"
version = "0.1.0" version = "0.1.0"
description = "" description = ""
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.9"
dependencies = [ dependencies = [
"langgraph-cli", "langgraph-cli",
"langgraph-sdk", "langgraph-sdk",
+1 -3
View File
@@ -13,7 +13,7 @@ from pathlib import Path
import msgspec import msgspec
from langgraph_cli.schemas import ( from langgraph_cli.config import (
AuthConfig, AuthConfig,
CheckpointerConfig, CheckpointerConfig,
Config, Config,
@@ -22,7 +22,6 @@ from langgraph_cli.schemas import (
HttpConfig, HttpConfig,
IndexConfig, IndexConfig,
SecurityConfig, SecurityConfig,
SerdeConfig,
StoreConfig, StoreConfig,
ThreadTTLConfig, ThreadTTLConfig,
TTLConfig, TTLConfig,
@@ -113,7 +112,6 @@ def add_descriptions_to_schema(schema, cls):
CorsConfig, CorsConfig,
ThreadTTLConfig, ThreadTTLConfig,
CheckpointerConfig, CheckpointerConfig,
SerdeConfig,
TTLConfig, TTLConfig,
ConfigurableHeaderConfig, ConfigurableHeaderConfig,
]: ]:
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.4.7" __version__ = "0.4.3"
+57 -41
View File
@@ -4,7 +4,8 @@ import os
import pathlib import pathlib
import shutil import shutil
import sys import sys
from collections.abc import Callable, Sequence from collections.abc import Sequence
from typing import Callable, Optional
import click import click
import click.exceptions import click.exceptions
@@ -199,23 +200,23 @@ def cli():
@log_command @log_command
def up( def up(
config: pathlib.Path, config: pathlib.Path,
docker_compose: pathlib.Path | None, docker_compose: Optional[pathlib.Path],
port: int, port: int,
recreate: bool, recreate: bool,
pull: bool, pull: bool,
watch: bool, watch: bool,
wait: bool, wait: bool,
verbose: bool, verbose: bool,
debugger_port: int | None, debugger_port: Optional[int],
debugger_base_url: str | None, debugger_base_url: Optional[str],
postgres_uri: str | None, postgres_uri: Optional[str],
api_version: str | None, api_version: Optional[str],
image: str | None, image: Optional[str],
base_image: str | None, base_image: Optional[str],
): ):
click.secho("Starting LangGraph API server...", fg="green") click.secho("Starting LangGraph API server...", fg="green")
click.secho( click.secho(
"""For local dev, requires env var LANGSMITH_API_KEY with access to LangSmith Deployment. """For local dev, requires env var LANGSMITH_API_KEY with access to LangGraph Platform.
For production use, requires a license key in env var LANGGRAPH_CLOUD_LICENSE_KEY.""", For production use, requires a license key in env var LANGGRAPH_CLOUD_LICENSE_KEY.""",
) )
with Runner() as runner, Progress(message="Pulling...") as set: with Runner() as runner, Progress(message="Pulling...") as set:
@@ -270,7 +271,7 @@ For production use, requires a license key in env var LANGGRAPH_CLOUD_LICENSE_KE
f"""Ready! f"""Ready!
- API: http://localhost:{port} - API: http://localhost:{port}
- Docs: http://localhost:{port}/docs - Docs: http://localhost:{port}/docs
- LangGraph Studio: {debugger_origin}/studio/?baseUrl={debugger_base_url_query} - LangSmith Debugger: {debugger_origin}/studio/?baseUrl={debugger_base_url_query}
""" """
) )
sys.stdout.flush() sys.stdout.flush()
@@ -297,13 +298,13 @@ def _build(
set: Callable[[str], None], set: Callable[[str], None],
config: pathlib.Path, config: pathlib.Path,
config_json: dict, config_json: dict,
base_image: str | None, base_image: Optional[str],
api_version: str | None, api_version: Optional[str],
pull: bool, pull: bool,
tag: str, tag: str,
passthrough: Sequence[str] = (), passthrough: Sequence[str] = (),
install_command: str | None = None, install_command: Optional[str] = None,
build_command: str | None = None, build_command: Optional[str] = None,
): ):
# pull latest images # pull latest images
if pull: if pull:
@@ -402,12 +403,12 @@ def _build(
def build( def build(
config: pathlib.Path, config: pathlib.Path,
docker_build_args: Sequence[str], docker_build_args: Sequence[str],
base_image: str | None, base_image: Optional[str],
api_version: str | None, api_version: Optional[str],
pull: bool, pull: bool,
tag: str, tag: str,
install_command: str | None, install_command: Optional[str],
build_command: str | None, build_command: Optional[str],
): ):
with Runner() as runner, Progress(message="Pulling...") as set: with Runner() as runner, Progress(message="Pulling...") as set:
if shutil.which("docker") is None: if shutil.which("docker") is None:
@@ -511,8 +512,8 @@ def dockerfile(
save_path: str, save_path: str,
config: pathlib.Path, config: pathlib.Path,
add_docker_compose: bool, add_docker_compose: bool,
base_image: str | None = None, base_image: Optional[str] = None,
api_version: str | None = None, api_version: Optional[str] = None,
) -> None: ) -> None:
save_path = pathlib.Path(save_path).absolute() save_path = pathlib.Path(save_path).absolute()
secho(f"🔍 Validating configuration at path: {config}", fg="yellow") secho(f"🔍 Validating configuration at path: {config}", fg="yellow")
@@ -583,7 +584,7 @@ def dockerfile(
"\n", "\n",
"# LANGSMITH_API_KEY=your-api-key", "# LANGSMITH_API_KEY=your-api-key",
"\n", "\n",
"# Or if you have a LangSmith Deployment license key, " "# Or if you have a LangGraph Platform license key, "
"then uncomment the following line: ", "then uncomment the following line: ",
"\n", "\n",
"# LANGGRAPH_CLOUD_LICENSE_KEY=your-license-key", "# LANGGRAPH_CLOUD_LICENSE_KEY=your-license-key",
@@ -651,11 +652,17 @@ def dockerfile(
help="Wait for a debugger client to connect to the debug port before starting the server", help="Wait for a debugger client to connect to the debug port before starting the server",
default=False, default=False,
) )
@click.option(
"--debugger-url",
type=str,
default=None,
help="URL of the LangSmith Debugger instance to connect to. Defaults to https://smith.langchain.com",
)
@click.option( @click.option(
"--studio-url", "--studio-url",
type=str, type=str,
default=None, default=None,
help="URL of the LangGraph Studio instance to connect to. Defaults to https://smith.langchain.com", help="(Deprecated: use --debugger-url instead) URL of the LangSmith Debugger instance to connect to.",
) )
@click.option( @click.option(
"--allow-blocking", "--allow-blocking",
@@ -687,16 +694,25 @@ def dev(
port: int, port: int,
no_reload: bool, no_reload: bool,
config: str, config: str,
n_jobs_per_worker: int | None, n_jobs_per_worker: Optional[int],
no_browser: bool, no_browser: bool,
debug_port: int | None, debug_port: Optional[int],
wait_for_client: bool, wait_for_client: bool,
studio_url: str | None, debugger_url: Optional[str],
studio_url: Optional[str],
allow_blocking: bool, allow_blocking: bool,
tunnel: bool, tunnel: bool,
server_log_level: str, server_log_level: str,
): ):
"""CLI entrypoint for running the LangGraph API server.""" """CLI entrypoint for running the LangGraph API server."""
if studio_url is not None:
click.secho(
"Warning: --studio-url is deprecated and will be removed in a future version. "
"Please use --debugger-url instead.",
fg="yellow",
)
if debugger_url is None:
debugger_url = studio_url
try: try:
from langgraph_api.cli import run_server # type: ignore from langgraph_api.cli import run_server # type: ignore
except ImportError: except ImportError:
@@ -760,7 +776,7 @@ def dev(
http=config_json.get("http"), http=config_json.get("http"),
ui=config_json.get("ui"), ui=config_json.get("ui"),
ui_config=config_json.get("ui_config"), ui_config=config_json.get("ui_config"),
studio_url=studio_url, studio_url=debugger_url,
allow_blocking=allow_blocking, allow_blocking=allow_blocking,
tunnel=tunnel, tunnel=tunnel,
server_level=server_log_level, server_level=server_log_level,
@@ -775,7 +791,7 @@ def dev(
) )
@cli.command("new", help="🌱 Create a new LangGraph project from a template.") @cli.command("new", help="🌱 Create a new LangGraph project from a template.")
@log_command @log_command
def new(path: str | None, template: str | None) -> None: def new(path: Optional[str], template: Optional[str]) -> None:
"""Create a new LangGraph project from a template.""" """Create a new LangGraph project from a template."""
return create_new(path, template) return create_new(path, template)
@@ -785,17 +801,17 @@ def prepare_args_and_stdin(
capabilities: DockerCapabilities, capabilities: DockerCapabilities,
config_path: pathlib.Path, config_path: pathlib.Path,
config: Config, config: Config,
docker_compose: pathlib.Path | None, docker_compose: Optional[pathlib.Path],
port: int, port: int,
watch: bool, watch: bool,
debugger_port: int | None = None, debugger_port: Optional[int] = None,
debugger_base_url: str | None = None, debugger_base_url: Optional[str] = None,
postgres_uri: str | None = None, postgres_uri: Optional[str] = None,
api_version: str | None = None, api_version: Optional[str] = None,
# Like "my-tag" (if you already built it locally) # Like "my-tag" (if you already built it locally)
image: str | None = None, image: Optional[str] = None,
# Like "langchain/langgraphjs-api" or "langchain/langgraph-api # Like "langchain/langgraphjs-api" or "langchain/langgraph-api
base_image: str | None = None, base_image: Optional[str] = None,
) -> tuple[list[str], str]: ) -> tuple[list[str], str]:
assert config_path.exists(), f"Config file not found: {config_path}" assert config_path.exists(), f"Config file not found: {config_path}"
# prepare args # prepare args
@@ -834,17 +850,17 @@ def prepare(
*, *,
capabilities: DockerCapabilities, capabilities: DockerCapabilities,
config_path: pathlib.Path, config_path: pathlib.Path,
docker_compose: pathlib.Path | None, docker_compose: Optional[pathlib.Path],
port: int, port: int,
pull: bool, pull: bool,
watch: bool, watch: bool,
verbose: bool, verbose: bool,
debugger_port: int | None = None, debugger_port: Optional[int] = None,
debugger_base_url: str | None = None, debugger_base_url: Optional[str] = None,
postgres_uri: str | None = None, postgres_uri: Optional[str] = None,
api_version: str | None = None, api_version: Optional[str] = None,
image: str | None = None, image: Optional[str] = None,
base_image: str | None = None, base_image: Optional[str] = None,
) -> tuple[list[str], str]: ) -> tuple[list[str], str]:
"""Prepare the arguments and stdin for running the LangGraph API server.""" """Prepare the arguments and stdin for running the LangGraph API server."""
config_json = langgraph_cli.config.validate_config_file(config_path) config_json = langgraph_cli.config.validate_config_file(config_path)
+542 -62
View File
@@ -4,12 +4,10 @@ import pathlib
import re import re
import textwrap import textwrap
from collections import Counter from collections import Counter
from typing import Literal, NamedTuple from typing import Any, Literal, NamedTuple, Optional, TypedDict, Union
import click import click
from langgraph_cli.schemas import Config, Distros
MIN_NODE_VERSION = "20" MIN_NODE_VERSION = "20"
DEFAULT_NODE_VERSION = "20" DEFAULT_NODE_VERSION = "20"
@@ -19,12 +17,510 @@ DEFAULT_PYTHON_VERSION = "3.11"
DEFAULT_IMAGE_DISTRO = "debian" DEFAULT_IMAGE_DISTRO = "debian"
Distros = Literal["debian", "wolfi", "bullseye", "bookworm"]
MiddlewareOrders = Literal["auth_first", "middleware_first"]
class TTLConfig(TypedDict, total=False):
"""Configuration for TTL (time-to-live) behavior in the store."""
refresh_on_read: bool
"""Default behavior for refreshing TTLs on read operations (GET and SEARCH).
If True, TTLs will be refreshed on read operations (get/search) by default.
This can be overridden per-operation by explicitly setting refresh_ttl.
Defaults to True if not configured.
"""
default_ttl: Optional[float]
"""Optional. Default TTL (time-to-live) in minutes for new items.
If provided, all new items will have this TTL unless explicitly overridden.
If omitted, items will have no TTL by default.
"""
sweep_interval_minutes: Optional[int]
"""Optional. Interval in minutes between TTL sweep iterations.
If provided, the store will periodically delete expired items based on the TTL.
If omitted, no automatic sweeping will occur.
"""
class IndexConfig(TypedDict, total=False):
"""Configuration for indexing documents for semantic search in the store.
This governs how text is converted into embeddings and stored for vector-based lookups.
"""
dims: int
"""Required. Dimensionality of the embedding vectors you will store.
Must match the output dimension of your selected embedding model or custom embed function.
If mismatched, you will likely encounter shape/size errors when inserting or querying vectors.
Common embedding model output dimensions:
- openai:text-embedding-3-large: 3072
- openai:text-embedding-3-small: 1536
- openai:text-embedding-ada-002: 1536
- cohere:embed-english-v3.0: 1024
- cohere:embed-english-light-v3.0: 384
- cohere:embed-multilingual-v3.0: 1024
- cohere:embed-multilingual-light-v3.0: 384
"""
embed: str
"""Required. Identifier or reference to the embedding model or a custom embedding function.
The format can vary:
- "<provider>:<model_name>" for recognized providers (e.g., "openai:text-embedding-3-large")
- "path/to/module.py:function_name" for your own local embedding function
- "my_custom_embed" if it's a known alias in your system
Examples:
- "openai:text-embedding-3-large"
- "cohere:embed-multilingual-v3.0"
- "src/app.py:embeddings"
Note: Must return embeddings of dimension `dims`.
"""
fields: Optional[list[str]]
"""Optional. List of JSON fields to extract before generating embeddings.
Defaults to ["$"], which means the entire JSON object is embedded as one piece of text.
If you provide multiple fields (e.g. ["title", "content"]), each is extracted and embedded separately,
often saving token usage if you only care about certain parts of the data.
Example:
fields=["title", "abstract", "author.biography"]
"""
class StoreConfig(TypedDict, total=False):
"""Configuration for the built-in long-term memory store.
This store can optionally perform semantic search. If you omit `index`,
the store will just handle traditional (non-embedded) data without vector lookups.
"""
index: Optional[IndexConfig]
"""Optional. Defines the vector-based semantic search configuration.
If provided, the store will:
- Generate embeddings according to `index.embed`
- Enforce the embedding dimension given by `index.dims`
- Embed only specified JSON fields (if any) from `index.fields`
If omitted, no vector index is initialized.
"""
ttl: Optional[TTLConfig]
"""Optional. Defines the TTL (time-to-live) behavior configuration.
If provided, the store will apply TTL settings according to the configuration.
If omitted, no TTL behavior is configured.
"""
class ThreadTTLConfig(TypedDict, total=False):
"""Configure a default TTL for checkpointed data within threads."""
strategy: Literal["delete"]
"""Strategy to use for deleting checkpointed data.
Choices:
- "delete": Delete all checkpoints for a thread after TTL expires.
"""
default_ttl: Optional[float]
"""Default TTL (time-to-live) in minutes for checkpointed data."""
sweep_interval_minutes: Optional[int]
"""Interval in minutes between sweep iterations.
If omitted, a default interval will be used (typically ~ 5 minutes)."""
class CheckpointerConfig(TypedDict, total=False):
"""Configuration for the built-in checkpointer, which handles checkpointing of state.
If omitted, no checkpointer is set up (the object store will still be present, however).
"""
ttl: Optional[ThreadTTLConfig]
"""Optional. Defines the TTL (time-to-live) behavior configuration.
If provided, the checkpointer will apply TTL settings according to the configuration.
If omitted, no TTL behavior is configured.
"""
class SecurityConfig(TypedDict, total=False):
"""Configuration for OpenAPI security definitions and requirements.
Useful for specifying global or path-level authentication and authorization flows
(e.g., OAuth2, API key headers, etc.).
"""
securitySchemes: dict[str, dict[str, Any]]
"""Required. Dict describing each security scheme recognized by your OpenAPI spec.
Keys are scheme names (e.g. "OAuth2", "ApiKeyAuth") and values are their definitions.
Example:
{
"OAuth2": {
"type": "oauth2",
"flows": {
"password": {
"tokenUrl": "/token",
"scopes": {"read": "Read data", "write": "Write data"}
}
}
}
}
"""
security: list[dict[str, list[str]]]
"""Optional. Global security requirements across all endpoints.
Each element in the list maps a security scheme (e.g. "OAuth2") to a list of scopes (e.g. ["read", "write"]).
Example:
[
{"OAuth2": ["read", "write"]},
{"ApiKeyAuth": []}
]
"""
# path => {method => security}
paths: dict[str, dict[str, list[dict[str, list[str]]]]]
"""Optional. Path-specific security overrides.
Keys are path templates (e.g., "/items/{item_id}"), mapping to:
- Keys that are HTTP methods (e.g., "GET", "POST"),
- Values are lists of security definitions (just like `security`) for that method.
Example:
{
"/private_data": {
"GET": [{"OAuth2": ["read"]}],
"POST": [{"OAuth2": ["write"]}]
}
}
"""
class AuthConfig(TypedDict, total=False):
"""Configuration for custom authentication logic and how it integrates into the OpenAPI spec."""
path: str
"""Required. Path to an instance of the Auth() class that implements custom authentication.
Format: "path/to/file.py:my_auth"
"""
disable_studio_auth: bool
"""Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio.
Defaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header
value is a valid API key for the deployment's workspace. If True, all requests will go through your custom
authentication logic, regardless of origin of the request.
"""
openapi: SecurityConfig
"""Required. Detailed security configuration that merges into your deployment's OpenAPI spec.
Example (OAuth2):
{
"securitySchemes": {
"OAuth2": {
"type": "oauth2",
"flows": {
"password": {
"tokenUrl": "/token",
"scopes": {"me": "Read user info", "items": "Manage items"}
}
}
}
},
"security": [
{"OAuth2": ["me"]}
]
}
"""
class CorsConfig(TypedDict, total=False):
"""Specifies Cross-Origin Resource Sharing (CORS) rules for your server.
If omitted, defaults are typically very restrictive (often no cross-origin requests).
Configure carefully if you want to allow usage from browsers hosted on other domains.
"""
allow_origins: list[str]
"""Optional. List of allowed origins (e.g., "https://example.com").
Default is often an empty list (no external origins).
Use "*" only if you trust all origins, as that bypasses most restrictions.
"""
allow_methods: list[str]
"""Optional. HTTP methods permitted for cross-origin requests (e.g. ["GET", "POST"]).
Default might be ["GET", "POST", "OPTIONS"] depending on your server framework.
"""
allow_headers: list[str]
"""Optional. HTTP headers that can be used in cross-origin requests (e.g. ["Content-Type", "Authorization"])."""
allow_credentials: bool
"""Optional. If True, cross-origin requests can include credentials (cookies, auth headers).
Default False to avoid accidentally exposing secured endpoints to untrusted sites.
"""
allow_origin_regex: str
"""Optional. A regex pattern for matching allowed origins, used if you have dynamic subdomains.
Example: "^https://.*\\.mycompany\\.com$"
"""
expose_headers: list[str]
"""Optional. List of headers that browsers are allowed to read from the response in cross-origin contexts."""
max_age: int
"""Optional. How many seconds the browser may cache preflight responses.
Default might be 600 (10 minutes). Larger values reduce preflight requests but can cause stale configurations.
"""
class ConfigurableHeaderConfig(TypedDict):
"""Customize which headers to include as configurable values in your runs.
By default, omits x-api-key, x-tenant-id, and x-service-key.
Exclusions (if provided) take precedence.
Each value can be a raw string with an optional wildcard.
"""
includes: Optional[list[str]]
"""Headers to include (if not also matches against an 'exludes' pattern.
Examples:
- 'user-agent'
- 'x-configurable-*'
"""
excludes: Optional[list[str]]
"""Headers to exclude. Applied before the 'includes' checks.
Examples:
- 'x-api-key'
- '*key*'
- '*token*'
"""
class HttpConfig(TypedDict, total=False):
"""Configuration for the built-in HTTP server that powers your deployment's routes and endpoints."""
app: str
"""Optional. Import path to a custom Starlette/FastAPI application to mount.
Format: "path/to/module.py:app_var"
If provided, it can override or extend the default routes.
"""
disable_assistants: bool
"""Optional. If True, /assistants routes are removed from the server.
Default is False (meaning /assistants is enabled).
"""
disable_threads: bool
"""Optional. If True, /threads routes are removed.
Default is False.
"""
disable_runs: bool
"""Optional. If True, /runs routes are removed.
Default is False.
"""
disable_store: bool
"""Optional. If True, /store routes are removed, disabling direct store interactions via HTTP.
Default is False.
"""
disable_mcp: bool
"""Optional. If True, /mcp routes are removed, disabling the MCP server.
Default is False.
"""
disable_meta: bool
"""Optional. Remove meta endpoints.
Set to True to disable the following endpoints: /openapi.json, /info, /metrics, /docs.
This will also make the /ok endpoint skip any DB or other checks, always returning {"ok": True}.
Default is False.
"""
cors: Optional[CorsConfig]
"""Optional. Defines CORS restrictions. If omitted, no special rules are set and
cross-origin behavior depends on default server settings.
"""
configurable_headers: Optional[ConfigurableHeaderConfig]
"""Optional. Defines how headers are treated for a run's configuration.
You can include or exclude headers as configurable values to condition your
agent's behavior or permissions on a request's headers."""
logging_headers: Optional[ConfigurableHeaderConfig]
"""Optional. Defines which headers are excluded from logging."""
middleware_order: Optional[MiddlewareOrders]
"""Optional. Defines the order in which to apply server customizations.
Choices:
- "auth_first": Authentication hooks (custom or default) are evaluated
before custom middleware.
- "middleware_first": Custom middleware is evaluated
before authentication hooks (custom or default).
Default is `middleware_first`.
"""
enable_custom_route_auth: bool
"""Optional. If True, authentication is enabled for custom routes,
not just the routes that are protected by default.
(Routes protected by default include /assistants, /threads, and /runs).
Default is False. This flag only affects authentication behavior
if `app` is provided and contains custom routes.
"""
class Config(TypedDict, total=False):
"""Top-level config for langgraph-cli or similar deployment tooling."""
python_version: str
"""Optional. Python version in 'major.minor' format (e.g. '3.11').
Must be at least 3.11 or greater for this deployment to function properly.
"""
node_version: Optional[str]
"""Optional. Node.js version as a major version (e.g. '20'), if your deployment needs Node.
Must be >= 20 if provided.
"""
api_version: Optional[str]
"""Optional. Which semantic version of the LangGraph API server to use.
Defaults to latest. Check the
[changelog](https://docs.langchain.com/langgraph-platform/langgraph-server-changelog)
for more information."""
_INTERNAL_docker_tag: Optional[str]
"""Optional. Internal use only.
"""
base_image: Optional[str]
"""Optional. Base image to use for the LangGraph API server.
Defaults to langchain/langgraph-api or langchain/langgraphjs-api."""
image_distro: Optional[Distros]
"""Optional. Linux distribution for the base image.
Must be one of 'wolfi', 'debian', 'bullseye', or 'bookworm'.
If omitted, defaults to 'debian' ('latest').
"""
pip_config_file: Optional[str]
"""Optional. Path to a pip config file (e.g., "/etc/pip.conf" or "pip.ini") for controlling
package installation (custom indices, credentials, etc.).
Only relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.
"""
pip_installer: Optional[str]
"""Optional. Python package installer to use ('auto', 'pip', 'uv').
- 'auto' (default): Use uv for supported base images, otherwise pip
- 'pip': Force use of pip regardless of base image support
- 'uv': Force use of uv (will fail if base image doesn't support it)
"""
dockerfile_lines: list[str]
"""Optional. Additional Docker instructions that will be appended to your base Dockerfile.
Useful for installing OS packages, setting environment variables, etc.
Example:
dockerfile_lines=[
"RUN apt-get update && apt-get install -y libmagic-dev",
"ENV MY_CUSTOM_VAR=hello_world"
]
"""
dependencies: list[str]
"""List of Python dependencies to install, either from PyPI or local paths.
Examples:
- "." or "./src" if you have a local Python package
- str (aka "anthropic") for a PyPI package
- "git+https://github.com/org/repo.git@main" for a Git-based package
Defaults to an empty list, meaning no additional packages installed beyond your base environment.
"""
graphs: dict[str, str]
"""Optional. Named definitions of graphs, each pointing to a Python object.
Graphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context
managers that accept a single configuration argument (of type RunnableConfig) and return a pregel object
(instance of Stategraph, etc.).
Keys are graph names, values are "path/to/file.py:object_name".
Example:
{
"mygraph": "graphs/my_graph.py:graph_definition",
"anothergraph": "graphs/another.py:get_graph"
}
"""
env: Union[dict[str, str], str]
"""Optional. Environment variables to set for your deployment.
- If given as a dict, keys are variable names and values are their values.
- If given as a string, it must be a path to a file containing lines in KEY=VALUE format.
Example as a dict:
env={"API_TOKEN": "abc123", "DEBUG": "true"}
Example as a file path:
env=".env"
"""
store: Optional[StoreConfig]
"""Optional. Configuration for the built-in long-term memory store, including semantic search indexing.
If omitted, no vector index is set up (the object store will still be present, however).
"""
checkpointer: Optional[CheckpointerConfig]
"""Optional. Configuration for the built-in checkpointer, which handles checkpointing of state.
If omitted, no checkpointer is set up (the object store will still be present, however).
"""
auth: Optional[AuthConfig]
"""Optional. Custom authentication config, including the path to your Python auth logic and
the OpenAPI security definitions it uses.
"""
http: Optional[HttpConfig]
"""Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed
and how cross-origin requests are handled.
"""
ui: Optional[dict[str, str]]
"""Optional. Named definitions of UI components emitted by the agent, each pointing to a JS/TS file.
"""
keep_pkg_tools: Optional[Union[bool, list[str]]]
"""Optional. Control whether to retain Python packaging tools in the final image.
Allowed tools are: "pip", "setuptools", "wheel".
You can also set to true to include all packaging tools.
"""
_BUILD_TOOLS = ("pip", "setuptools", "wheel") _BUILD_TOOLS = ("pip", "setuptools", "wheel")
def _get_pip_cleanup_lines( def _get_pip_cleanup_lines(
install_cmd: str, install_cmd: str,
to_uninstall: tuple[str] | None, to_uninstall: Optional[tuple[str]],
pip_installer: Literal["uv", "pip"], pip_installer: Literal["uv", "pip"],
) -> str: ) -> str:
commands = [ commands = [
@@ -90,7 +586,7 @@ def _parse_node_version(version_str: str) -> int:
) from None ) from None
def _is_node_graph(spec: str | dict) -> bool: def _is_node_graph(spec: Union[str, dict]) -> bool:
"""Check if a graph is a Node.js graph based on the file extension.""" """Check if a graph is a Node.js graph based on the file extension."""
if isinstance(spec, dict): if isinstance(spec, dict):
spec = spec.get("path") spec = spec.get("path")
@@ -350,7 +846,7 @@ class LocalDeps(NamedTuple):
real_pkgs: dict[pathlib.Path, tuple[str, str]] real_pkgs: dict[pathlib.Path, tuple[str, str]]
faux_pkgs: dict[pathlib.Path, tuple[str, str]] faux_pkgs: dict[pathlib.Path, tuple[str, str]]
# if . is in dependencies, use it as working_dir # if . is in dependencies, use it as working_dir
working_dir: str | None = None working_dir: Optional[str] = None
# if there are local dependencies in parent directories, use additional_contexts # if there are local dependencies in parent directories, use additional_contexts
additional_contexts: list[pathlib.Path] = None additional_contexts: list[pathlib.Path] = None
@@ -386,7 +882,7 @@ def _assemble_local_deps(config_path: pathlib.Path, config: Config) -> LocalDeps
pip_reqs = [] pip_reqs = []
real_pkgs = {} real_pkgs = {}
faux_pkgs = {} faux_pkgs = {}
working_dir: str | None = None working_dir: Optional[str] = None
additional_contexts: list[pathlib.Path] = [] additional_contexts: list[pathlib.Path] = []
for local_dep in config["dependencies"]: for local_dep in config["dependencies"]:
@@ -769,7 +1265,7 @@ def python_config_to_docker(
config_path: pathlib.Path, config_path: pathlib.Path,
config: Config, config: Config,
base_image: str, base_image: str,
api_version: str | None = None, api_version: Optional[str] = None,
) -> tuple[str, dict[str, str]]: ) -> tuple[str, dict[str, str]]:
"""Generate a Dockerfile from the configuration.""" """Generate a Dockerfile from the configuration."""
pip_installer = config.get("pip_installer", "auto") pip_installer = config.get("pip_installer", "auto")
@@ -926,51 +1422,35 @@ ADD {relpath} /deps/{name}
] ]
) )
image_str = docker_tag(config, base_image, api_version) image_str = docker_tag(config, base_image, api_version)
docker_file_contents = [
# Prepare docker file contents f"FROM {image_str}",
docker_file_contents = [] "",
os.linesep.join(config["dockerfile_lines"]),
# Add syntax directive if we have additional contexts (requires BuildKit frontend.contexts capability) "",
if local_deps.additional_contexts: installs,
docker_file_contents.extend( "",
[ "# -- Installing all local dependencies --",
"# syntax=docker/dockerfile:1.4", f"""RUN for dep in /deps/*; do \
"",
]
)
# Add main dockerfile content
docker_file_contents.extend(
[
f"FROM {image_str}",
"",
os.linesep.join(config["dockerfile_lines"]),
"",
installs,
"",
"# -- Installing all local dependencies --",
f"""RUN for dep in /deps/*; do \
echo "Installing $dep"; \ echo "Installing $dep"; \
if [ -d "$dep" ]; then \ if [ -d "$dep" ]; then \
echo "Installing $dep"; \ echo "Installing $dep"; \
(cd "$dep" && {global_reqs_pip_install} -e .); \ (cd "$dep" && {global_reqs_pip_install} .); \
fi; \ fi; \
done""", done""",
"# -- End of local dependencies install --", "# -- End of local dependencies install --",
os.linesep.join(env_vars), os.linesep.join(env_vars),
"", "",
js_inst_str, js_inst_str,
"", "",
# Add pip cleanup after all installations are complete # Add pip cleanup after all installations are complete
_get_pip_cleanup_lines( _get_pip_cleanup_lines(
install_cmd=install_cmd, install_cmd=install_cmd,
to_uninstall=build_tools_to_uninstall, to_uninstall=build_tools_to_uninstall,
pip_installer=pip_installer, pip_installer=pip_installer,
), ),
"", "",
f"WORKDIR {local_deps.working_dir}" if local_deps.working_dir else "", f"WORKDIR {local_deps.working_dir}" if local_deps.working_dir else "",
] ]
)
additional_contexts: dict[str, str] = {} additional_contexts: dict[str, str] = {}
for p in local_deps.additional_contexts: for p in local_deps.additional_contexts:
@@ -989,10 +1469,10 @@ def node_config_to_docker(
config_path: pathlib.Path, config_path: pathlib.Path,
config: Config, config: Config,
base_image: str, base_image: str,
api_version: str | None = None, api_version: Optional[str] = None,
install_command: str | None = None, install_command: Optional[str] = None,
build_command: str | None = None, build_command: Optional[str] = None,
build_context: str | None = None, build_context: Optional[str] = None,
) -> tuple[str, dict[str, str]]: ) -> tuple[str, dict[str, str]]:
# Calculate paths for monorepo support # Calculate paths for monorepo support
if build_context: if build_context:
@@ -1082,8 +1562,8 @@ def default_base_image(config: Config) -> str:
def docker_tag( def docker_tag(
config: Config, config: Config,
base_image: str | None = None, base_image: Optional[str] = None,
api_version: str | None = None, api_version: Optional[str] = None,
) -> str: ) -> str:
api_version = api_version or config.get("api_version") api_version = api_version or config.get("api_version")
base_image = base_image or default_base_image(config) base_image = base_image or default_base_image(config)
@@ -1132,11 +1612,11 @@ def _calculate_relative_workdir(config_path: pathlib.Path, build_context: str) -
def config_to_docker( def config_to_docker(
config_path: pathlib.Path, config_path: pathlib.Path,
config: Config, config: Config,
base_image: str | None = None, base_image: Optional[str] = None,
api_version: str | None = None, api_version: Optional[str] = None,
install_command: str | None = None, install_command: Optional[str] = None,
build_command: str | None = None, build_command: Optional[str] = None,
build_context: str | None = None, build_context: Optional[str] = None,
) -> tuple[str, dict[str, str]]: ) -> tuple[str, dict[str, str]]:
base_image = base_image or default_base_image(config) base_image = base_image or default_base_image(config)
@@ -1157,9 +1637,9 @@ def config_to_docker(
def config_to_compose( def config_to_compose(
config_path: pathlib.Path, config_path: pathlib.Path,
config: Config, config: Config,
base_image: str | None = None, base_image: Optional[str] = None,
api_version: str | None = None, api_version: Optional[str] = None,
image: str | None = None, image: Optional[str] = None,
watch: bool = False, watch: bool = False,
) -> str: ) -> str:
base_image = base_image or default_base_image(config) base_image = base_image or default_base_image(config)
+16 -14
View File
@@ -1,7 +1,7 @@
import json import json
import pathlib import pathlib
import shutil import shutil
from typing import Literal, NamedTuple from typing import Literal, NamedTuple, Optional
import click.exceptions import click.exceptions
@@ -90,7 +90,9 @@ def check_capabilities(runner) -> DockerCapabilities:
) )
def debugger_compose(*, port: int | None = None, base_url: str | None = None) -> dict: def debugger_compose(
*, port: Optional[int] = None, base_url: Optional[str] = None
) -> dict:
if port is None: if port is None:
return "" return ""
@@ -139,16 +141,16 @@ def compose_as_dict(
capabilities: DockerCapabilities, capabilities: DockerCapabilities,
*, *,
port: int, port: int,
debugger_port: int | None = None, debugger_port: Optional[int] = None,
debugger_base_url: str | None = None, debugger_base_url: Optional[str] = None,
# postgres://user:password@host:port/database?option=value # postgres://user:password@host:port/database?option=value
postgres_uri: str | None = None, postgres_uri: Optional[str] = None,
# If you are running against an already-built image, you can pass it here # If you are running against an already-built image, you can pass it here
image: str | None = None, image: Optional[str] = None,
# Base image to use for the LangGraph API server # Base image to use for the LangGraph API server
base_image: str | None = None, base_image: Optional[str] = None,
# API version of the base image # API version of the base image
api_version: str | None = None, api_version: Optional[str] = None,
) -> dict: ) -> dict:
"""Create a docker compose file as a dictionary in YML style.""" """Create a docker compose file as a dictionary in YML style."""
if postgres_uri is None: if postgres_uri is None:
@@ -248,13 +250,13 @@ def compose(
capabilities: DockerCapabilities, capabilities: DockerCapabilities,
*, *,
port: int, port: int,
debugger_port: int | None = None, debugger_port: Optional[int] = None,
debugger_base_url: str | None = None, debugger_base_url: Optional[str] = None,
# postgres://user:password@host:port/database?option=value # postgres://user:password@host:port/database?option=value
postgres_uri: str | None = None, postgres_uri: Optional[str] = None,
image: str | None = None, image: Optional[str] = None,
base_image: str | None = None, base_image: Optional[str] = None,
api_version: str | None = None, api_version: Optional[str] = None,
) -> str: ) -> str:
"""Create a docker compose file as a string.""" """Create a docker compose file as a string."""
compose_content = compose_as_dict( compose_content = compose_as_dict(
+7 -8
View File
@@ -1,9 +1,8 @@
import asyncio import asyncio
import signal import signal
import sys import sys
from collections.abc import Callable
from contextlib import contextmanager from contextlib import contextmanager
from typing import cast from typing import Callable, Optional, cast
import click.exceptions import click.exceptions
@@ -31,12 +30,12 @@ def Runner():
async def subp_exec( async def subp_exec(
cmd: str, cmd: str,
*args: str, *args: str,
input: str | None = None, input: Optional[str] = None,
wait: float | None = None, wait: Optional[float] = None,
verbose: bool = False, verbose: bool = False,
collect: bool = False, collect: bool = False,
on_stdout: Callable[[str], bool | None] | None = None, on_stdout: Optional[Callable[[str], Optional[bool]]] = None,
) -> tuple[str | None, str | None]: ) -> tuple[Optional[str], Optional[str]]:
if verbose: if verbose:
cmd_str = f"+ {cmd} {' '.join(map(str, args))}" cmd_str = f"+ {cmd} {' '.join(map(str, args))}"
if input: if input:
@@ -127,8 +126,8 @@ async def monitor_stream(
stream: asyncio.StreamReader, stream: asyncio.StreamReader,
collect: bool = False, collect: bool = False,
display: bool = False, display: bool = False,
on_line: Callable[[str], bool | None] | None = None, on_line: Optional[Callable[[str], Optional[bool]]] = None,
) -> bytearray | None: ) -> Optional[bytearray]:
if collect: if collect:
ba = bytearray() ba = bytearray()
+1 -1
View File
@@ -1,7 +1,7 @@
import sys import sys
import threading import threading
import time import time
from collections.abc import Callable from typing import Callable
class Progress: class Progress:
-558
View File
@@ -1,558 +0,0 @@
from typing import Any, Literal, TypedDict
Distros = Literal["debian", "wolfi", "bullseye", "bookworm"]
MiddlewareOrders = Literal["auth_first", "middleware_first"]
class TTLConfig(TypedDict, total=False):
"""Configuration for TTL (time-to-live) behavior in the store."""
refresh_on_read: bool
"""Default behavior for refreshing TTLs on read operations (`GET` and `SEARCH`).
If `True`, TTLs will be refreshed on read operations (get/search) by default.
This can be overridden per-operation by explicitly setting `refresh_ttl`.
Defaults to `True` if not configured.
"""
default_ttl: float | None
"""Optional. Default TTL (time-to-live) in minutes for new items.
If provided, all new items will have this TTL unless explicitly overridden.
If omitted, items will have no TTL by default.
"""
sweep_interval_minutes: int | None
"""Optional. Interval in minutes between TTL sweep iterations.
If provided, the store will periodically delete expired items based on the TTL.
If omitted, no automatic sweeping will occur.
"""
class IndexConfig(TypedDict, total=False):
"""Configuration for indexing documents for semantic search in the store.
This governs how text is converted into embeddings and stored for vector-based lookups.
"""
dims: int
"""Required. Dimensionality of the embedding vectors you will store.
Must match the output dimension of your selected embedding model or custom embed function.
If mismatched, you will likely encounter shape/size errors when inserting or querying vectors.
Common embedding model output dimensions:
- openai:text-embedding-3-large: 3072
- openai:text-embedding-3-small: 1536
- openai:text-embedding-ada-002: 1536
- cohere:embed-english-v3.0: 1024
- cohere:embed-english-light-v3.0: 384
- cohere:embed-multilingual-v3.0: 1024
- cohere:embed-multilingual-light-v3.0: 384
"""
embed: str
"""Required. Identifier or reference to the embedding model or a custom embedding function.
The format can vary:
- "<provider>:<model_name>" for recognized providers (e.g., "openai:text-embedding-3-large")
- "path/to/module.py:function_name" for your own local embedding function
- "my_custom_embed" if it's a known alias in your system
Examples:
- "openai:text-embedding-3-large"
- "cohere:embed-multilingual-v3.0"
- "src/app.py:embeddings"
Note: Must return embeddings of dimension `dims`.
"""
fields: list[str] | None
"""Optional. List of JSON fields to extract before generating embeddings.
Defaults to ["$"], which means the entire JSON object is embedded as one piece of text.
If you provide multiple fields (e.g. ["title", "content"]), each is extracted and embedded separately,
often saving token usage if you only care about certain parts of the data.
Example:
fields=["title", "abstract", "author.biography"]
"""
class StoreConfig(TypedDict, total=False):
"""Configuration for the built-in long-term memory store.
This store can optionally perform semantic search. If you omit `index`,
the store will just handle traditional (non-embedded) data without vector lookups.
"""
index: IndexConfig | None
"""Optional. Defines the vector-based semantic search configuration.
If provided, the store will:
- Generate embeddings according to `index.embed`
- Enforce the embedding dimension given by `index.dims`
- Embed only specified JSON fields (if any) from `index.fields`
If omitted, no vector index is initialized.
"""
ttl: TTLConfig | None
"""Optional. Defines the TTL (time-to-live) behavior configuration.
If provided, the store will apply TTL settings according to the configuration.
If omitted, no TTL behavior is configured.
"""
class ThreadTTLConfig(TypedDict, total=False):
"""Configure a default TTL for checkpointed data within threads."""
strategy: Literal["delete"]
"""Strategy to use for deleting checkpointed data.
Choices:
- "delete": Delete all checkpoints for a thread after TTL expires.
"""
default_ttl: float | None
"""Default TTL (time-to-live) in minutes for checkpointed data."""
sweep_interval_minutes: int | None
"""Interval in minutes between sweep iterations.
If omitted, a default interval will be used (typically ~ 5 minutes)."""
class SerdeConfig(TypedDict, total=False):
"""Configuration for the built-in serde, which handles checkpointing of state.
If omitted, no serde is set up (the object store will still be present, however)."""
allowed_json_modules: list[list[str]] | bool | None
"""Optional. List of allowed python modules to de-serialize custom objects from.
If provided, only the specified modules will be allowed to be deserialized.
If omitted, no modules are allowed, and the object returned will simply be a json object OR
a deserialized langchain object.
Example:
{...
"serde": {
"allowed_json_modules": [
["my_agent", "my_file", "SomeType"],
]
}
}
If you set this to True, any module will be allowed to be deserialized.
Example:
{...
"serde": {
"allowed_json_modules": true
}
}
"""
pickle_fallback: bool
"""Optional. Whether to allow pickling as a fallback for deserialization.
If True, pickling will be allowed as a fallback for deserialization.
If False, pickling will not be allowed as a fallback for deserialization.
Defaults to True if not configured."""
class CheckpointerConfig(TypedDict, total=False):
"""Configuration for the built-in checkpointer, which handles checkpointing of state.
If omitted, no checkpointer is set up (the object store will still be present, however).
"""
ttl: ThreadTTLConfig | None
"""Optional. Defines the TTL (time-to-live) behavior configuration.
If provided, the checkpointer will apply TTL settings according to the configuration.
If omitted, no TTL behavior is configured.
"""
serde: SerdeConfig | None
"""Optional. Defines the serde configuration.
If provided, the checkpointer will apply serde settings according to the configuration.
If omitted, no serde behavior is configured.
This configuration requires server version 0.5 or later to take effect.
"""
class SecurityConfig(TypedDict, total=False):
"""Configuration for OpenAPI security definitions and requirements.
Useful for specifying global or path-level authentication and authorization flows
(e.g., OAuth2, API key headers, etc.).
"""
securitySchemes: dict[str, dict[str, Any]]
"""Describe each security scheme recognized by your OpenAPI spec.
Keys are scheme names (e.g. "OAuth2", "ApiKeyAuth") and values are their definitions.
Example:
{
"OAuth2": {
"type": "oauth2",
"flows": {
"password": {
"tokenUrl": "/token",
"scopes": {"read": "Read data", "write": "Write data"}
}
}
}
}
"""
security: list[dict[str, list[str]]]
"""Global security requirements across all endpoints.
Each element in the list maps a security scheme (e.g. "OAuth2") to a list of scopes (e.g. ["read", "write"]).
Example:
[
{"OAuth2": ["read", "write"]},
{"ApiKeyAuth": []}
]
"""
# path => {method => security}
paths: dict[str, dict[str, list[dict[str, list[str]]]]]
"""Path-specific security overrides.
Keys are path templates (e.g., "/items/{item_id}"), mapping to:
- Keys that are HTTP methods (e.g., "GET", "POST"),
- Values are lists of security definitions (just like `security`) for that method.
Example:
{
"/private_data": {
"GET": [{"OAuth2": ["read"]}],
"POST": [{"OAuth2": ["write"]}]
}
}
"""
class AuthConfig(TypedDict, total=False):
"""Configuration for custom authentication logic and how it integrates into the OpenAPI spec."""
path: str
"""Required. Path to an instance of the Auth() class that implements custom authentication.
Format: "path/to/file.py:my_auth"
"""
disable_studio_auth: bool
"""Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio.
Defaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header
value is a valid API key for the deployment's workspace. If `True`, all requests will go through your custom
authentication logic, regardless of origin of the request.
"""
openapi: SecurityConfig
"""The security configuration to include in your server's OpenAPI spec.
Example (OAuth2):
{
"securitySchemes": {
"OAuth2": {
"type": "oauth2",
"flows": {
"password": {
"tokenUrl": "/token",
"scopes": {"me": "Read user info", "items": "Manage items"}
}
}
}
},
"security": [
{"OAuth2": ["me"]}
]
}
"""
class CorsConfig(TypedDict, total=False):
"""Specifies Cross-Origin Resource Sharing (CORS) rules for your server.
If omitted, defaults are typically very restrictive (often no cross-origin requests).
Configure carefully if you want to allow usage from browsers hosted on other domains.
"""
allow_origins: list[str]
"""Optional. List of allowed origins (e.g., "https://example.com").
Default is often an empty list (no external origins).
Use "*" only if you trust all origins, as that bypasses most restrictions.
"""
allow_methods: list[str]
"""Optional. HTTP methods permitted for cross-origin requests (e.g. ["GET", "POST"]).
Default might be ["GET", "POST", "OPTIONS"] depending on your server framework.
"""
allow_headers: list[str]
"""Optional. HTTP headers that can be used in cross-origin requests (e.g. ["Content-Type", "Authorization"])."""
allow_credentials: bool
"""Optional. If `True`, cross-origin requests can include credentials (cookies, auth headers).
Default False to avoid accidentally exposing secured endpoints to untrusted sites.
"""
allow_origin_regex: str
"""Optional. A regex pattern for matching allowed origins, used if you have dynamic subdomains.
Example: "^https://.*\\.mycompany\\.com$"
"""
expose_headers: list[str]
"""Optional. List of headers that browsers are allowed to read from the response in cross-origin contexts."""
max_age: int
"""Optional. How many seconds the browser may cache preflight responses.
Default might be 600 (10 minutes). Larger values reduce preflight requests but can cause stale configurations.
"""
class ConfigurableHeaderConfig(TypedDict):
"""Customize which headers to include as configurable values in your runs.
By default, omits x-api-key, x-tenant-id, and x-service-key.
Exclusions (if provided) take precedence.
Each value can be a raw string with an optional wildcard.
"""
includes: list[str] | None
"""Headers to include (if not also matches against an 'exludes' pattern.
Examples:
- 'user-agent'
- 'x-configurable-*'
"""
excludes: list[str] | None
"""Headers to exclude. Applied before the 'includes' checks.
Examples:
- 'x-api-key'
- '*key*'
- '*token*'
"""
class HttpConfig(TypedDict, total=False):
"""Configuration for the built-in HTTP server that powers your deployment's routes and endpoints."""
app: str
"""Optional. Import path to a custom Starlette/FastAPI application to mount.
Format: "path/to/module.py:app_var"
If provided, it can override or extend the default routes.
"""
disable_assistants: bool
"""Optional. If `True`, /assistants routes are removed from the server.
Default is False (meaning /assistants is enabled).
"""
disable_threads: bool
"""Optional. If `True`, /threads routes are removed.
Default is False.
"""
disable_runs: bool
"""Optional. If `True`, /runs routes are removed.
Default is False.
"""
disable_store: bool
"""Optional. If `True`, /store routes are removed, disabling direct store interactions via HTTP.
Default is False.
"""
disable_mcp: bool
"""Optional. If `True`, /mcp routes are removed, disabling the MCP server.
Default is False.
"""
disable_meta: bool
"""Optional. Remove meta endpoints.
Set to True to disable the following endpoints: /openapi.json, /info, /metrics, /docs.
This will also make the /ok endpoint skip any DB or other checks, always returning {"ok": True}.
Default is False.
"""
cors: CorsConfig | None
"""Optional. Defines CORS restrictions. If omitted, no special rules are set and
cross-origin behavior depends on default server settings.
"""
configurable_headers: ConfigurableHeaderConfig | None
"""Optional. Defines how headers are treated for a run's configuration.
You can include or exclude headers as configurable values to condition your
agent's behavior or permissions on a request's headers."""
logging_headers: ConfigurableHeaderConfig | None
"""Optional. Defines which headers are excluded from logging."""
middleware_order: MiddlewareOrders | None
"""Optional. Defines the order in which to apply server customizations.
Choices:
- "auth_first": Authentication hooks (custom or default) are evaluated
before custom middleware.
- "middleware_first": Custom middleware is evaluated
before authentication hooks (custom or default).
Default is `middleware_first`.
"""
enable_custom_route_auth: bool
"""Optional. If `True`, authentication is enabled for custom routes,
not just the routes that are protected by default.
(Routes protected by default include /assistants, /threads, and /runs).
Default is False. This flag only affects authentication behavior
if `app` is provided and contains custom routes.
"""
class Config(TypedDict, total=False):
"""Top-level config for langgraph-cli or similar deployment tooling."""
python_version: str
"""Optional. Python version in 'major.minor' format (e.g. '3.11').
Must be at least 3.11 or greater for this deployment to function properly.
"""
node_version: str | None
"""Optional. Node.js version as a major version (e.g. '20'), if your deployment needs Node.
Must be >= 20 if provided.
"""
api_version: str | None
"""Optional. Which semantic version of the LangGraph API server to use.
Defaults to latest. Check the
[changelog](https://docs.langchain.com/langgraph-platform/langgraph-server-changelog)
for more information."""
_INTERNAL_docker_tag: str | None
"""Optional. Internal use only.
"""
base_image: str | None
"""Optional. Base image to use for the LangGraph API server.
Defaults to langchain/langgraph-api or langchain/langgraphjs-api."""
image_distro: Distros | None
"""Optional. Linux distribution for the base image.
Must be one of 'wolfi', 'debian', 'bullseye', or 'bookworm'.
If omitted, defaults to 'debian' ('latest').
"""
pip_config_file: str | None
"""Optional. Path to a pip config file (e.g., "/etc/pip.conf" or "pip.ini") for controlling
package installation (custom indices, credentials, etc.).
Only relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.
"""
pip_installer: str | None
"""Optional. Python package installer to use ('auto', 'pip', 'uv').
- 'auto' (default): Use uv for supported base images, otherwise pip
- 'pip': Force use of pip regardless of base image support
- 'uv': Force use of uv (will fail if base image doesn't support it)
"""
dockerfile_lines: list[str]
"""Optional. Additional Docker instructions that will be appended to your base Dockerfile.
Useful for installing OS packages, setting environment variables, etc.
Example:
dockerfile_lines=[
"RUN apt-get update && apt-get install -y libmagic-dev",
"ENV MY_CUSTOM_VAR=hello_world"
]
"""
dependencies: list[str]
"""List of Python dependencies to install, either from PyPI or local paths.
Examples:
- "." or "./src" if you have a local Python package
- str (aka "anthropic") for a PyPI package
- "git+https://github.com/org/repo.git@main" for a Git-based package
Defaults to an empty list, meaning no additional packages installed beyond your base environment.
"""
graphs: dict[str, str]
"""Optional. Named definitions of graphs, each pointing to a Python object.
Graphs can be StateGraph, @entrypoint, or any other Pregel object OR they can point to (async) context
managers that accept a single configuration argument (of type RunnableConfig) and return a pregel object
(instance of Stategraph, etc.).
Keys are graph names, values are "path/to/file.py:object_name".
Example:
{
"mygraph": "graphs/my_graph.py:graph_definition",
"anothergraph": "graphs/another.py:get_graph"
}
"""
env: dict[str, str] | str
"""Optional. Environment variables to set for your deployment.
- If given as a dict, keys are variable names and values are their values.
- If given as a string, it must be a path to a file containing lines in KEY=VALUE format.
Example as a dict:
env={"API_TOKEN": "abc123", "DEBUG": "true"}
Example as a file path:
env=".env"
"""
store: StoreConfig | None
"""Optional. Configuration for the built-in long-term memory store, including semantic search indexing.
If omitted, no vector index is set up (the object store will still be present, however).
"""
checkpointer: CheckpointerConfig | None
"""Optional. Configuration for the built-in checkpointer, which handles checkpointing of state.
If omitted, no checkpointer is set up (the object store will still be present, however).
"""
auth: AuthConfig | None
"""Optional. Custom authentication config, including the path to your Python auth logic and
the OpenAPI security definitions it uses.
"""
http: HttpConfig | None
"""Optional. Configuration for the built-in HTTP server, controlling which custom routes are exposed
and how cross-origin requests are handled.
"""
ui: dict[str, str] | None
"""Optional. Named definitions of UI components emitted by the agent, each pointing to a JS/TS file.
"""
keep_pkg_tools: bool | list[str] | None
"""Optional. Control whether to retain Python packaging tools in the final image.
Allowed tools are: "pip", "setuptools", "wheel".
You can also set to true to include all packaging tools.
"""
__all__ = [
"Config",
"StoreConfig",
"CheckpointerConfig",
"AuthConfig",
"HttpConfig",
"MiddlewareOrders",
"Distros",
"TTLConfig",
"IndexConfig",
]
+4 -3
View File
@@ -2,6 +2,7 @@ import os
import shutil import shutil
import sys import sys
from io import BytesIO from io import BytesIO
from typing import Optional
from urllib import error, request from urllib import error, request
from zipfile import ZipFile from zipfile import ZipFile
@@ -64,7 +65,7 @@ def _choose_template() -> str:
click.secho(f" - {template_info['description']}", fg="white") click.secho(f" - {template_info['description']}", fg="white")
# Get the template choice from the user, defaulting to the first template if blank # Get the template choice from the user, defaulting to the first template if blank
template_choice: int | None = click.prompt( template_choice: Optional[int] = click.prompt(
"Enter the number of your template choice (default is 1)", "Enter the number of your template choice (default is 1)",
type=int, type=int,
default=1, default=1,
@@ -130,7 +131,7 @@ def _download_repo_with_requests(repo_url: str, path: str) -> None:
sys.exit(1) sys.exit(1)
def _get_template_url(template_name: str) -> str | None: def _get_template_url(template_name: str) -> Optional[str]:
""" """
Retrieves the template URL based on the provided template name. Retrieves the template URL based on the provided template name.
@@ -161,7 +162,7 @@ def _get_template_url(template_name: str) -> str | None:
return None return None
def create_new(path: str | None, template: str | None) -> None: def create_new(path: Optional[str], template: Optional[str]) -> None:
"""Create a new LangGraph project at the specified PATH using the chosen TEMPLATE. """Create a new LangGraph project at the specified PATH using the chosen TEMPLATE.
Args: Args:
+7 -18
View File
@@ -7,7 +7,7 @@ name = "langgraph-cli"
dynamic = ["version"] dynamic = ["version"]
description = "CLI for interacting with LangGraph API" description = "CLI for interacting with LangGraph API"
authors = [] authors = []
requires-python = ">=3.10" requires-python = ">=3.9"
readme = "README.md" readme = "README.md"
license = "MIT" license = "MIT"
license-files = ['LICENSE'] license-files = ['LICENSE']
@@ -19,36 +19,27 @@ dependencies = [
path = "langgraph_cli/__init__.py" path = "langgraph_cli/__init__.py"
[project.optional-dependencies] [project.optional-dependencies]
inmem = [ inmem = [
"langgraph-api>=0.4,<0.6.0 ; python_version >= '3.11'", "langgraph-api>=0.3,<0.5.0 ; python_version >= '3.11'",
"langgraph-runtime-inmem>=0.7 ; python_version >= '3.11'", "langgraph-runtime-inmem>=0.7 ; python_version >= '3.11'",
"python-dotenv>=0.8.0", "python-dotenv>=0.8.0",
] ]
[project.urls] [project.urls]
Source = "https://github.com/langchain-ai/langgraph/tree/main/libs/cli" Repository = "https://www.github.com/langchain-ai/langgraph"
Twitter = "https://x.com/LangChainAI"
Slack = "https://www.langchain.com/join-community"
Reddit = "https://www.reddit.com/r/LangChain/"
[project.scripts] [project.scripts]
langgraph = "langgraph_cli.cli:cli" langgraph = "langgraph_cli.cli:cli"
[dependency-groups] [dependency-groups]
test = [ dev = [
"ruff",
"codespell",
"pytest", "pytest",
"pytest-asyncio", "pytest-asyncio",
"pytest-mock", "pytest-mock",
"pytest-watch", "pytest-watch",
"msgspec",
]
lint = [
"ruff",
"codespell",
"mypy", "mypy",
] "msgspec",
dev = [
{include-group = "test"},
{include-group = "lint"},
] ]
[tool.uv] [tool.uv]
@@ -68,7 +59,5 @@ lint.select = [
"UP", # pyupgrade "UP", # pyupgrade
"B", # flake8-bugbear "B", # flake8-bugbear
"I", # isort "I", # isort
"UP", # pyupgrade
] ]
lint.ignore = ["E501", "B008"] lint.ignore = ["E501", "B008"]
target-version = "py310"
@@ -8,7 +8,7 @@ authors = [
license = { text = "MIT" } license = { text = "MIT" }
requires-python = ">=3.11,<4.0" requires-python = ">=3.11,<4.0"
dependencies = [ dependencies = [
"langgraph>=0.6.0,<2", "langgraph>=0.6.0,<0.7.0",
"langchain-core>=0.2.14", "langchain-core>=0.2.14",
] ]
+13 -56
View File
@@ -407,11 +407,11 @@
"properties": { "properties": {
"disable_studio_auth": { "disable_studio_auth": {
"type": "boolean", "type": "boolean",
"description": "Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio.\n\nDefaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header\nvalue is a valid API key for the deployment's workspace. If `True`, all requests will go through your custom\nauthentication logic, regardless of origin of the request.\n" "description": "Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio.\n\nDefaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header\nvalue is a valid API key for the deployment's workspace. If True, all requests will go through your custom\nauthentication logic, regardless of origin of the request.\n"
}, },
"openapi": { "openapi": {
"$ref": "#/$defs/SecurityConfig", "$ref": "#/$defs/SecurityConfig",
"description": "The security configuration to include in your server's OpenAPI spec.\n\n{\n}\n}\n}\n},\n]\n}\n" "description": "Required. Detailed security configuration that merges into your deployment's OpenAPI spec.\n\n{\n}\n}\n}\n},\n]\n}\n"
}, },
"path": { "path": {
"type": "string", "type": "string",
@@ -442,7 +442,7 @@
} }
} }
}, },
"description": "Path-specific security overrides.\n\n- Keys that are HTTP methods (e.g., \"GET\", \"POST\"),\n- Values are lists of security definitions (just like `security`) for that method.\n" "description": "Optional. Path-specific security overrides.\n\n- Keys that are HTTP methods (e.g., \"GET\", \"POST\"),\n- Values are lists of security definitions (just like `security`) for that method.\n"
}, },
"security": { "security": {
"type": "array", "type": "array",
@@ -455,14 +455,14 @@
} }
} }
}, },
"description": "Global security requirements across all endpoints.\n\nEach element in the list maps a security scheme (e.g. \"OAuth2\") to a list of scopes (e.g. [\"read\", \"write\"])." "description": "Optional. Global security requirements across all endpoints.\n\nEach element in the list maps a security scheme (e.g. \"OAuth2\") to a list of scopes (e.g. [\"read\", \"write\"])."
}, },
"securitySchemes": { "securitySchemes": {
"type": "object", "type": "object",
"additionalProperties": { "additionalProperties": {
"type": "object" "type": "object"
}, },
"description": "Describe each security scheme recognized by your OpenAPI spec.\n\nKeys are scheme names (e.g. \"OAuth2\", \"ApiKeyAuth\") and values are their definitions." "description": "Required. Dict describing each security scheme recognized by your OpenAPI spec.\n\nKeys are scheme names (e.g. \"OAuth2\", \"ApiKeyAuth\") and values are their definitions."
} }
}, },
"required": [] "required": []
@@ -472,17 +472,6 @@
"description": "Configuration for the built-in checkpointer, which handles checkpointing of state.\n\nIf omitted, no checkpointer is set up (the object store will still be present, however).", "description": "Configuration for the built-in checkpointer, which handles checkpointing of state.\n\nIf omitted, no checkpointer is set up (the object store will still be present, however).",
"type": "object", "type": "object",
"properties": { "properties": {
"serde": {
"anyOf": [
{
"$ref": "#/$defs/SerdeConfig"
},
{
"type": "null"
}
],
"description": "Optional. Defines the serde configuration.\n\nIf provided, the checkpointer will apply serde settings according to the configuration.\nIf omitted, no serde behavior is configured.\n\nThis configuration requires server version 0.5 or later to take effect.\n"
},
"ttl": { "ttl": {
"anyOf": [ "anyOf": [
{ {
@@ -497,38 +486,6 @@
}, },
"required": [] "required": []
}, },
"SerdeConfig": {
"title": "SerdeConfig",
"description": "Configuration for the built-in serde, which handles checkpointing of state.\n\nIf omitted, no serde is set up (the object store will still be present, however).",
"type": "object",
"properties": {
"allowed_json_modules": {
"anyOf": [
{
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
}
},
{
"type": "boolean"
},
{
"type": "null"
}
],
"description": "Optional. List of allowed python modules to de-serialize custom objects from.\n\nIf provided, only the specified modules will be allowed to be deserialized.\nIf omitted, no modules are allowed, and the object returned will simply be a json object OR\na deserialized langchain object.\n"
},
"pickle_fallback": {
"type": "boolean",
"description": "Optional. Whether to allow pickling as a fallback for deserialization.\n\nIf True, pickling will be allowed as a fallback for deserialization.\nIf False, pickling will not be allowed as a fallback for deserialization.\nDefaults to True if not configured."
}
},
"required": []
},
"ThreadTTLConfig": { "ThreadTTLConfig": {
"title": "ThreadTTLConfig", "title": "ThreadTTLConfig",
"description": "Configure a default TTL for checkpointed data within threads.", "description": "Configure a default TTL for checkpointed data within threads.",
@@ -598,11 +555,11 @@
}, },
"disable_assistants": { "disable_assistants": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, /assistants routes are removed from the server.\n\nDefault is False (meaning /assistants is enabled).\n" "description": "Optional. If True, /assistants routes are removed from the server.\n\nDefault is False (meaning /assistants is enabled).\n"
}, },
"disable_mcp": { "disable_mcp": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, /mcp routes are removed, disabling the MCP server.\n\nDefault is False.\n" "description": "Optional. If True, /mcp routes are removed, disabling the MCP server.\n\nDefault is False.\n"
}, },
"disable_meta": { "disable_meta": {
"type": "boolean", "type": "boolean",
@@ -610,19 +567,19 @@
}, },
"disable_runs": { "disable_runs": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, /runs routes are removed.\n\nDefault is False.\n" "description": "Optional. If True, /runs routes are removed.\n\nDefault is False.\n"
}, },
"disable_store": { "disable_store": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, /store routes are removed, disabling direct store interactions via HTTP.\n\nDefault is False.\n" "description": "Optional. If True, /store routes are removed, disabling direct store interactions via HTTP.\n\nDefault is False.\n"
}, },
"disable_threads": { "disable_threads": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, /threads routes are removed.\n\nDefault is False.\n" "description": "Optional. If True, /threads routes are removed.\n\nDefault is False.\n"
}, },
"enable_custom_route_auth": { "enable_custom_route_auth": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, authentication is enabled for custom routes,\nnot just the routes that are protected by default.\n(Routes protected by default include /assistants, /threads, and /runs).\n\nDefault is False. This flag only affects authentication behavior\nif `app` is provided and contains custom routes.\n" "description": "Optional. If True, authentication is enabled for custom routes,\nnot just the routes that are protected by default.\n(Routes protected by default include /assistants, /threads, and /runs).\n\nDefault is False. This flag only affects authentication behavior\nif `app` is provided and contains custom routes.\n"
}, },
"logging_headers": { "logging_headers": {
"anyOf": [ "anyOf": [
@@ -698,7 +655,7 @@
"properties": { "properties": {
"allow_credentials": { "allow_credentials": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, cross-origin requests can include credentials (cookies, auth headers).\n\nDefault False to avoid accidentally exposing secured endpoints to untrusted sites.\n" "description": "Optional. If True, cross-origin requests can include credentials (cookies, auth headers).\n\nDefault False to avoid accidentally exposing secured endpoints to untrusted sites.\n"
}, },
"allow_headers": { "allow_headers": {
"type": "array", "type": "array",
@@ -817,7 +774,7 @@
}, },
"refresh_on_read": { "refresh_on_read": {
"type": "boolean", "type": "boolean",
"description": "Default behavior for refreshing TTLs on read operations (`GET` and `SEARCH`).\n\nIf `True`, TTLs will be refreshed on read operations (get/search) by default.\nThis can be overridden per-operation by explicitly setting `refresh_ttl`.\nDefaults to `True` if not configured.\n" "description": "Default behavior for refreshing TTLs on read operations (GET and SEARCH).\n\nIf True, TTLs will be refreshed on read operations (get/search) by default.\nThis can be overridden per-operation by explicitly setting refresh_ttl.\nDefaults to True if not configured.\n"
}, },
"sweep_interval_minutes": { "sweep_interval_minutes": {
"anyOf": [ "anyOf": [
+13 -56
View File
@@ -407,11 +407,11 @@
"properties": { "properties": {
"disable_studio_auth": { "disable_studio_auth": {
"type": "boolean", "type": "boolean",
"description": "Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio.\n\nDefaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header\nvalue is a valid API key for the deployment's workspace. If `True`, all requests will go through your custom\nauthentication logic, regardless of origin of the request.\n" "description": "Optional. Whether to disable LangSmith API-key authentication for requests originating the Studio.\n\nDefaults to False, meaning that if a particular header is set, the server will verify the `x-api-key` header\nvalue is a valid API key for the deployment's workspace. If True, all requests will go through your custom\nauthentication logic, regardless of origin of the request.\n"
}, },
"openapi": { "openapi": {
"$ref": "#/$defs/SecurityConfig", "$ref": "#/$defs/SecurityConfig",
"description": "The security configuration to include in your server's OpenAPI spec.\n\n{\n}\n}\n}\n},\n]\n}\n" "description": "Required. Detailed security configuration that merges into your deployment's OpenAPI spec.\n\n{\n}\n}\n}\n},\n]\n}\n"
}, },
"path": { "path": {
"type": "string", "type": "string",
@@ -442,7 +442,7 @@
} }
} }
}, },
"description": "Path-specific security overrides.\n\n- Keys that are HTTP methods (e.g., \"GET\", \"POST\"),\n- Values are lists of security definitions (just like `security`) for that method.\n" "description": "Optional. Path-specific security overrides.\n\n- Keys that are HTTP methods (e.g., \"GET\", \"POST\"),\n- Values are lists of security definitions (just like `security`) for that method.\n"
}, },
"security": { "security": {
"type": "array", "type": "array",
@@ -455,14 +455,14 @@
} }
} }
}, },
"description": "Global security requirements across all endpoints.\n\nEach element in the list maps a security scheme (e.g. \"OAuth2\") to a list of scopes (e.g. [\"read\", \"write\"])." "description": "Optional. Global security requirements across all endpoints.\n\nEach element in the list maps a security scheme (e.g. \"OAuth2\") to a list of scopes (e.g. [\"read\", \"write\"])."
}, },
"securitySchemes": { "securitySchemes": {
"type": "object", "type": "object",
"additionalProperties": { "additionalProperties": {
"type": "object" "type": "object"
}, },
"description": "Describe each security scheme recognized by your OpenAPI spec.\n\nKeys are scheme names (e.g. \"OAuth2\", \"ApiKeyAuth\") and values are their definitions." "description": "Required. Dict describing each security scheme recognized by your OpenAPI spec.\n\nKeys are scheme names (e.g. \"OAuth2\", \"ApiKeyAuth\") and values are their definitions."
} }
}, },
"required": [] "required": []
@@ -472,17 +472,6 @@
"description": "Configuration for the built-in checkpointer, which handles checkpointing of state.\n\nIf omitted, no checkpointer is set up (the object store will still be present, however).", "description": "Configuration for the built-in checkpointer, which handles checkpointing of state.\n\nIf omitted, no checkpointer is set up (the object store will still be present, however).",
"type": "object", "type": "object",
"properties": { "properties": {
"serde": {
"anyOf": [
{
"$ref": "#/$defs/SerdeConfig"
},
{
"type": "null"
}
],
"description": "Optional. Defines the serde configuration.\n\nIf provided, the checkpointer will apply serde settings according to the configuration.\nIf omitted, no serde behavior is configured.\n\nThis configuration requires server version 0.5 or later to take effect.\n"
},
"ttl": { "ttl": {
"anyOf": [ "anyOf": [
{ {
@@ -497,38 +486,6 @@
}, },
"required": [] "required": []
}, },
"SerdeConfig": {
"title": "SerdeConfig",
"description": "Configuration for the built-in serde, which handles checkpointing of state.\n\nIf omitted, no serde is set up (the object store will still be present, however).",
"type": "object",
"properties": {
"allowed_json_modules": {
"anyOf": [
{
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
}
},
{
"type": "boolean"
},
{
"type": "null"
}
],
"description": "Optional. List of allowed python modules to de-serialize custom objects from.\n\nIf provided, only the specified modules will be allowed to be deserialized.\nIf omitted, no modules are allowed, and the object returned will simply be a json object OR\na deserialized langchain object.\n"
},
"pickle_fallback": {
"type": "boolean",
"description": "Optional. Whether to allow pickling as a fallback for deserialization.\n\nIf True, pickling will be allowed as a fallback for deserialization.\nIf False, pickling will not be allowed as a fallback for deserialization.\nDefaults to True if not configured."
}
},
"required": []
},
"ThreadTTLConfig": { "ThreadTTLConfig": {
"title": "ThreadTTLConfig", "title": "ThreadTTLConfig",
"description": "Configure a default TTL for checkpointed data within threads.", "description": "Configure a default TTL for checkpointed data within threads.",
@@ -598,11 +555,11 @@
}, },
"disable_assistants": { "disable_assistants": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, /assistants routes are removed from the server.\n\nDefault is False (meaning /assistants is enabled).\n" "description": "Optional. If True, /assistants routes are removed from the server.\n\nDefault is False (meaning /assistants is enabled).\n"
}, },
"disable_mcp": { "disable_mcp": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, /mcp routes are removed, disabling the MCP server.\n\nDefault is False.\n" "description": "Optional. If True, /mcp routes are removed, disabling the MCP server.\n\nDefault is False.\n"
}, },
"disable_meta": { "disable_meta": {
"type": "boolean", "type": "boolean",
@@ -610,19 +567,19 @@
}, },
"disable_runs": { "disable_runs": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, /runs routes are removed.\n\nDefault is False.\n" "description": "Optional. If True, /runs routes are removed.\n\nDefault is False.\n"
}, },
"disable_store": { "disable_store": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, /store routes are removed, disabling direct store interactions via HTTP.\n\nDefault is False.\n" "description": "Optional. If True, /store routes are removed, disabling direct store interactions via HTTP.\n\nDefault is False.\n"
}, },
"disable_threads": { "disable_threads": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, /threads routes are removed.\n\nDefault is False.\n" "description": "Optional. If True, /threads routes are removed.\n\nDefault is False.\n"
}, },
"enable_custom_route_auth": { "enable_custom_route_auth": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, authentication is enabled for custom routes,\nnot just the routes that are protected by default.\n(Routes protected by default include /assistants, /threads, and /runs).\n\nDefault is False. This flag only affects authentication behavior\nif `app` is provided and contains custom routes.\n" "description": "Optional. If True, authentication is enabled for custom routes,\nnot just the routes that are protected by default.\n(Routes protected by default include /assistants, /threads, and /runs).\n\nDefault is False. This flag only affects authentication behavior\nif `app` is provided and contains custom routes.\n"
}, },
"logging_headers": { "logging_headers": {
"anyOf": [ "anyOf": [
@@ -698,7 +655,7 @@
"properties": { "properties": {
"allow_credentials": { "allow_credentials": {
"type": "boolean", "type": "boolean",
"description": "Optional. If `True`, cross-origin requests can include credentials (cookies, auth headers).\n\nDefault False to avoid accidentally exposing secured endpoints to untrusted sites.\n" "description": "Optional. If True, cross-origin requests can include credentials (cookies, auth headers).\n\nDefault False to avoid accidentally exposing secured endpoints to untrusted sites.\n"
}, },
"allow_headers": { "allow_headers": {
"type": "array", "type": "array",
@@ -817,7 +774,7 @@
}, },
"refresh_on_read": { "refresh_on_read": {
"type": "boolean", "type": "boolean",
"description": "Default behavior for refreshing TTLs on read operations (`GET` and `SEARCH`).\n\nIf `True`, TTLs will be refreshed on read operations (get/search) by default.\nThis can be overridden per-operation by explicitly setting `refresh_ttl`.\nDefaults to `True` if not configured.\n" "description": "Default behavior for refreshing TTLs on read operations (GET and SEARCH).\n\nIf True, TTLs will be refreshed on read operations (get/search) by default.\nThis can be overridden per-operation by explicitly setting refresh_ttl.\nDefaults to True if not configured.\n"
}, },
"sweep_interval_minutes": { "sweep_interval_minutes": {
"anyOf": [ "anyOf": [
+1 -2
View File
@@ -141,7 +141,6 @@ services:
additional_contexts: additional_contexts:
- cli_1: {str(pathlib.Path(__file__).parent.parent.parent.parent.absolute())} - cli_1: {str(pathlib.Path(__file__).parent.parent.parent.parent.absolute())}
dockerfile_inline: | dockerfile_inline: |
# syntax=docker/dockerfile:1.4
FROM langchain/langgraph-api:3.11 FROM langchain/langgraph-api:3.11
# -- Adding local package . -- # -- Adding local package . --
ADD . /deps/cli ADD . /deps/cli
@@ -150,7 +149,7 @@ services:
COPY --from=cli_1 . /deps/cli_1 COPY --from=cli_1 . /deps/cli_1
# -- End of local package ../../.. -- # -- End of local package ../../.. --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{{"agent": "agent.py:graph"}}' ENV LANGSERVE_GRAPHS='{{"agent": "agent.py:graph"}}'
{textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")} {textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")}
+14 -16
View File
@@ -419,7 +419,6 @@ def test_config_to_docker_simple():
"langchain/langgraph-api", "langchain/langgraph-api",
) )
expected_docker_stdin = f"""\ expected_docker_stdin = f"""\
# syntax=docker/dockerfile:1.4
FROM langchain/langgraph-api:3.11 FROM langchain/langgraph-api:3.11
# -- Installing local requirements -- # -- Installing local requirements --
COPY --from=outer-requirements.txt requirements.txt /deps/outer-graphs_reqs_a/graphs_reqs_a/requirements.txt COPY --from=outer-requirements.txt requirements.txt /deps/outer-graphs_reqs_a/graphs_reqs_a/requirements.txt
@@ -457,7 +456,7 @@ RUN set -ex && \\
done done
# -- End of non-package dependency graphs_reqs_a -- # -- End of non-package dependency graphs_reqs_a --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGGRAPH_HTTP='{{"app": "/deps/examples/my_app.py:app"}}' ENV LANGGRAPH_HTTP='{{"app": "/deps/examples/my_app.py:app"}}'
ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}' ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}'
@@ -483,7 +482,6 @@ def test_config_to_docker_outside_path():
) )
expected_docker_stdin = ( expected_docker_stdin = (
"""\ """\
# syntax=docker/dockerfile:1.4
FROM langchain/langgraph-api:3.11 FROM langchain/langgraph-api:3.11
# -- Adding non-package dependency unit_tests -- # -- Adding non-package dependency unit_tests --
ADD . /deps/outer-unit_tests/unit_tests ADD . /deps/outer-unit_tests/unit_tests
@@ -514,7 +512,7 @@ RUN set -ex && \\
done done
# -- End of non-package dependency tests -- # -- End of non-package dependency tests --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}' ENV LANGSERVE_GRAPHS='{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}'
""" """
@@ -561,7 +559,7 @@ RUN set -ex && \\
done done
# -- End of non-package dependency unit_tests -- # -- End of non-package dependency unit_tests --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PIP_CONFIG_FILE=/pipconfig.txt PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PIP_CONFIG_FILE=/pipconfig.txt PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}' ENV LANGSERVE_GRAPHS='{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}'
""" """
@@ -623,7 +621,7 @@ RUN set -ex && \\
done done
# -- End of non-package dependency graphs -- # -- End of non-package dependency graphs --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-graphs/src/agent.py:graph"}}' ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-graphs/src/agent.py:graph"}}'
{FORMATTED_CLEANUP_LINES}\ {FORMATTED_CLEANUP_LINES}\
@@ -659,7 +657,7 @@ dependencies = ["langchain"]"""
ADD . /deps/unit_tests ADD . /deps/unit_tests
# -- End of local package . -- # -- End of local package . --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{"agent": "/deps/unit_tests/graphs/agent.py:graph"}' ENV LANGSERVE_GRAPHS='{"agent": "/deps/unit_tests/graphs/agent.py:graph"}'
""" """
@@ -707,7 +705,7 @@ RUN set -ex && \\
done done
# -- End of non-package dependency graphs -- # -- End of non-package dependency graphs --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PIP_CONFIG_FILE=/pipconfig.txt PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PIP_CONFIG_FILE=/pipconfig.txt PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-graphs/src/agent.py:graph"}}' ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-graphs/src/agent.py:graph"}}'
{FORMATTED_CLEANUP_LINES}""" {FORMATTED_CLEANUP_LINES}"""
@@ -715,7 +713,7 @@ ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-graphs/src/agent.py:graph"}}'
assert additional_contexts == {} assert additional_contexts == {}
# node.js build used for LangSmith Deployment # node.js build used for LangGraph Platform
def test_config_to_docker_nodejs(): def test_config_to_docker_nodejs():
graphs = {"agent": "./graphs/agent.js:graph"} graphs = {"agent": "./graphs/agent.js:graph"}
actual_docker_stdin, additional_contexts = config_to_docker( actual_docker_stdin, additional_contexts = config_to_docker(
@@ -813,7 +811,7 @@ RUN set -ex && \\
done done
# -- End of non-package dependency unit_tests -- # -- End of non-package dependency unit_tests --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGGRAPH_UI='{{"agent": "./graphs/agent.ui.jsx"}}' ENV LANGGRAPH_UI='{{"agent": "./graphs/agent.ui.jsx"}}'
ENV LANGGRAPH_UI_CONFIG='{{"shared": ["nuqs"]}}' ENV LANGGRAPH_UI_CONFIG='{{"shared": ["nuqs"]}}'
@@ -859,7 +857,7 @@ RUN set -ex && \\
done done
# -- End of non-package dependency unit_tests -- # -- End of non-package dependency unit_tests --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{{"python": "/deps/outer-unit_tests/unit_tests/multiplatform/python.py:graph", "js": "/deps/outer-unit_tests/unit_tests/multiplatform/js.mts:graph"}}' ENV LANGSERVE_GRAPHS='{{"python": "/deps/outer-unit_tests/unit_tests/multiplatform/python.py:graph", "js": "/deps/outer-unit_tests/unit_tests/multiplatform/js.mts:graph"}}'
# -- Installing JS dependencies -- # -- Installing JS dependencies --
@@ -1000,7 +998,7 @@ def test_config_to_compose_simple_config():
done done
# -- End of non-package dependency unit_tests -- # -- End of non-package dependency unit_tests --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}' ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}'
{textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")} {textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")}
@@ -1041,7 +1039,7 @@ def test_config_to_compose_env_vars():
done done
# -- End of non-package dependency unit_tests -- # -- End of non-package dependency unit_tests --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}' ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}'
{textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")} {textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")}
@@ -1086,7 +1084,7 @@ def test_config_to_compose_env_file():
done done
# -- End of non-package dependency unit_tests -- # -- End of non-package dependency unit_tests --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}' ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}'
{textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")} {textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")}
@@ -1124,7 +1122,7 @@ def test_config_to_compose_watch():
done done
# -- End of non-package dependency unit_tests -- # -- End of non-package dependency unit_tests --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}' ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}'
{textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")} {textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")}
@@ -1171,7 +1169,7 @@ def test_config_to_compose_end_to_end():
done done
# -- End of non-package dependency unit_tests -- # -- End of non-package dependency unit_tests --
# -- Installing all local dependencies -- # -- Installing all local dependencies --
RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); fi; done RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
# -- End of local dependencies install -- # -- End of local dependencies install --
ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}' ENV LANGSERVE_GRAPHS='{{"agent": "/deps/outer-unit_tests/unit_tests/agent.py:graph"}}'
{textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")} {textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")}
+764 -841
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,14 @@
{
"permissions": {
"allow": [
"Bash(rg:*)",
"Bash(python:*)",
"Bash(grep:*)",
"Bash(sed:*)",
"Bash(awk:*)",
"Bash(uv run mypy:*)",
"Bash(uv run:*)"
],
"deny": []
}
}
+1 -1
View File
@@ -76,7 +76,7 @@ test:
test_parallel: test_parallel:
make start-services &&\ make start-services &&\
make start-dev-server &&\ make start-dev-server &&\
uv run pytest -n auto --dist worksteal $(TEST) -vv --lf; \ uv run pytest -n auto --dist worksteal $(TEST) --lf --snapshot-update; \
EXIT_CODE=$$?; \ EXIT_CODE=$$?; \
make stop-services; \ make stop-services; \
make stop-dev-server; \ make stop-dev-server; \
+2 -2
View File
@@ -63,8 +63,8 @@ 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: 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](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/). - [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://docs.langchain.com/oss/python/langchain/overview) Provides integrations and composable components to streamline LLM application development. - [LangChain](https://python.langchain.com/docs/introduction/) Provides integrations and composable components to streamline LLM application development.
> [!NOTE] > [!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/). > 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/).
+8 -8
View File
@@ -2,7 +2,7 @@ import operator
from collections.abc import Sequence from collections.abc import Sequence
from functools import partial from functools import partial
from random import choice from random import choice
from typing import Annotated from typing import Annotated, Optional
from pydantic import BaseModel, Field, field_validator from pydantic import BaseModel, Field, field_validator
@@ -55,7 +55,7 @@ def pydantic_state(n: int) -> StateGraph:
raise TypeError("primary_issue_medium must be a string") raise TypeError("primary_issue_medium must be a string")
return v return v
autoresponse: Annotated[dict | None, lambda _, y: y] = Field( autoresponse: Annotated[Optional[dict], lambda _, y: y] = Field(
default=None default=None
) # Always overwrite ) # Always overwrite
@@ -75,7 +75,7 @@ def pydantic_state(n: int) -> StateGraph:
raise TypeError("issue must be a dict or None") raise TypeError("issue must be a dict or None")
return v return v
relevant_rules: list[dict] | None = Field(default=None) relevant_rules: Optional[list[dict]] = Field(default=None)
"""SOPs fetched from the rulebook that are relevant to the current conversation.""" """SOPs fetched from the rulebook that are relevant to the current conversation."""
@field_validator("relevant_rules", mode="after") @field_validator("relevant_rules", mode="after")
@@ -94,7 +94,7 @@ def pydantic_state(n: int) -> StateGraph:
) )
return v return v
memory_docs: list[dict] | None = Field(default=None) memory_docs: Optional[list[dict]] = Field(default=None)
"""Memory docs fetched from the memory service that are relevant to the current conversation.""" """Memory docs fetched from the memory service that are relevant to the current conversation."""
@field_validator("memory_docs", mode="after") @field_validator("memory_docs", mode="after")
@@ -145,7 +145,7 @@ def pydantic_state(n: int) -> StateGraph:
raise TypeError("responses must be a list of dicts with str keys") raise TypeError("responses must be a list of dicts with str keys")
return v return v
user_info: Annotated[dict | None, lambda x, y: y if y is not None else x] = ( user_info: Annotated[Optional[dict], lambda x, y: y if y is not None else x] = (
Field(default=None) Field(default=None)
) )
"""The current user state (by email).""" """The current user state (by email)."""
@@ -157,7 +157,7 @@ def pydantic_state(n: int) -> StateGraph:
raise TypeError("user_info must be a dict or None") raise TypeError("user_info must be a dict or None")
return v return v
crm_info: Annotated[dict | None, lambda x, y: y if y is not None else x] = ( crm_info: Annotated[Optional[dict], lambda x, y: y if y is not None else x] = (
Field(default=None) Field(default=None)
) )
"""The CRM information for organization the current user is from.""" """The CRM information for organization the current user is from."""
@@ -170,7 +170,7 @@ def pydantic_state(n: int) -> StateGraph:
return v return v
email_thread_id: Annotated[ email_thread_id: Annotated[
str | None, lambda x, y: y if y is not None else x Optional[str], lambda x, y: y if y is not None else x
] = Field(default=None) ] = Field(default=None)
"""The current email thread ID.""" """The current email thread ID."""
@@ -194,7 +194,7 @@ def pydantic_state(n: int) -> StateGraph:
raise TypeError("slack_participants must be a dict with str keys") raise TypeError("slack_participants must be a dict with str keys")
return v return v
bot_id: str | None = Field(default=None) bot_id: Optional[str] = Field(default=None)
"""The ID of the bot user in the slack channel.""" """The ID of the bot user in the slack channel."""
@field_validator("bot_id", mode="after") @field_validator("bot_id", mode="after")
+4 -4
View File
@@ -1,4 +1,4 @@
from typing import Any from typing import Any, Optional
from uuid import uuid4 from uuid import uuid4
from langchain_core.callbacks import CallbackManagerForLLMRun from langchain_core.callbacks import CallbackManagerForLLMRun
@@ -14,7 +14,7 @@ from langgraph.prebuilt.chat_agent_executor import create_react_agent
from langgraph.pregel import Pregel from langgraph.pregel import Pregel
def react_agent(n_tools: int, checkpointer: BaseCheckpointSaver | None) -> Pregel: def react_agent(n_tools: int, checkpointer: Optional[BaseCheckpointSaver]) -> Pregel:
class FakeFunctionChatModel(FakeMessagesListChatModel): class FakeFunctionChatModel(FakeMessagesListChatModel):
def bind_tools(self, functions: list): def bind_tools(self, functions: list):
return self return self
@@ -22,8 +22,8 @@ def react_agent(n_tools: int, checkpointer: BaseCheckpointSaver | None) -> Prege
def _generate( def _generate(
self, self,
messages: list[BaseMessage], messages: list[BaseMessage],
stop: list[str] | None = None, stop: Optional[list[str]] = None,
run_manager: CallbackManagerForLLMRun | None = None, run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any, **kwargs: Any,
) -> ChatResult: ) -> ChatResult:
response = self.responses[self.i].copy() response = self.responses[self.i].copy()
+10 -8
View File
@@ -2,7 +2,7 @@ import operator
from collections.abc import Sequence from collections.abc import Sequence
from functools import partial from functools import partial
from random import choice from random import choice
from typing import Annotated from typing import Annotated, Optional
from typing_extensions import TypedDict from typing_extensions import TypedDict
@@ -16,26 +16,28 @@ def wide_dict(n: int) -> StateGraph:
trigger_events: Annotated[list, operator.add] trigger_events: Annotated[list, operator.add]
"""The external events that are converted by the graph.""" """The external events that are converted by the graph."""
primary_issue_medium: Annotated[str, lambda x, y: y or x] primary_issue_medium: Annotated[str, lambda x, y: y or x]
autoresponse: Annotated[dict | None, lambda _, y: y] # Always overwrite autoresponse: Annotated[Optional[dict], lambda _, y: y] # Always overwrite
issue: Annotated[dict | None, lambda x, y: y if y else x] issue: Annotated[dict | None, lambda x, y: y if y else x]
relevant_rules: list[dict] | None relevant_rules: Optional[list[dict]]
"""SOPs fetched from the rulebook that are relevant to the current conversation.""" """SOPs fetched from the rulebook that are relevant to the current conversation."""
memory_docs: list[dict] | None memory_docs: Optional[list[dict]]
"""Memory docs fetched from the memory service that are relevant to the current conversation.""" """Memory docs fetched from the memory service that are relevant to the current conversation."""
categorizations: Annotated[list[dict], operator.add] categorizations: Annotated[list[dict], operator.add]
"""The issue categorizations auto-generated by the AI.""" """The issue categorizations auto-generated by the AI."""
responses: Annotated[list[dict], operator.add] responses: Annotated[list[dict], operator.add]
"""The draft responses recommended by the AI.""" """The draft responses recommended by the AI."""
user_info: Annotated[dict | None, lambda x, y: y if y is not None else x] user_info: Annotated[Optional[dict], lambda x, y: y if y is not None else x]
"""The current user state (by email).""" """The current user state (by email)."""
crm_info: Annotated[dict | None, lambda x, y: y if y is not None else x] crm_info: Annotated[Optional[dict], lambda x, y: y if y is not None else x]
"""The CRM information for organization the current user is from.""" """The CRM information for organization the current user is from."""
email_thread_id: Annotated[str | None, lambda x, y: y if y is not None else x] email_thread_id: Annotated[
Optional[str], lambda x, y: y if y is not None else x
]
"""The current email thread ID.""" """The current email thread ID."""
slack_participants: Annotated[dict, operator.or_] slack_participants: Annotated[dict, operator.or_]
"""The growing list of current slack participants.""" """The growing list of current slack participants."""
bot_id: str | None bot_id: Optional[str]
"""The ID of the bot user in the slack channel.""" """The ID of the bot user in the slack channel."""
notified_assignees: Annotated[dict, operator.or_] notified_assignees: Annotated[dict, operator.or_]
+8 -8
View File
@@ -3,7 +3,7 @@ from collections.abc import Sequence
from dataclasses import dataclass, field from dataclasses import dataclass, field
from functools import partial from functools import partial
from random import choice from random import choice
from typing import Annotated from typing import Annotated, Optional
from langgraph.constants import END, START from langgraph.constants import END, START
from langgraph.graph.state import StateGraph from langgraph.graph.state import StateGraph
@@ -18,13 +18,13 @@ def wide_state(n: int) -> StateGraph:
primary_issue_medium: Annotated[str, lambda x, y: y or x] = field( primary_issue_medium: Annotated[str, lambda x, y: y or x] = field(
default="email" default="email"
) )
autoresponse: Annotated[dict | None, lambda _, y: y] = field( autoresponse: Annotated[Optional[dict], lambda _, y: y] = field(
default=None default=None
) # Always overwrite ) # Always overwrite
issue: Annotated[dict | None, lambda x, y: y if y else x] = field(default=None) issue: Annotated[dict | None, lambda x, y: y if y else x] = field(default=None)
relevant_rules: list[dict] | None = field(default=None) relevant_rules: Optional[list[dict]] = field(default=None)
"""SOPs fetched from the rulebook that are relevant to the current conversation.""" """SOPs fetched from the rulebook that are relevant to the current conversation."""
memory_docs: list[dict] | None = field(default=None) memory_docs: Optional[list[dict]] = field(default=None)
"""Memory docs fetched from the memory service that are relevant to the current conversation.""" """Memory docs fetched from the memory service that are relevant to the current conversation."""
categorizations: Annotated[list[dict], operator.add] = field( categorizations: Annotated[list[dict], operator.add] = field(
default_factory=list default_factory=list
@@ -33,21 +33,21 @@ def wide_state(n: int) -> StateGraph:
responses: Annotated[list[dict], operator.add] = field(default_factory=list) responses: Annotated[list[dict], operator.add] = field(default_factory=list)
"""The draft responses recommended by the AI.""" """The draft responses recommended by the AI."""
user_info: Annotated[dict | None, lambda x, y: y if y is not None else x] = ( user_info: Annotated[Optional[dict], lambda x, y: y if y is not None else x] = (
field(default=None) field(default=None)
) )
"""The current user state (by email).""" """The current user state (by email)."""
crm_info: Annotated[dict | None, lambda x, y: y if y is not None else x] = ( crm_info: Annotated[Optional[dict], lambda x, y: y if y is not None else x] = (
field(default=None) field(default=None)
) )
"""The CRM information for organization the current user is from.""" """The CRM information for organization the current user is from."""
email_thread_id: Annotated[ email_thread_id: Annotated[
str | None, lambda x, y: y if y is not None else x Optional[str], lambda x, y: y if y is not None else x
] = field(default=None) ] = field(default=None)
"""The current email thread ID.""" """The current email thread ID."""
slack_participants: Annotated[dict, operator.or_] = field(default_factory=dict) slack_participants: Annotated[dict, operator.or_] = field(default_factory=dict)
"""The growing list of current slack participants.""" """The growing list of current slack participants."""
bot_id: str | None = field(default=None) bot_id: Optional[str] = field(default=None)
"""The ID of the bot user in the slack channel.""" """The ID of the bot user in the slack channel."""
notified_assignees: Annotated[dict, operator.or_] = field(default_factory=dict) notified_assignees: Annotated[dict, operator.or_] = field(default_factory=dict)
+12 -19
View File
@@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
from collections import ChainMap from collections import ChainMap
from collections.abc import Mapping, Sequence from collections.abc import Sequence
from os import getenv from os import getenv
from typing import Any, cast from typing import Any, cast
@@ -162,10 +162,14 @@ def patch_config(
Args: Args:
config: The config to patch. config: The config to patch.
callbacks: The callbacks to set. callbacks: The callbacks to set.
Defaults to None.
recursion_limit: The recursion limit to set. recursion_limit: The recursion limit to set.
Defaults to None.
max_concurrency: The max number of concurrent steps to run, which also applies to parallelized steps. max_concurrency: The max number of concurrent steps to run, which also applies to parallelized steps.
run_name: The run name to set. Defaults to None.
run_name: The run name to set. Defaults to None.
configurable: The configurable to set. configurable: The configurable to set.
Defaults to None.
Returns: Returns:
RunnableConfig: The patched config. RunnableConfig: The patched config.
@@ -308,22 +312,11 @@ def ensure_config(*configs: RunnableConfig | None) -> RunnableConfig:
for k, v in config.items(): for k, v in config.items():
if _is_not_empty(v) and k not in CONFIG_KEYS: if _is_not_empty(v) and k not in CONFIG_KEYS:
empty[CONF][k] = v empty[CONF][k] = v
_empty_metadata = empty["metadata"]
for key, value in empty[CONF].items(): for key, value in empty[CONF].items():
if _exclude_as_metadata(key, value, _empty_metadata): if (
continue not key.startswith("__")
_empty_metadata[key] = value and isinstance(value, (str, int, float, bool))
and key not in empty["metadata"]
):
empty["metadata"][key] = value
return empty return empty
_OMIT = ("key", "token", "secret", "password", "auth")
def _exclude_as_metadata(key: str, value: Any, metadata: Mapping[str, Any]) -> bool:
key_lower = key.casefold()
return (
key.startswith("__")
or not isinstance(value, (str, int, float, bool))
or key in metadata
or any(substr in key_lower for substr in _OMIT)
)
@@ -77,8 +77,6 @@ CONF = cast(Literal["configurable"], sys.intern("configurable"))
# key for the configurable dict in RunnableConfig # key for the configurable dict in RunnableConfig
NULL_TASK_ID = sys.intern("00000000-0000-0000-0000-000000000000") NULL_TASK_ID = sys.intern("00000000-0000-0000-0000-000000000000")
# the task_id to use for writes that are not associated with a task # the task_id to use for writes that are not associated with a task
OVERWRITE = sys.intern("__overwrite__")
# dict key for the overwrite value, used as `{'__overwrite__': value}`
# redefined to avoid circular import with langgraph.constants # redefined to avoid circular import with langgraph.constants
_TAG_HIDDEN = sys.intern("langsmith:hidden") _TAG_HIDDEN = sys.intern("langsmith:hidden")
+2 -12
View File
@@ -4,10 +4,10 @@ import dataclasses
import types import types
import weakref import weakref
from collections.abc import Generator, Sequence from collections.abc import Generator, Sequence
from typing import Annotated, Any, Optional, Union, get_origin, get_type_hints from typing import Annotated, Any, Optional, Union, get_type_hints
from pydantic import BaseModel from pydantic import BaseModel
from typing_extensions import NotRequired, ReadOnly, Required from typing_extensions import NotRequired, ReadOnly, Required, get_origin
from langgraph._internal._typing import MISSING from langgraph._internal._typing import MISSING
@@ -15,12 +15,6 @@ from langgraph._internal._typing import MISSING
def _is_optional_type(type_: Any) -> bool: def _is_optional_type(type_: Any) -> bool:
"""Check if a type is Optional.""" """Check if a type is Optional."""
# Handle new union syntax (PEP 604): str | None
if isinstance(type_, types.UnionType):
return any(
arg is type(None) or _is_optional_type(arg) for arg in type_.__args__
)
if hasattr(type_, "__origin__") and hasattr(type_, "__args__"): if hasattr(type_, "__origin__") and hasattr(type_, "__args__"):
origin = get_origin(type_) origin = get_origin(type_)
if origin is Optional: if origin is Optional:
@@ -201,10 +195,6 @@ def get_cached_annotated_keys(obj: type[Any]) -> tuple[str, ...]:
keys: list[str] = [] keys: list[str] = []
for base in reversed(obj.__mro__): for base in reversed(obj.__mro__):
ann = base.__dict__.get("__annotations__") ann = base.__dict__.get("__annotations__")
# In Python 3.14+, Pydantic models use descriptors for __annotations__
# so we need to fall back to getattr if __dict__.get returns None
if ann is None:
ann = getattr(base, "__annotations__", None)
if ann is None or isinstance(ann, types.GetSetDescriptorType): if ann is None or isinstance(ann, types.GetSetDescriptorType):
continue continue
keys.extend(ann.keys()) keys.extend(ann.keys())
@@ -7,10 +7,10 @@ import inspect
import sys import sys
import types import types
from collections.abc import Awaitable, Coroutine, Generator from collections.abc import Awaitable, Coroutine, Generator
from typing import TypeVar, cast from typing import TypeVar, Union, cast
T = TypeVar("T") T = TypeVar("T")
AnyFuture = asyncio.Future | concurrent.futures.Future AnyFuture = Union[asyncio.Future, concurrent.futures.Future]
CONTEXT_NOT_SUPPORTED = sys.version_info < (3, 11) CONTEXT_NOT_SUPPORTED = sys.version_info < (3, 11)
EAGER_NOT_SUPPORTED = sys.version_info < (3, 12) EAGER_NOT_SUPPORTED = sys.version_info < (3, 12)
+7 -1
View File
@@ -3,11 +3,14 @@ from __future__ import annotations
import asyncio import asyncio
import queue import queue
import sys
import threading import threading
import types import types
from collections import deque from collections import deque
from time import monotonic from time import monotonic
PY_310 = sys.version_info >= (3, 10)
class AsyncQueue(asyncio.Queue): class AsyncQueue(asyncio.Queue):
"""Async unbounded FIFO queue with a wait() method. """Async unbounded FIFO queue with a wait() method.
@@ -21,7 +24,10 @@ class AsyncQueue(asyncio.Queue):
ie. this doesn't consume the item, just waits for it. ie. this doesn't consume the item, just waits for it.
""" """
while self.empty(): while self.empty():
getter = self._get_loop().create_future() if PY_310:
getter = self._get_loop().create_future()
else:
getter = self._loop.create_future()
self._getters.append(getter) self._getters.append(getter)
try: try:
await getter await getter
+19 -18
View File
@@ -8,7 +8,6 @@ import warnings
from collections.abc import ( from collections.abc import (
AsyncIterator, AsyncIterator,
Awaitable, Awaitable,
Callable,
Coroutine, Coroutine,
Generator, Generator,
Iterator, Iterator,
@@ -19,9 +18,10 @@ from contextvars import Context, Token, copy_context
from functools import partial, wraps from functools import partial, wraps
from typing import ( from typing import (
Any, Any,
Callable,
Optional, Optional,
Protocol, Protocol,
TypeGuard, Union,
cast, cast,
) )
@@ -42,6 +42,7 @@ from langchain_core.runnables.config import (
from langchain_core.runnables.utils import Input, Output from langchain_core.runnables.utils import Input, Output
from langchain_core.tracers.langchain import LangChainTracer from langchain_core.tracers.langchain import LangChainTracer
from langgraph.store.base import BaseStore from langgraph.store.base import BaseStore
from typing_extensions import TypeGuard
from langgraph._internal._config import ( from langgraph._internal._config import (
ensure_config, ensure_config,
@@ -135,7 +136,7 @@ KWARGS_CONFIG_KEYS: tuple[tuple[str, tuple[Any, ...], str, Any], ...] = (
( (
RunnableConfig, RunnableConfig,
"RunnableConfig", "RunnableConfig",
Optional[RunnableConfig], # noqa: UP045 Optional[RunnableConfig],
"Optional[RunnableConfig]", "Optional[RunnableConfig]",
inspect.Parameter.empty, inspect.Parameter.empty,
), ),
@@ -162,7 +163,7 @@ KWARGS_CONFIG_KEYS: tuple[tuple[str, tuple[Any, ...], str, Any], ...] = (
( (
"store", "store",
( (
Optional[BaseStore], # noqa: UP045 Optional[BaseStore],
"Optional[BaseStore]", "Optional[BaseStore]",
), ),
"store", "store",
@@ -240,15 +241,15 @@ class _RunnableWithConfigWriterStore(Protocol[Input, Output]):
) -> Output: ... ) -> Output: ...
RunnableLike = ( RunnableLike = Union[
LCRunnableLike LCRunnableLike,
| _RunnableWithWriter[Input, Output] _RunnableWithWriter[Input, Output],
| _RunnableWithStore[Input, Output] _RunnableWithStore[Input, Output],
| _RunnableWithWriterStore[Input, Output] _RunnableWithWriterStore[Input, Output],
| _RunnableWithConfigWriter[Input, Output] _RunnableWithConfigWriter[Input, Output],
| _RunnableWithConfigStore[Input, Output] _RunnableWithConfigStore[Input, Output],
| _RunnableWithConfigWriterStore[Input, Output] _RunnableWithConfigWriterStore[Input, Output],
) ]
class RunnableCallable(Runnable): class RunnableCallable(Runnable):
@@ -481,9 +482,9 @@ def is_async_callable(
) -> TypeGuard[Callable[..., Awaitable]]: ) -> TypeGuard[Callable[..., Awaitable]]:
"""Check if a function is async.""" """Check if a function is async."""
return ( return (
inspect.iscoroutinefunction(func) asyncio.iscoroutinefunction(func)
or hasattr(func, "__call__") or hasattr(func, "__call__")
and inspect.iscoroutinefunction(func.__call__) and asyncio.iscoroutinefunction(func.__call__)
) )
@@ -533,9 +534,9 @@ def coerce_to_runnable(
class RunnableSeq(Runnable): class RunnableSeq(Runnable):
"""Sequence of `Runnable`, where the output of each is the input of the next. """Sequence of Runnables, where the output of each is the input of the next.
`RunnableSeq` is a simpler version of `RunnableSequence` that is internal to RunnableSeq is a simpler version of RunnableSequence that is internal to
LangGraph. LangGraph.
""" """
@@ -549,7 +550,7 @@ class RunnableSeq(Runnable):
Args: Args:
steps: The steps to include in the sequence. steps: The steps to include in the sequence.
name: The name of the `Runnable`. name: The name of the Runnable. Defaults to None.
Raises: Raises:
ValueError: If the sequence has less than 2 steps. ValueError: If the sequence has less than 2 steps.
@@ -1,6 +1,5 @@
import dataclasses import dataclasses
from collections.abc import Callable from typing import Any, Callable
from typing import Any
from langgraph.types import _DC_KWARGS from langgraph.types import _DC_KWARGS
@@ -3,10 +3,10 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import Field from dataclasses import Field
from typing import Any, ClassVar, Protocol, TypeAlias from typing import Any, ClassVar, Protocol, Union
from pydantic import BaseModel from pydantic import BaseModel
from typing_extensions import TypedDict from typing_extensions import TypeAlias, TypedDict
class TypedDictLikeV1(Protocol): class TypedDictLikeV1(Protocol):
@@ -35,7 +35,7 @@ class DataclassLike(Protocol):
__dataclass_fields__: ClassVar[dict[str, Field[Any]]] __dataclass_fields__: ClassVar[dict[str, Field[Any]]]
StateLike: TypeAlias = TypedDictLikeV1 | TypedDictLikeV2 | DataclassLike | BaseModel StateLike: TypeAlias = Union[TypedDictLikeV1, TypedDictLikeV2, DataclassLike, BaseModel]
"""Type alias for state-like types. """Type alias for state-like types.
It can either be a `TypedDict`, `dataclass`, or Pydantic `BaseModel`. It can either be a `TypedDict`, `dataclass`, or Pydantic `BaseModel`.

Some files were not shown because too many files have changed in this diff Show More