mirror of
https://github.com/hwchase17/langchain.git
synced 2026-02-08 10:09:46 +00:00
Compare commits
6 Commits
langchain-
...
isaac-recu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
255fb6c6d6 | ||
|
|
8c49af3e9c | ||
|
|
71661fd16b | ||
|
|
6d3568d992 | ||
|
|
09db121339 | ||
|
|
0a18a48171 |
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -1,2 +0,0 @@
|
||||
/.github/ @efriis @baskaryan @ccurme
|
||||
/libs/packages.yml @efriis
|
||||
2
.github/DISCUSSION_TEMPLATE/q-a.yml
vendored
2
.github/DISCUSSION_TEMPLATE/q-a.yml
vendored
@@ -22,7 +22,7 @@ body:
|
||||
if there's another way to solve your problem:
|
||||
|
||||
[LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction),
|
||||
[API Reference](https://python.langchain.com/api_reference/),
|
||||
[API Reference](https://api.python.langchain.com/en/stable/),
|
||||
[GitHub search](https://github.com/langchain-ai/langchain),
|
||||
[LangChain Github Discussions](https://github.com/langchain-ai/langchain/discussions),
|
||||
[LangChain Github Issues](https://github.com/langchain-ai/langchain/issues?q=is%3Aissue),
|
||||
|
||||
28
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
28
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -16,7 +16,7 @@ body:
|
||||
if there's another way to solve your problem:
|
||||
|
||||
[LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction),
|
||||
[API Reference](https://python.langchain.com/api_reference/),
|
||||
[API Reference](https://api.python.langchain.com/en/stable/),
|
||||
[GitHub search](https://github.com/langchain-ai/langchain),
|
||||
[LangChain Github Discussions](https://github.com/langchain-ai/langchain/discussions),
|
||||
[LangChain Github Issues](https://github.com/langchain-ai/langchain/issues?q=is%3Aissue),
|
||||
@@ -96,21 +96,25 @@ body:
|
||||
attributes:
|
||||
label: System Info
|
||||
description: |
|
||||
Please share your system info with us. Do NOT skip this step and please don't trim
|
||||
the output. Most users don't include enough information here and it makes it harder
|
||||
for us to help you.
|
||||
Please share your system info with us.
|
||||
|
||||
Run the following command in your terminal and paste the output here:
|
||||
"pip freeze | grep langchain"
|
||||
platform (windows / linux / mac)
|
||||
python version
|
||||
|
||||
OR if you're on a recent version of langchain-core you can paste the output of:
|
||||
|
||||
python -m langchain_core.sys_info
|
||||
|
||||
or if you have an existing python interpreter running:
|
||||
|
||||
from langchain_core import sys_info
|
||||
sys_info.print_sys_info()
|
||||
|
||||
alternatively, put the entire output of `pip freeze` here.
|
||||
placeholder: |
|
||||
"pip freeze | grep langchain"
|
||||
platform
|
||||
python version
|
||||
|
||||
Alternatively, if you're on a recent version of langchain-core you can paste the output of:
|
||||
|
||||
python -m langchain_core.sys_info
|
||||
|
||||
These will only surface LangChain packages, don't forget to include any other relevant
|
||||
packages you're using (if you're not sure what's relevant, you can paste the entire output of `pip freeze`).
|
||||
validations:
|
||||
required: true
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/documentation.yml
vendored
2
.github/ISSUE_TEMPLATE/documentation.yml
vendored
@@ -21,7 +21,7 @@ body:
|
||||
place to ask your question:
|
||||
|
||||
[LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction),
|
||||
[API Reference](https://python.langchain.com/api_reference/),
|
||||
[API Reference](https://api.python.langchain.com/en/stable/),
|
||||
[GitHub search](https://github.com/langchain-ai/langchain),
|
||||
[LangChain Github Discussions](https://github.com/langchain-ai/langchain/discussions),
|
||||
[LangChain Github Issues](https://github.com/langchain-ai/langchain/issues?q=is%3Aissue),
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,7 +1,7 @@
|
||||
Thank you for contributing to LangChain!
|
||||
|
||||
- [ ] **PR title**: "package: description"
|
||||
- Where "package" is whichever of langchain, community, core, etc. is being modified. Use "docs: ..." for purely docs changes, "infra: ..." for CI changes.
|
||||
- Where "package" is whichever of langchain, community, core, experimental, etc. is being modified. Use "docs: ..." for purely docs changes, "templates: ..." for template changes, "infra: ..." for CI changes.
|
||||
- Example: "community: add foobar LLM"
|
||||
|
||||
|
||||
|
||||
21
.github/actions/uv_setup/action.yml
vendored
21
.github/actions/uv_setup/action.yml
vendored
@@ -1,21 +0,0 @@
|
||||
# TODO: https://docs.astral.sh/uv/guides/integration/github/#caching
|
||||
|
||||
name: uv-install
|
||||
description: Set up Python and uv
|
||||
|
||||
inputs:
|
||||
python-version:
|
||||
description: Python version, supporting MAJOR.MINOR only
|
||||
required: true
|
||||
|
||||
env:
|
||||
UV_VERSION: "0.5.25"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install uv and set the python version
|
||||
uses: astral-sh/setup-uv@v5
|
||||
with:
|
||||
version: ${{ env.UV_VERSION }}
|
||||
python-version: ${{ inputs.python-version }}
|
||||
164
.github/scripts/check_diff.py
vendored
164
.github/scripts/check_diff.py
vendored
@@ -2,14 +2,10 @@ import glob
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tomllib
|
||||
from collections import defaultdict
|
||||
from typing import Dict, List, Set
|
||||
from pathlib import Path
|
||||
import tomllib
|
||||
|
||||
from packaging.requirements import Requirement
|
||||
|
||||
from get_min_versions import get_min_version_from_toml
|
||||
|
||||
|
||||
LANGCHAIN_DIRS = [
|
||||
@@ -17,14 +13,9 @@ LANGCHAIN_DIRS = [
|
||||
"libs/text-splitters",
|
||||
"libs/langchain",
|
||||
"libs/community",
|
||||
"libs/experimental",
|
||||
]
|
||||
|
||||
# when set to True, we are ignoring core dependents
|
||||
# in order to be able to get CI to pass for each individual
|
||||
# package that depends on core
|
||||
# e.g. if you touch core, we don't then add textsplitters/etc to CI
|
||||
IGNORE_CORE_DEPENDENTS = False
|
||||
|
||||
# ignored partners are removed from dependents
|
||||
# but still run if directly edited
|
||||
IGNORED_PARTNERS = [
|
||||
@@ -32,14 +23,9 @@ IGNORED_PARTNERS = [
|
||||
# specifically in huggingface jobs
|
||||
# https://github.com/langchain-ai/langchain/issues/25558
|
||||
"huggingface",
|
||||
# prompty exhibiting issues with numpy for Python 3.13
|
||||
# https://github.com/langchain-ai/langchain/actions/runs/12651104685/job/35251034969?pr=29065
|
||||
"prompty",
|
||||
]
|
||||
|
||||
PY_312_MAX_PACKAGES = [
|
||||
"libs/partners/huggingface", # https://github.com/pytorch/pytorch/issues/130249
|
||||
"libs/partners/voyageai",
|
||||
# remove ai21 because of breaking changes in sdk version 2.14.0
|
||||
# that have not been fixed yet
|
||||
"ai21",
|
||||
]
|
||||
|
||||
|
||||
@@ -64,17 +50,15 @@ def dependents_graph() -> dict:
|
||||
|
||||
# load regular and test deps from pyproject.toml
|
||||
with open(path, "rb") as f:
|
||||
pyproject = tomllib.load(f)
|
||||
pyproject = tomllib.load(f)["tool"]["poetry"]
|
||||
|
||||
pkg_dir = "libs" + "/".join(path.split("libs")[1].split("/")[:-1])
|
||||
for dep in [
|
||||
*pyproject["project"]["dependencies"],
|
||||
*pyproject["dependency-groups"]["test"],
|
||||
*pyproject["dependencies"].keys(),
|
||||
*pyproject["group"]["test"]["dependencies"].keys(),
|
||||
]:
|
||||
requirement = Requirement(dep)
|
||||
package_name = requirement.name
|
||||
if "langchain" in dep:
|
||||
dependents[package_name].add(pkg_dir)
|
||||
dependents[dep].add(pkg_dir)
|
||||
continue
|
||||
|
||||
# load extended deps from extended_testing_deps.txt
|
||||
@@ -118,107 +102,44 @@ def add_dependents(dirs_to_eval: Set[str], dependents: dict) -> List[str]:
|
||||
|
||||
|
||||
def _get_configs_for_single_dir(job: str, dir_: str) -> List[Dict[str, str]]:
|
||||
if job == "test-pydantic":
|
||||
return _get_pydantic_test_configs(dir_)
|
||||
|
||||
if dir_ == "libs/core":
|
||||
py_versions = ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
return [
|
||||
{"working-directory": dir_, "python-version": f"3.{v}"}
|
||||
for v in range(8, 13)
|
||||
]
|
||||
min_python = "3.8"
|
||||
max_python = "3.12"
|
||||
|
||||
# custom logic for specific directories
|
||||
elif dir_ == "libs/partners/milvus":
|
||||
# milvus doesn't allow 3.12 because they declare deps in funny way
|
||||
py_versions = ["3.9", "3.11"]
|
||||
if dir_ == "libs/partners/milvus":
|
||||
# milvus poetry doesn't allow 3.12 because they
|
||||
# declare deps in funny way
|
||||
max_python = "3.11"
|
||||
|
||||
elif dir_ in PY_312_MAX_PACKAGES:
|
||||
py_versions = ["3.9", "3.12"]
|
||||
if dir_ in ["libs/community", "libs/langchain"] and job == "extended-tests":
|
||||
# community extended test resolution in 3.12 is slow
|
||||
# even in uv
|
||||
max_python = "3.11"
|
||||
|
||||
elif dir_ == "libs/langchain" and job == "extended-tests":
|
||||
py_versions = ["3.9", "3.13"]
|
||||
|
||||
elif dir_ == "libs/community" and job == "extended-tests":
|
||||
py_versions = ["3.9", "3.12"]
|
||||
|
||||
elif dir_ == "libs/community" and job == "compile-integration-tests":
|
||||
if dir_ == "libs/community" and job == "compile-integration-tests":
|
||||
# community integration deps are slow in 3.12
|
||||
py_versions = ["3.9", "3.11"]
|
||||
elif dir_ == ".":
|
||||
# unable to install with 3.13 because tokenizers doesn't support 3.13 yet
|
||||
py_versions = ["3.9", "3.12"]
|
||||
else:
|
||||
py_versions = ["3.9", "3.13"]
|
||||
max_python = "3.11"
|
||||
|
||||
return [{"working-directory": dir_, "python-version": py_v} for py_v in py_versions]
|
||||
|
||||
|
||||
def _get_pydantic_test_configs(
|
||||
dir_: str, *, python_version: str = "3.11"
|
||||
) -> List[Dict[str, str]]:
|
||||
with open("./libs/core/uv.lock", "rb") as f:
|
||||
core_uv_lock_data = tomllib.load(f)
|
||||
for package in core_uv_lock_data["package"]:
|
||||
if package["name"] == "pydantic":
|
||||
core_max_pydantic_minor = package["version"].split(".")[1]
|
||||
break
|
||||
|
||||
with open(f"./{dir_}/uv.lock", "rb") as f:
|
||||
dir_uv_lock_data = tomllib.load(f)
|
||||
|
||||
for package in dir_uv_lock_data["package"]:
|
||||
if package["name"] == "pydantic":
|
||||
dir_max_pydantic_minor = package["version"].split(".")[1]
|
||||
break
|
||||
|
||||
core_min_pydantic_version = get_min_version_from_toml(
|
||||
"./libs/core/pyproject.toml", "release", python_version, include=["pydantic"]
|
||||
)["pydantic"]
|
||||
core_min_pydantic_minor = (
|
||||
core_min_pydantic_version.split(".")[1]
|
||||
if "." in core_min_pydantic_version
|
||||
else "0"
|
||||
)
|
||||
dir_min_pydantic_version = get_min_version_from_toml(
|
||||
f"./{dir_}/pyproject.toml", "release", python_version, include=["pydantic"]
|
||||
).get("pydantic", "0.0.0")
|
||||
dir_min_pydantic_minor = (
|
||||
dir_min_pydantic_version.split(".")[1]
|
||||
if "." in dir_min_pydantic_version
|
||||
else "0"
|
||||
)
|
||||
|
||||
custom_mins = {
|
||||
# depends on pydantic-settings 2.4 which requires pydantic 2.7
|
||||
"libs/community": 7,
|
||||
}
|
||||
|
||||
max_pydantic_minor = min(
|
||||
int(dir_max_pydantic_minor),
|
||||
int(core_max_pydantic_minor),
|
||||
)
|
||||
min_pydantic_minor = max(
|
||||
int(dir_min_pydantic_minor),
|
||||
int(core_min_pydantic_minor),
|
||||
custom_mins.get(dir_, 0),
|
||||
)
|
||||
|
||||
configs = [
|
||||
{
|
||||
"working-directory": dir_,
|
||||
"pydantic-version": f"2.{v}.0",
|
||||
"python-version": python_version,
|
||||
}
|
||||
for v in range(min_pydantic_minor, max_pydantic_minor + 1)
|
||||
return [
|
||||
{"working-directory": dir_, "python-version": min_python},
|
||||
{"working-directory": dir_, "python-version": max_python},
|
||||
]
|
||||
return configs
|
||||
|
||||
|
||||
def _get_configs_for_multi_dirs(
|
||||
job: str, dirs_to_run: Dict[str, Set[str]], dependents: dict
|
||||
job: str, dirs_to_run: List[str], dependents: dict
|
||||
) -> List[Dict[str, str]]:
|
||||
if job == "lint":
|
||||
dirs = add_dependents(
|
||||
dirs_to_run["lint"] | dirs_to_run["test"] | dirs_to_run["extended-test"],
|
||||
dependents,
|
||||
)
|
||||
elif job in ["test", "compile-integration-tests", "dependencies", "test-pydantic"]:
|
||||
elif job in ["test", "compile-integration-tests", "dependencies"]:
|
||||
dirs = add_dependents(
|
||||
dirs_to_run["test"] | dirs_to_run["extended-test"], dependents
|
||||
)
|
||||
@@ -247,7 +168,6 @@ if __name__ == "__main__":
|
||||
dirs_to_run["lint"] = all_package_dirs()
|
||||
dirs_to_run["test"] = all_package_dirs()
|
||||
dirs_to_run["extended-test"] = set(LANGCHAIN_DIRS)
|
||||
|
||||
for file in files:
|
||||
if any(
|
||||
file.startswith(dir_)
|
||||
@@ -265,12 +185,8 @@ if __name__ == "__main__":
|
||||
if any(file.startswith(dir_) for dir_ in LANGCHAIN_DIRS):
|
||||
# add that dir and all dirs after in LANGCHAIN_DIRS
|
||||
# for extended testing
|
||||
|
||||
found = False
|
||||
for dir_ in LANGCHAIN_DIRS:
|
||||
if dir_ == "libs/core" and IGNORE_CORE_DEPENDENTS:
|
||||
dirs_to_run["extended-test"].add(dir_)
|
||||
continue
|
||||
if file.startswith(dir_):
|
||||
found = True
|
||||
if found:
|
||||
@@ -279,19 +195,16 @@ if __name__ == "__main__":
|
||||
# TODO: update to include all packages that rely on standard-tests (all partner packages)
|
||||
# note: won't run on external repo partners
|
||||
dirs_to_run["lint"].add("libs/standard-tests")
|
||||
dirs_to_run["test"].add("libs/standard-tests")
|
||||
dirs_to_run["lint"].add("libs/cli")
|
||||
dirs_to_run["test"].add("libs/cli")
|
||||
dirs_to_run["test"].add("libs/partners/mistralai")
|
||||
dirs_to_run["test"].add("libs/partners/openai")
|
||||
dirs_to_run["test"].add("libs/partners/anthropic")
|
||||
dirs_to_run["test"].add("libs/partners/ai21")
|
||||
dirs_to_run["test"].add("libs/partners/fireworks")
|
||||
dirs_to_run["test"].add("libs/partners/groq")
|
||||
|
||||
elif file.startswith("libs/cli"):
|
||||
dirs_to_run["lint"].add("libs/cli")
|
||||
dirs_to_run["test"].add("libs/cli")
|
||||
|
||||
# todo: add cli makefile
|
||||
pass
|
||||
elif file.startswith("libs/partners"):
|
||||
partner_dir = file.split("/")[2]
|
||||
if os.path.isdir(f"libs/partners/{partner_dir}") and [
|
||||
@@ -301,21 +214,21 @@ if __name__ == "__main__":
|
||||
] != ["README.md"]:
|
||||
dirs_to_run["test"].add(f"libs/partners/{partner_dir}")
|
||||
# Skip if the directory was deleted or is just a tombstone readme
|
||||
elif file == "libs/packages.yml":
|
||||
continue
|
||||
elif file.startswith("libs/"):
|
||||
raise ValueError(
|
||||
f"Unknown lib: {file}. check_diff.py likely needs "
|
||||
"an update for this new library!"
|
||||
)
|
||||
elif file.startswith("docs/") or file in ["pyproject.toml", "uv.lock"]: # docs or root uv files
|
||||
docs_edited = True
|
||||
elif any(file.startswith(p) for p in ["docs/", "templates/", "cookbook/"]):
|
||||
if file.startswith("docs/"):
|
||||
docs_edited = True
|
||||
dirs_to_run["lint"].add(".")
|
||||
|
||||
dependents = dependents_graph()
|
||||
|
||||
# we now have dirs_by_job
|
||||
# todo: clean this up
|
||||
|
||||
map_job_to_configs = {
|
||||
job: _get_configs_for_multi_dirs(job, dirs_to_run, dependents)
|
||||
for job in [
|
||||
@@ -324,7 +237,6 @@ if __name__ == "__main__":
|
||||
"extended-tests",
|
||||
"compile-integration-tests",
|
||||
"dependencies",
|
||||
"test-pydantic",
|
||||
]
|
||||
}
|
||||
map_job_to_configs["test-doc-imports"] = (
|
||||
|
||||
13
.github/scripts/check_prerelease_dependencies.py
vendored
13
.github/scripts/check_prerelease_dependencies.py
vendored
@@ -10,25 +10,26 @@ if __name__ == "__main__":
|
||||
toml_data = tomllib.load(file)
|
||||
|
||||
# see if we're releasing an rc
|
||||
version = toml_data["project"]["version"]
|
||||
releasing_rc = "rc" in version or "dev" in version
|
||||
version = toml_data["tool"]["poetry"]["version"]
|
||||
releasing_rc = "rc" in version
|
||||
|
||||
# if not, iterate through dependencies and make sure none allow prereleases
|
||||
if not releasing_rc:
|
||||
dependencies = toml_data["project"]["dependencies"]
|
||||
for dep_version in dependencies:
|
||||
dependencies = toml_data["tool"]["poetry"]["dependencies"]
|
||||
for lib in dependencies:
|
||||
dep_version = dependencies[lib]
|
||||
dep_version_string = (
|
||||
dep_version["version"] if isinstance(dep_version, dict) else dep_version
|
||||
)
|
||||
|
||||
if "rc" in dep_version_string:
|
||||
raise ValueError(
|
||||
f"Dependency {dep_version} has a prerelease version. Please remove this."
|
||||
f"Dependency {lib} has a prerelease version. Please remove this."
|
||||
)
|
||||
|
||||
if isinstance(dep_version, dict) and dep_version.get(
|
||||
"allow-prereleases", False
|
||||
):
|
||||
raise ValueError(
|
||||
f"Dependency {dep_version} has allow-prereleases set to true. Please remove this."
|
||||
f"Dependency {lib} has allow-prereleases set to true. Please remove this."
|
||||
)
|
||||
|
||||
178
.github/scripts/get_min_versions.py
vendored
178
.github/scripts/get_min_versions.py
vendored
@@ -1,6 +1,4 @@
|
||||
from collections import defaultdict
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
import tomllib
|
||||
@@ -8,148 +6,72 @@ else:
|
||||
# for python 3.10 and below, which doesnt have stdlib tomllib
|
||||
import tomli as tomllib
|
||||
|
||||
from packaging.requirements import Requirement
|
||||
from packaging.specifiers import SpecifierSet
|
||||
from packaging.version import Version
|
||||
|
||||
|
||||
import requests
|
||||
from packaging.version import parse
|
||||
from typing import List
|
||||
|
||||
from packaging.version import parse as parse_version
|
||||
import re
|
||||
|
||||
|
||||
MIN_VERSION_LIBS = [
|
||||
"langchain-core",
|
||||
"langchain-community",
|
||||
"langchain",
|
||||
"langchain-text-splitters",
|
||||
"numpy",
|
||||
"SQLAlchemy",
|
||||
]
|
||||
|
||||
# some libs only get checked on release because of simultaneous changes in
|
||||
# multiple libs
|
||||
SKIP_IF_PULL_REQUEST = [
|
||||
"langchain-core",
|
||||
"langchain-text-splitters",
|
||||
"langchain",
|
||||
"langchain-community",
|
||||
]
|
||||
SKIP_IF_PULL_REQUEST = ["langchain-core"]
|
||||
|
||||
|
||||
def get_pypi_versions(package_name: str) -> List[str]:
|
||||
"""
|
||||
Fetch all available versions for a package from PyPI.
|
||||
def get_min_version(version: str) -> str:
|
||||
# base regex for x.x.x with cases for rc/post/etc
|
||||
# valid strings: https://peps.python.org/pep-0440/#public-version-identifiers
|
||||
vstring = r"\d+(?:\.\d+){0,2}(?:(?:a|b|rc|\.post|\.dev)\d+)?"
|
||||
# case ^x.x.x
|
||||
_match = re.match(f"^\\^({vstring})$", version)
|
||||
if _match:
|
||||
return _match.group(1)
|
||||
|
||||
Args:
|
||||
package_name (str): Name of the package
|
||||
# case >=x.x.x,<y.y.y
|
||||
_match = re.match(f"^>=({vstring}),<({vstring})$", version)
|
||||
if _match:
|
||||
_min = _match.group(1)
|
||||
_max = _match.group(2)
|
||||
assert parse_version(_min) < parse_version(_max)
|
||||
return _min
|
||||
|
||||
Returns:
|
||||
List[str]: List of all available versions
|
||||
# case x.x.x
|
||||
_match = re.match(f"^({vstring})$", version)
|
||||
if _match:
|
||||
return _match.group(1)
|
||||
|
||||
Raises:
|
||||
requests.exceptions.RequestException: If PyPI API request fails
|
||||
KeyError: If package not found or response format unexpected
|
||||
"""
|
||||
pypi_url = f"https://pypi.org/pypi/{package_name}/json"
|
||||
response = requests.get(pypi_url)
|
||||
response.raise_for_status()
|
||||
return list(response.json()["releases"].keys())
|
||||
raise ValueError(f"Unrecognized version format: {version}")
|
||||
|
||||
|
||||
def get_minimum_version(package_name: str, spec_string: str) -> Optional[str]:
|
||||
"""
|
||||
Find the minimum published version that satisfies the given constraints.
|
||||
|
||||
Args:
|
||||
package_name (str): Name of the package
|
||||
spec_string (str): Version specification string (e.g., ">=0.2.43,<0.4.0,!=0.3.0")
|
||||
|
||||
Returns:
|
||||
Optional[str]: Minimum compatible version or None if no compatible version found
|
||||
"""
|
||||
# rewrite occurrences of ^0.0.z to 0.0.z (can be anywhere in constraint string)
|
||||
spec_string = re.sub(r"\^0\.0\.(\d+)", r"0.0.\1", spec_string)
|
||||
# rewrite occurrences of ^0.y.z to >=0.y.z,<0.y+1 (can be anywhere in constraint string)
|
||||
for y in range(1, 10):
|
||||
spec_string = re.sub(rf"\^0\.{y}\.(\d+)", rf">=0.{y}.\1,<0.{y+1}", spec_string)
|
||||
# rewrite occurrences of ^x.y.z to >=x.y.z,<x+1.0.0 (can be anywhere in constraint string)
|
||||
for x in range(1, 10):
|
||||
spec_string = re.sub(
|
||||
rf"\^{x}\.(\d+)\.(\d+)", rf">={x}.\1.\2,<{x+1}", spec_string
|
||||
)
|
||||
|
||||
spec_set = SpecifierSet(spec_string)
|
||||
all_versions = get_pypi_versions(package_name)
|
||||
|
||||
valid_versions = []
|
||||
for version_str in all_versions:
|
||||
try:
|
||||
version = parse(version_str)
|
||||
if spec_set.contains(version):
|
||||
valid_versions.append(version)
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
return str(min(valid_versions)) if valid_versions else None
|
||||
|
||||
|
||||
def _check_python_version_from_requirement(
|
||||
requirement: Requirement, python_version: str
|
||||
) -> bool:
|
||||
if not requirement.marker:
|
||||
return True
|
||||
else:
|
||||
marker_str = str(requirement.marker)
|
||||
if "python_version" or "python_full_version" in marker_str:
|
||||
python_version_str = "".join(
|
||||
char
|
||||
for char in marker_str
|
||||
if char.isdigit() or char in (".", "<", ">", "=", ",")
|
||||
)
|
||||
return check_python_version(python_version, python_version_str)
|
||||
return True
|
||||
|
||||
|
||||
def get_min_version_from_toml(
|
||||
toml_path: str,
|
||||
versions_for: str,
|
||||
python_version: str,
|
||||
*,
|
||||
include: Optional[list] = None,
|
||||
):
|
||||
def get_min_version_from_toml(toml_path: str, versions_for: str):
|
||||
# Parse the TOML file
|
||||
with open(toml_path, "rb") as file:
|
||||
toml_data = tomllib.load(file)
|
||||
|
||||
dependencies = defaultdict(list)
|
||||
for dep in toml_data["project"]["dependencies"]:
|
||||
requirement = Requirement(dep)
|
||||
dependencies[requirement.name].append(requirement)
|
||||
# Get the dependencies from tool.poetry.dependencies
|
||||
dependencies = toml_data["tool"]["poetry"]["dependencies"]
|
||||
|
||||
# Initialize a dictionary to store the minimum versions
|
||||
min_versions = {}
|
||||
|
||||
# Iterate over the libs in MIN_VERSION_LIBS
|
||||
for lib in set(MIN_VERSION_LIBS + (include or [])):
|
||||
for lib in MIN_VERSION_LIBS:
|
||||
if versions_for == "pull_request" and lib in SKIP_IF_PULL_REQUEST:
|
||||
# some libs only get checked on release because of simultaneous
|
||||
# changes in multiple libs
|
||||
# changes
|
||||
continue
|
||||
# Check if the lib is present in the dependencies
|
||||
if lib in dependencies:
|
||||
if include and lib not in include:
|
||||
continue
|
||||
requirements = dependencies[lib]
|
||||
for requirement in requirements:
|
||||
if _check_python_version_from_requirement(requirement, python_version):
|
||||
version_string = str(requirement.specifier)
|
||||
break
|
||||
# Get the version string
|
||||
version_string = dependencies[lib]
|
||||
|
||||
if isinstance(version_string, dict):
|
||||
version_string = version_string["version"]
|
||||
|
||||
# Use parse_version to get the minimum supported version from version_string
|
||||
min_version = get_minimum_version(lib, version_string)
|
||||
min_version = get_min_version(version_string)
|
||||
|
||||
# Store the minimum version in the min_versions dictionary
|
||||
min_versions[lib] = min_version
|
||||
@@ -157,45 +79,13 @@ def get_min_version_from_toml(
|
||||
return min_versions
|
||||
|
||||
|
||||
def check_python_version(version_string, constraint_string):
|
||||
"""
|
||||
Check if the given Python version matches the given constraints.
|
||||
|
||||
:param version_string: A string representing the Python version (e.g. "3.8.5").
|
||||
:param constraint_string: A string representing the package's Python version constraints (e.g. ">=3.6, <4.0").
|
||||
:return: True if the version matches the constraints, False otherwise.
|
||||
"""
|
||||
|
||||
# rewrite occurrences of ^0.0.z to 0.0.z (can be anywhere in constraint string)
|
||||
constraint_string = re.sub(r"\^0\.0\.(\d+)", r"0.0.\1", constraint_string)
|
||||
# rewrite occurrences of ^0.y.z to >=0.y.z,<0.y+1.0 (can be anywhere in constraint string)
|
||||
for y in range(1, 10):
|
||||
constraint_string = re.sub(
|
||||
rf"\^0\.{y}\.(\d+)", rf">=0.{y}.\1,<0.{y+1}.0", constraint_string
|
||||
)
|
||||
# rewrite occurrences of ^x.y.z to >=x.y.z,<x+1.0.0 (can be anywhere in constraint string)
|
||||
for x in range(1, 10):
|
||||
constraint_string = re.sub(
|
||||
rf"\^{x}\.0\.(\d+)", rf">={x}.0.\1,<{x+1}.0.0", constraint_string
|
||||
)
|
||||
|
||||
try:
|
||||
version = Version(version_string)
|
||||
constraints = SpecifierSet(constraint_string)
|
||||
return version in constraints
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Get the TOML file path from the command line argument
|
||||
toml_file = sys.argv[1]
|
||||
versions_for = sys.argv[2]
|
||||
python_version = sys.argv[3]
|
||||
assert versions_for in ["release", "pull_request"]
|
||||
|
||||
# Call the function to get the minimum versions
|
||||
min_versions = get_min_version_from_toml(toml_file, versions_for, python_version)
|
||||
min_versions = get_min_version_from_toml(toml_file, versions_for)
|
||||
|
||||
print(" ".join([f"{lib}=={version}" for lib, version in min_versions.items()]))
|
||||
|
||||
99
.github/scripts/prep_api_docs_build.py
vendored
99
.github/scripts/prep_api_docs_build.py
vendored
@@ -1,99 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""Script to sync libraries from various repositories into the main langchain repository."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
def load_packages_yaml() -> Dict[str, Any]:
|
||||
"""Load and parse the packages.yml file."""
|
||||
with open("langchain/libs/packages.yml", "r") as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
|
||||
def get_target_dir(package_name: str) -> Path:
|
||||
"""Get the target directory for a given package."""
|
||||
package_name_short = package_name.replace("langchain-", "")
|
||||
base_path = Path("langchain/libs")
|
||||
if package_name_short == "experimental":
|
||||
return base_path / "experimental"
|
||||
return base_path / "partners" / package_name_short
|
||||
|
||||
|
||||
def clean_target_directories(packages: list) -> None:
|
||||
"""Remove old directories that will be replaced."""
|
||||
for package in packages:
|
||||
|
||||
target_dir = get_target_dir(package["name"])
|
||||
if target_dir.exists():
|
||||
print(f"Removing {target_dir}")
|
||||
shutil.rmtree(target_dir)
|
||||
|
||||
|
||||
def move_libraries(packages: list) -> None:
|
||||
"""Move libraries from their source locations to the target directories."""
|
||||
for package in packages:
|
||||
|
||||
repo_name = package["repo"].split("/")[1]
|
||||
source_path = package["path"]
|
||||
target_dir = get_target_dir(package["name"])
|
||||
|
||||
# Handle root path case
|
||||
if source_path == ".":
|
||||
source_dir = repo_name
|
||||
else:
|
||||
source_dir = f"{repo_name}/{source_path}"
|
||||
|
||||
print(f"Moving {source_dir} to {target_dir}")
|
||||
|
||||
# Ensure target directory exists
|
||||
os.makedirs(os.path.dirname(target_dir), exist_ok=True)
|
||||
|
||||
try:
|
||||
# Move the directory
|
||||
shutil.move(source_dir, target_dir)
|
||||
except Exception as e:
|
||||
print(f"Error moving {source_dir} to {target_dir}: {e}")
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to orchestrate the library sync process."""
|
||||
try:
|
||||
# Load packages configuration
|
||||
package_yaml = load_packages_yaml()
|
||||
|
||||
# Clean target directories
|
||||
clean_target_directories([
|
||||
p
|
||||
for p in package_yaml["packages"]
|
||||
if p["repo"].startswith("langchain-ai/")
|
||||
and p["repo"] != "langchain-ai/langchain"
|
||||
])
|
||||
|
||||
# Move libraries to their new locations
|
||||
move_libraries([
|
||||
p
|
||||
for p in package_yaml["packages"]
|
||||
if not p.get("disabled", False)
|
||||
and p["repo"].startswith("langchain-ai/")
|
||||
and p["repo"] != "langchain-ai/langchain"
|
||||
])
|
||||
|
||||
# Delete ones without a pyproject.toml
|
||||
for partner in Path("langchain/libs/partners").iterdir():
|
||||
if partner.is_dir() and not (partner / "pyproject.toml").exists():
|
||||
print(f"Removing {partner} as it does not have a pyproject.toml")
|
||||
shutil.rmtree(partner)
|
||||
|
||||
print("Library sync completed successfully!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error during library sync: {e}")
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
16
.github/workflows/_compile_integration_test.yml
vendored
16
.github/workflows/_compile_integration_test.yml
vendored
@@ -13,7 +13,7 @@ on:
|
||||
description: "Python version to use"
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
POETRY_VERSION: "1.7.1"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -21,23 +21,25 @@ jobs:
|
||||
run:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
name: "uv run pytest -m compile tests/integration_tests #${{ inputs.python-version }}"
|
||||
name: "poetry run pytest -m compile tests/integration_tests #${{ inputs.python-version }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ inputs.python-version }} + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
- name: Set up Python ${{ inputs.python-version }} + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
cache-key: compile-integration
|
||||
|
||||
- name: Install integration dependencies
|
||||
shell: bash
|
||||
run: uv sync --group test --group test_integration
|
||||
run: poetry install --with=test_integration,test
|
||||
|
||||
- name: Check integration tests compile
|
||||
shell: bash
|
||||
run: uv run pytest -m compile tests/integration_tests
|
||||
run: poetry run pytest -m compile tests/integration_tests
|
||||
|
||||
- name: Ensure the tests did not create any additional files
|
||||
shell: bash
|
||||
|
||||
114
.github/workflows/_dependencies.yml
vendored
Normal file
114
.github/workflows/_dependencies.yml
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
name: dependencies
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
working-directory:
|
||||
required: true
|
||||
type: string
|
||||
description: "From which folder this pipeline executes"
|
||||
langchain-location:
|
||||
required: false
|
||||
type: string
|
||||
description: "Relative path to the langchain library folder"
|
||||
python-version:
|
||||
required: true
|
||||
type: string
|
||||
description: "Python version to use"
|
||||
|
||||
env:
|
||||
POETRY_VERSION: "1.7.1"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
runs-on: ubuntu-latest
|
||||
name: dependency checks ${{ inputs.python-version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ inputs.python-version }} + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
cache-key: pydantic-cross-compat
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: poetry install
|
||||
|
||||
- name: Check imports with base dependencies
|
||||
shell: bash
|
||||
run: poetry run make check_imports
|
||||
|
||||
- name: Install test dependencies
|
||||
shell: bash
|
||||
run: poetry install --with test
|
||||
|
||||
- name: Install langchain editable
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
if: ${{ inputs.langchain-location }}
|
||||
env:
|
||||
LANGCHAIN_LOCATION: ${{ inputs.langchain-location }}
|
||||
run: |
|
||||
poetry run pip install -e "$LANGCHAIN_LOCATION"
|
||||
|
||||
- name: Install the opposite major version of pydantic
|
||||
# If normal tests use pydantic v1, here we'll use v2, and vice versa.
|
||||
shell: bash
|
||||
# airbyte currently doesn't support pydantic v2
|
||||
if: ${{ !startsWith(inputs.working-directory, 'libs/partners/airbyte') }}
|
||||
run: |
|
||||
# Determine the major part of pydantic version
|
||||
REGULAR_VERSION=$(poetry run python -c "import pydantic; print(pydantic.__version__)" | cut -d. -f1)
|
||||
|
||||
if [[ "$REGULAR_VERSION" == "1" ]]; then
|
||||
PYDANTIC_DEP=">=2.1,<3"
|
||||
TEST_WITH_VERSION="2"
|
||||
elif [[ "$REGULAR_VERSION" == "2" ]]; then
|
||||
PYDANTIC_DEP="<2"
|
||||
TEST_WITH_VERSION="1"
|
||||
else
|
||||
echo "Unexpected pydantic major version '$REGULAR_VERSION', cannot determine which version to use for cross-compatibility test."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install via `pip` instead of `poetry add` to avoid changing lockfile,
|
||||
# which would prevent caching from working: the cache would get saved
|
||||
# to a different key than where it gets loaded from.
|
||||
poetry run pip install "pydantic${PYDANTIC_DEP}"
|
||||
|
||||
# Ensure that the correct pydantic is installed now.
|
||||
echo "Checking pydantic version... Expecting ${TEST_WITH_VERSION}"
|
||||
|
||||
# Determine the major part of pydantic version
|
||||
CURRENT_VERSION=$(poetry run python -c "import pydantic; print(pydantic.__version__)" | cut -d. -f1)
|
||||
|
||||
# Check that the major part of pydantic version is as expected, if not
|
||||
# raise an error
|
||||
if [[ "$CURRENT_VERSION" != "$TEST_WITH_VERSION" ]]; then
|
||||
echo "Error: expected pydantic version ${CURRENT_VERSION} to have been installed, but found: ${TEST_WITH_VERSION}"
|
||||
exit 1
|
||||
fi
|
||||
echo "Found pydantic version ${CURRENT_VERSION}, as expected"
|
||||
- name: Run pydantic compatibility tests
|
||||
# airbyte currently doesn't support pydantic v2
|
||||
if: ${{ !startsWith(inputs.working-directory, 'libs/partners/airbyte') }}
|
||||
shell: bash
|
||||
run: make test
|
||||
|
||||
- name: Ensure the tests did not create any additional files
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
STATUS="$(git status)"
|
||||
echo "$STATUS"
|
||||
|
||||
# grep will exit non-zero if the target message isn't found,
|
||||
# and `set -e` above will cause the step to fail.
|
||||
echo "$STATUS" | grep 'nothing to commit, working tree clean'
|
||||
25
.github/workflows/_integration_test.yml
vendored
25
.github/workflows/_integration_test.yml
vendored
@@ -12,7 +12,7 @@ on:
|
||||
description: "Python version to use"
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
POETRY_VERSION: "1.7.1"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -24,19 +24,28 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ inputs.python-version }} + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
- name: Set up Python ${{ inputs.python-version }} + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
cache-key: core
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: uv sync --group test --group test_integration
|
||||
run: poetry install --with test,test_integration
|
||||
|
||||
- name: Install deps outside pyproject
|
||||
if: ${{ startsWith(inputs.working-directory, 'libs/community/') }}
|
||||
shell: bash
|
||||
run: VIRTUAL_ENV=.venv uv pip install "boto3<2" "google-cloud-aiplatform<2"
|
||||
run: poetry run pip install "boto3<2" "google-cloud-aiplatform<2"
|
||||
|
||||
- name: 'Authenticate to Google Cloud'
|
||||
id: 'auth'
|
||||
uses: google-github-actions/auth@v2
|
||||
with:
|
||||
credentials_json: '${{ secrets.GOOGLE_CREDENTIALS }}'
|
||||
|
||||
- name: Run integration tests
|
||||
shell: bash
|
||||
@@ -49,7 +58,6 @@ jobs:
|
||||
AZURE_OPENAI_API_BASE: ${{ secrets.AZURE_OPENAI_API_BASE }}
|
||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_CHAT_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_LLM_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LLM_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME }}
|
||||
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
|
||||
@@ -59,22 +67,23 @@ jobs:
|
||||
NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }}
|
||||
GOOGLE_SEARCH_API_KEY: ${{ secrets.GOOGLE_SEARCH_API_KEY }}
|
||||
GOOGLE_CSE_ID: ${{ secrets.GOOGLE_CSE_ID }}
|
||||
HUGGINGFACEHUB_API_TOKEN: ${{ secrets.HUGGINGFACEHUB_API_TOKEN }}
|
||||
EXA_API_KEY: ${{ secrets.EXA_API_KEY }}
|
||||
NOMIC_API_KEY: ${{ secrets.NOMIC_API_KEY }}
|
||||
WATSONX_APIKEY: ${{ secrets.WATSONX_APIKEY }}
|
||||
WATSONX_PROJECT_ID: ${{ secrets.WATSONX_PROJECT_ID }}
|
||||
PINECONE_API_KEY: ${{ secrets.PINECONE_API_KEY }}
|
||||
PINECONE_ENVIRONMENT: ${{ secrets.PINECONE_ENVIRONMENT }}
|
||||
ASTRA_DB_API_ENDPOINT: ${{ secrets.ASTRA_DB_API_ENDPOINT }}
|
||||
ASTRA_DB_APPLICATION_TOKEN: ${{ secrets.ASTRA_DB_APPLICATION_TOKEN }}
|
||||
ASTRA_DB_KEYSPACE: ${{ secrets.ASTRA_DB_KEYSPACE }}
|
||||
ES_URL: ${{ secrets.ES_URL }}
|
||||
ES_CLOUD_ID: ${{ secrets.ES_CLOUD_ID }}
|
||||
ES_API_KEY: ${{ secrets.ES_API_KEY }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # for airbyte
|
||||
MONGODB_ATLAS_URI: ${{ secrets.MONGODB_ATLAS_URI }}
|
||||
VOYAGE_API_KEY: ${{ secrets.VOYAGE_API_KEY }}
|
||||
COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
|
||||
UPSTAGE_API_KEY: ${{ secrets.UPSTAGE_API_KEY }}
|
||||
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
|
||||
run: |
|
||||
make integration_tests
|
||||
|
||||
|
||||
60
.github/workflows/_lint.yml
vendored
60
.github/workflows/_lint.yml
vendored
@@ -7,31 +7,48 @@ on:
|
||||
required: true
|
||||
type: string
|
||||
description: "From which folder this pipeline executes"
|
||||
langchain-location:
|
||||
required: false
|
||||
type: string
|
||||
description: "Relative path to the langchain library folder"
|
||||
python-version:
|
||||
required: true
|
||||
type: string
|
||||
description: "Python version to use"
|
||||
|
||||
env:
|
||||
POETRY_VERSION: "1.7.1"
|
||||
WORKDIR: ${{ inputs.working-directory == '' && '.' || inputs.working-directory }}
|
||||
|
||||
# This env var allows us to get inline annotations when ruff has complaints.
|
||||
RUFF_OUTPUT_FORMAT: github
|
||||
|
||||
UV_FROZEN: "true"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: "make lint #${{ inputs.python-version }}"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ inputs.python-version }} + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
- name: Set up Python ${{ inputs.python-version }} + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
cache-key: lint-with-extras
|
||||
|
||||
- name: Check Poetry File
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: |
|
||||
poetry check
|
||||
|
||||
- name: Check lock file
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: |
|
||||
poetry lock --check
|
||||
|
||||
- name: Install dependencies
|
||||
# Also installs dev/lint/test/typing dependencies, to ensure we have
|
||||
@@ -44,7 +61,25 @@ jobs:
|
||||
# It doesn't matter how you change it, any change will cause a cache-bust.
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: |
|
||||
uv sync --group lint --group typing
|
||||
poetry install --with lint,typing
|
||||
|
||||
- name: Install langchain editable
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
if: ${{ inputs.langchain-location }}
|
||||
env:
|
||||
LANGCHAIN_LOCATION: ${{ inputs.langchain-location }}
|
||||
run: |
|
||||
poetry run pip install -e "$LANGCHAIN_LOCATION"
|
||||
|
||||
- name: Get .mypy_cache to speed up mypy
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2"
|
||||
with:
|
||||
path: |
|
||||
${{ env.WORKDIR }}/.mypy_cache
|
||||
key: mypy-lint-${{ runner.os }}-${{ runner.arch }}-py${{ inputs.python-version }}-${{ inputs.working-directory }}-${{ hashFiles(format('{0}/poetry.lock', inputs.working-directory)) }}
|
||||
|
||||
|
||||
- name: Analysing the code with our lint
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
@@ -63,12 +98,21 @@ jobs:
|
||||
if: ${{ ! startsWith(inputs.working-directory, 'libs/partners/') }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: |
|
||||
uv sync --inexact --group test
|
||||
poetry install --with test
|
||||
- name: Install unit+integration test dependencies
|
||||
if: ${{ startsWith(inputs.working-directory, 'libs/partners/') }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: |
|
||||
uv sync --inexact --group test --group test_integration
|
||||
poetry install --with test,test_integration
|
||||
|
||||
- name: Get .mypy_cache_test to speed up mypy
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2"
|
||||
with:
|
||||
path: |
|
||||
${{ env.WORKDIR }}/.mypy_cache_test
|
||||
key: mypy-test-${{ runner.os }}-${{ runner.arch }}-py${{ inputs.python-version }}-${{ inputs.working-directory }}-${{ hashFiles(format('{0}/poetry.lock', inputs.working-directory)) }}
|
||||
|
||||
- name: Analysing the code with our lint
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
134
.github/workflows/_release.yml
vendored
134
.github/workflows/_release.yml
vendored
@@ -21,8 +21,7 @@ on:
|
||||
|
||||
env:
|
||||
PYTHON_VERSION: "3.11"
|
||||
UV_FROZEN: "true"
|
||||
UV_NO_SYNC: "true"
|
||||
POETRY_VERSION: "1.7.1"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -37,10 +36,13 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
cache-key: release
|
||||
|
||||
# We want to keep this build stage *separate* from the release stage,
|
||||
# so that there's no sharing of permissions between them.
|
||||
@@ -54,7 +56,7 @@ jobs:
|
||||
# > from the publish job.
|
||||
# https://github.com/pypa/gh-action-pypi-publish#non-goals
|
||||
- name: Build project for distribution
|
||||
run: uv build
|
||||
run: poetry build
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
- name: Upload build
|
||||
@@ -65,18 +67,11 @@ jobs:
|
||||
|
||||
- name: Check Version
|
||||
id: check-version
|
||||
shell: python
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: |
|
||||
import os
|
||||
import tomllib
|
||||
with open("pyproject.toml", "rb") as f:
|
||||
data = tomllib.load(f)
|
||||
pkg_name = data["project"]["name"]
|
||||
version = data["project"]["version"]
|
||||
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
|
||||
f.write(f"pkg-name={pkg_name}\n")
|
||||
f.write(f"version={version}\n")
|
||||
echo pkg-name="$(poetry version | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT
|
||||
echo version="$(poetry version --short)" >> $GITHUB_OUTPUT
|
||||
release-notes:
|
||||
needs:
|
||||
- build
|
||||
@@ -90,7 +85,7 @@ jobs:
|
||||
path: langchain
|
||||
sparse-checkout: | # this only grabs files for relevant dir
|
||||
${{ inputs.working-directory }}
|
||||
ref: ${{ github.ref }} # this scopes to just ref'd branch
|
||||
ref: master # this scopes to just master branch
|
||||
fetch-depth: 0 # this fetches entire commit history
|
||||
- name: Check Tags
|
||||
id: check-tags
|
||||
@@ -100,30 +95,9 @@ jobs:
|
||||
PKG_NAME: ${{ needs.build.outputs.pkg-name }}
|
||||
VERSION: ${{ needs.build.outputs.version }}
|
||||
run: |
|
||||
PREV_TAG="$PKG_NAME==${VERSION%.*}.$(( ${VERSION##*.} - 1 ))"; [[ "${VERSION##*.}" -eq 0 ]] && PREV_TAG=""
|
||||
|
||||
# backup case if releasing e.g. 0.3.0, looks up last release
|
||||
# note if last release (chronologically) was e.g. 0.1.47 it will get
|
||||
# that instead of the last 0.2 release
|
||||
if [ -z "$PREV_TAG" ]; then
|
||||
REGEX="^$PKG_NAME==\\d+\\.\\d+\\.\\d+\$"
|
||||
echo $REGEX
|
||||
PREV_TAG=$(git tag --sort=-creatordate | (grep -P $REGEX || true) | head -1)
|
||||
fi
|
||||
|
||||
# if PREV_TAG is empty, let it be empty
|
||||
if [ -z "$PREV_TAG" ]; then
|
||||
echo "No previous tag found - first release"
|
||||
else
|
||||
# confirm prev-tag actually exists in git repo with git tag
|
||||
GIT_TAG_RESULT=$(git tag -l "$PREV_TAG")
|
||||
if [ -z "$GIT_TAG_RESULT" ]; then
|
||||
echo "Previous tag $PREV_TAG not found in git repo"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
REGEX="^$PKG_NAME==\\d+\\.\\d+\\.\\d+\$"
|
||||
echo $REGEX
|
||||
PREV_TAG=$(git tag --sort=-creatordate | grep -P $REGEX || true | head -1)
|
||||
TAG="${PKG_NAME}==${VERSION}"
|
||||
if [ "$TAG" == "$PREV_TAG" ]; then
|
||||
echo "No new version to release"
|
||||
@@ -172,7 +146,6 @@ jobs:
|
||||
- release-notes
|
||||
- test-pypi-publish
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -189,18 +162,14 @@ jobs:
|
||||
# - The package is published, and it breaks on the missing dependency when
|
||||
# used in the real world.
|
||||
|
||||
- name: Set up Python + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
id: setup-python
|
||||
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: dist
|
||||
path: ${{ inputs.working-directory }}/dist/
|
||||
|
||||
- name: Import dist package
|
||||
- name: Import published package
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
env:
|
||||
@@ -216,21 +185,27 @@ jobs:
|
||||
# - attempt install again after 5 seconds if it fails because there is
|
||||
# sometimes a delay in availability on test pypi
|
||||
run: |
|
||||
uv venv
|
||||
VIRTUAL_ENV=.venv uv pip install dist/*.whl
|
||||
poetry run pip install \
|
||||
--extra-index-url https://test.pypi.org/simple/ \
|
||||
"$PKG_NAME==$VERSION" || \
|
||||
( \
|
||||
sleep 15 && \
|
||||
poetry run pip install \
|
||||
--extra-index-url https://test.pypi.org/simple/ \
|
||||
"$PKG_NAME==$VERSION" \
|
||||
)
|
||||
|
||||
# Replace all dashes in the package name with underscores,
|
||||
# since that's how Python imports packages with dashes in the name.
|
||||
# also remove _official suffix
|
||||
IMPORT_NAME="$(echo "$PKG_NAME" | sed s/-/_/g | sed s/_official//g)"
|
||||
IMPORT_NAME="$(echo "$PKG_NAME" | sed s/-/_/g)"
|
||||
|
||||
uv run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))"
|
||||
poetry run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))"
|
||||
|
||||
- name: Import test dependencies
|
||||
run: uv sync --group test
|
||||
run: poetry install --with test
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
# Overwrite the local version of the package with the built version
|
||||
# Overwrite the local version of the package with the test PyPI version.
|
||||
- name: Import published package (again)
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
shell: bash
|
||||
@@ -238,7 +213,9 @@ jobs:
|
||||
PKG_NAME: ${{ needs.build.outputs.pkg-name }}
|
||||
VERSION: ${{ needs.build.outputs.version }}
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install dist/*.whl
|
||||
poetry run pip install \
|
||||
--extra-index-url https://test.pypi.org/simple/ \
|
||||
"$PKG_NAME==$VERSION"
|
||||
|
||||
- name: Run unit tests
|
||||
run: make tests
|
||||
@@ -247,15 +224,14 @@ jobs:
|
||||
- name: Check for prerelease versions
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: |
|
||||
uv run python $GITHUB_WORKSPACE/.github/scripts/check_prerelease_dependencies.py pyproject.toml
|
||||
poetry run python $GITHUB_WORKSPACE/.github/scripts/check_prerelease_dependencies.py pyproject.toml
|
||||
|
||||
- name: Get minimum versions
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
id: min-version
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install packaging requests
|
||||
python_version="$(uv run python --version | awk '{print $2}')"
|
||||
min_versions="$(uv run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml release $python_version)"
|
||||
poetry run pip install packaging
|
||||
min_versions="$(poetry run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml release)"
|
||||
echo "min-versions=$min_versions" >> "$GITHUB_OUTPUT"
|
||||
echo "min-versions=$min_versions"
|
||||
|
||||
@@ -264,12 +240,18 @@ jobs:
|
||||
env:
|
||||
MIN_VERSIONS: ${{ steps.min-version.outputs.min-versions }}
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install --force-reinstall $MIN_VERSIONS --editable .
|
||||
poetry run pip install --force-reinstall $MIN_VERSIONS --editable .
|
||||
make tests
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
- name: 'Authenticate to Google Cloud'
|
||||
id: 'auth'
|
||||
uses: google-github-actions/auth@v2
|
||||
with:
|
||||
credentials_json: '${{ secrets.GOOGLE_CREDENTIALS }}'
|
||||
|
||||
- name: Import integration test dependencies
|
||||
run: uv sync --group test --group test_integration
|
||||
run: poetry install --with test,test_integration
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
- name: Run integration tests
|
||||
@@ -285,30 +267,30 @@ jobs:
|
||||
AZURE_OPENAI_API_BASE: ${{ secrets.AZURE_OPENAI_API_BASE }}
|
||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_CHAT_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_LLM_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LLM_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME }}
|
||||
NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }}
|
||||
GOOGLE_SEARCH_API_KEY: ${{ secrets.GOOGLE_SEARCH_API_KEY }}
|
||||
GOOGLE_CSE_ID: ${{ secrets.GOOGLE_CSE_ID }}
|
||||
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
||||
HUGGINGFACEHUB_API_TOKEN: ${{ secrets.HUGGINGFACEHUB_API_TOKEN }}
|
||||
EXA_API_KEY: ${{ secrets.EXA_API_KEY }}
|
||||
NOMIC_API_KEY: ${{ secrets.NOMIC_API_KEY }}
|
||||
WATSONX_APIKEY: ${{ secrets.WATSONX_APIKEY }}
|
||||
WATSONX_PROJECT_ID: ${{ secrets.WATSONX_PROJECT_ID }}
|
||||
PINECONE_API_KEY: ${{ secrets.PINECONE_API_KEY }}
|
||||
PINECONE_ENVIRONMENT: ${{ secrets.PINECONE_ENVIRONMENT }}
|
||||
ASTRA_DB_API_ENDPOINT: ${{ secrets.ASTRA_DB_API_ENDPOINT }}
|
||||
ASTRA_DB_APPLICATION_TOKEN: ${{ secrets.ASTRA_DB_APPLICATION_TOKEN }}
|
||||
ASTRA_DB_KEYSPACE: ${{ secrets.ASTRA_DB_KEYSPACE }}
|
||||
ES_URL: ${{ secrets.ES_URL }}
|
||||
ES_CLOUD_ID: ${{ secrets.ES_CLOUD_ID }}
|
||||
ES_API_KEY: ${{ secrets.ES_API_KEY }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # for airbyte
|
||||
MONGODB_ATLAS_URI: ${{ secrets.MONGODB_ATLAS_URI }}
|
||||
VOYAGE_API_KEY: ${{ secrets.VOYAGE_API_KEY }}
|
||||
UPSTAGE_API_KEY: ${{ secrets.UPSTAGE_API_KEY }}
|
||||
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
|
||||
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
UNSTRUCTURED_API_KEY: ${{ secrets.UNSTRUCTURED_API_KEY }}
|
||||
run: make integration_tests
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
@@ -334,10 +316,13 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
cache-key: release
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -350,8 +335,6 @@ jobs:
|
||||
packages-dir: ${{ inputs.working-directory }}/dist/
|
||||
verbose: true
|
||||
print-hash: true
|
||||
# Temp workaround since attestations are on by default as of gh-action-pypi-publish v1.11.0
|
||||
attestations: false
|
||||
|
||||
mark-release:
|
||||
needs:
|
||||
@@ -373,10 +356,13 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
cache-key: release
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
|
||||
62
.github/workflows/_release_docker.yml
vendored
Normal file
62
.github/workflows/_release_docker.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: release_docker
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
dockerfile:
|
||||
required: true
|
||||
type: string
|
||||
description: "Path to the Dockerfile to build"
|
||||
image:
|
||||
required: true
|
||||
type: string
|
||||
description: "Name of the image to build"
|
||||
|
||||
env:
|
||||
TEST_TAG: ${{ inputs.image }}:test
|
||||
LATEST_TAG: ${{ inputs.image }}:latest
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Get git tag
|
||||
uses: actions-ecosystem/action-get-latest-tag@v1
|
||||
id: get-latest-tag
|
||||
- name: Set docker tag
|
||||
env:
|
||||
VERSION: ${{ steps.get-latest-tag.outputs.tag }}
|
||||
run: |
|
||||
echo "VERSION_TAG=${{ inputs.image }}:${VERSION#v}" >> $GITHUB_ENV
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build for Test
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ${{ inputs.dockerfile }}
|
||||
load: true
|
||||
tags: ${{ env.TEST_TAG }}
|
||||
- name: Test
|
||||
run: |
|
||||
docker run --rm ${{ env.TEST_TAG }} python -c "import langchain"
|
||||
- name: Build and Push to Docker Hub
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ${{ inputs.dockerfile }}
|
||||
# We can only build for the intersection of platforms supported by
|
||||
# QEMU and base python image, for now build only for
|
||||
# linux/amd64 and linux/arm64
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ env.LATEST_TAG }},${{ env.VERSION_TAG }}
|
||||
push: true
|
||||
64
.github/workflows/_test.yml
vendored
64
.github/workflows/_test.yml
vendored
@@ -7,14 +7,17 @@ on:
|
||||
required: true
|
||||
type: string
|
||||
description: "From which folder this pipeline executes"
|
||||
langchain-location:
|
||||
required: false
|
||||
type: string
|
||||
description: "Relative path to the langchain library folder"
|
||||
python-version:
|
||||
required: true
|
||||
type: string
|
||||
description: "Python version to use"
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
UV_NO_SYNC: "true"
|
||||
POETRY_VERSION: "1.7.1"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -22,45 +25,35 @@ jobs:
|
||||
run:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
name: "make test #${{ inputs.python-version }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ inputs.python-version }} + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
id: setup-python
|
||||
- name: Set up Python ${{ inputs.python-version }} + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
cache-key: core
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: uv sync --group test --dev
|
||||
run: poetry install --with test
|
||||
|
||||
- name: Install langchain editable
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
if: ${{ inputs.langchain-location }}
|
||||
env:
|
||||
LANGCHAIN_LOCATION: ${{ inputs.langchain-location }}
|
||||
run: |
|
||||
poetry run pip install -e "$LANGCHAIN_LOCATION"
|
||||
|
||||
- name: Run core tests
|
||||
shell: bash
|
||||
run: |
|
||||
make test
|
||||
|
||||
- name: Get minimum versions
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
id: min-version
|
||||
shell: bash
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install packaging tomli requests
|
||||
python_version="$(uv run python --version | awk '{print $2}')"
|
||||
min_versions="$(uv run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml pull_request $python_version)"
|
||||
echo "min-versions=$min_versions" >> "$GITHUB_OUTPUT"
|
||||
echo "min-versions=$min_versions"
|
||||
|
||||
- name: Run unit tests with minimum dependency versions
|
||||
if: ${{ steps.min-version.outputs.min-versions != '' }}
|
||||
env:
|
||||
MIN_VERSIONS: ${{ steps.min-version.outputs.min-versions }}
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install $MIN_VERSIONS
|
||||
make tests
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
- name: Ensure the tests did not create any additional files
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -73,3 +66,20 @@ jobs:
|
||||
# and `set -e` above will cause the step to fail.
|
||||
echo "$STATUS" | grep 'nothing to commit, working tree clean'
|
||||
|
||||
- name: Get minimum versions
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
id: min-version
|
||||
run: |
|
||||
poetry run pip install packaging tomli
|
||||
min_versions="$(poetry run python $GITHUB_WORKSPACE/.github/scripts/get_min_versions.py pyproject.toml pull_request)"
|
||||
echo "min-versions=$min_versions" >> "$GITHUB_OUTPUT"
|
||||
echo "min-versions=$min_versions"
|
||||
|
||||
- name: Run unit tests with minimum dependency versions
|
||||
if: ${{ steps.min-version.outputs.min-versions != '' }}
|
||||
env:
|
||||
MIN_VERSIONS: ${{ steps.min-version.outputs.min-versions }}
|
||||
run: |
|
||||
poetry run pip install --force-reinstall $MIN_VERSIONS --editable .
|
||||
make tests
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
15
.github/workflows/_test_doc_imports.yml
vendored
15
.github/workflows/_test_doc_imports.yml
vendored
@@ -9,33 +9,34 @@ on:
|
||||
description: "Python version to use"
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
POETRY_VERSION: "1.7.1"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
name: "check doc imports #${{ inputs.python-version }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ inputs.python-version }} + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
- name: Set up Python ${{ inputs.python-version }} + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
cache-key: core
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: uv sync --group test
|
||||
run: poetry install --with test
|
||||
|
||||
- name: Install langchain editable
|
||||
run: |
|
||||
VIRTUAL_ENV=.venv uv pip install langchain-experimental -e libs/core libs/langchain libs/community
|
||||
poetry run pip install -e libs/core libs/langchain libs/community libs/experimental
|
||||
|
||||
- name: Check doc imports
|
||||
shell: bash
|
||||
run: |
|
||||
uv run python docs/scripts/check_imports.py
|
||||
poetry run python docs/scripts/check_imports.py
|
||||
|
||||
- name: Ensure the test did not create any additional files
|
||||
shell: bash
|
||||
|
||||
63
.github/workflows/_test_pydantic.yml
vendored
63
.github/workflows/_test_pydantic.yml
vendored
@@ -1,63 +0,0 @@
|
||||
name: test pydantic intermediate versions
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
working-directory:
|
||||
required: true
|
||||
type: string
|
||||
description: "From which folder this pipeline executes"
|
||||
python-version:
|
||||
required: false
|
||||
type: string
|
||||
description: "Python version to use"
|
||||
default: "3.11"
|
||||
pydantic-version:
|
||||
required: true
|
||||
type: string
|
||||
description: "Pydantic version to test."
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
UV_NO_SYNC: "true"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
name: "make test # pydantic: ~=${{ inputs.pydantic-version }}, python: ${{ inputs.python-version }}, "
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ inputs.python-version }} + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: uv sync --group test
|
||||
|
||||
- name: Overwrite pydantic version
|
||||
shell: bash
|
||||
run: VIRTUAL_ENV=.venv uv pip install pydantic~=${{ inputs.pydantic-version }}
|
||||
|
||||
- name: Run core tests
|
||||
shell: bash
|
||||
run: |
|
||||
make test
|
||||
|
||||
- name: Ensure the tests did not create any additional files
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
STATUS="$(git status)"
|
||||
echo "$STATUS"
|
||||
|
||||
# grep will exit non-zero if the target message isn't found,
|
||||
# and `set -e` above will cause the step to fail.
|
||||
echo "$STATUS" | grep 'nothing to commit, working tree clean'
|
||||
28
.github/workflows/_test_release.yml
vendored
28
.github/workflows/_test_release.yml
vendored
@@ -14,8 +14,8 @@ on:
|
||||
description: "Release from a non-master branch (danger!)"
|
||||
|
||||
env:
|
||||
PYTHON_VERSION: "3.11"
|
||||
UV_FROZEN: "true"
|
||||
POETRY_VERSION: "1.7.1"
|
||||
PYTHON_VERSION: "3.10"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -29,10 +29,13 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
cache-key: release
|
||||
|
||||
# We want to keep this build stage *separate* from the release stage,
|
||||
# so that there's no sharing of permissions between them.
|
||||
@@ -46,7 +49,7 @@ jobs:
|
||||
# > from the publish job.
|
||||
# https://github.com/pypa/gh-action-pypi-publish#non-goals
|
||||
- name: Build project for distribution
|
||||
run: uv build
|
||||
run: poetry build
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
|
||||
- name: Upload build
|
||||
@@ -57,18 +60,11 @@ jobs:
|
||||
|
||||
- name: Check Version
|
||||
id: check-version
|
||||
shell: python
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: |
|
||||
import os
|
||||
import tomllib
|
||||
with open("pyproject.toml", "rb") as f:
|
||||
data = tomllib.load(f)
|
||||
pkg_name = data["project"]["name"]
|
||||
version = data["project"]["version"]
|
||||
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
|
||||
f.write(f"pkg-name={pkg_name}\n")
|
||||
f.write(f"version={version}\n")
|
||||
echo pkg-name="$(poetry version | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT
|
||||
echo version="$(poetry version --short)" >> $GITHUB_OUTPUT
|
||||
|
||||
publish:
|
||||
needs:
|
||||
@@ -102,5 +98,3 @@ jobs:
|
||||
# This is *only for CI use* and is *extremely dangerous* otherwise!
|
||||
# https://github.com/pypa/gh-action-pypi-publish#tolerating-release-package-file-duplicates
|
||||
skip-existing: true
|
||||
# Temp workaround since attestations are on by default as of gh-action-pypi-publish v1.11.0
|
||||
attestations: false
|
||||
|
||||
96
.github/workflows/api_doc_build.yml
vendored
96
.github/workflows/api_doc_build.yml
vendored
@@ -1,96 +0,0 @@
|
||||
name: API docs build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 13 * * *'
|
||||
env:
|
||||
PYTHON_VERSION: "3.11"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository == 'langchain-ai/langchain' || github.event_name != 'schedule'
|
||||
runs-on: ubuntu-latest
|
||||
permissions: write-all
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: langchain
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: langchain-ai/langchain-api-docs-html
|
||||
path: langchain-api-docs-html
|
||||
token: ${{ secrets.TOKEN_GITHUB_API_DOCS_HTML }}
|
||||
|
||||
- name: Get repos with yq
|
||||
id: get-unsorted-repos
|
||||
uses: mikefarah/yq@master
|
||||
with:
|
||||
cmd: yq '.packages[].repo' langchain/libs/packages.yml
|
||||
|
||||
- name: Parse YAML and checkout repos
|
||||
env:
|
||||
REPOS_UNSORTED: ${{ steps.get-unsorted-repos.outputs.result }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
# Get unique repositories
|
||||
REPOS=$(echo "$REPOS_UNSORTED" | sort -u)
|
||||
|
||||
# Checkout each unique repository that is in langchain-ai org
|
||||
for repo in $REPOS; do
|
||||
if [[ "$repo" != "langchain-ai/langchain" && "$repo" == langchain-ai/* ]]; then
|
||||
REPO_NAME=$(echo $repo | cut -d'/' -f2)
|
||||
echo "Checking out $repo to $REPO_NAME"
|
||||
git clone --depth 1 https://github.com/$repo.git $REPO_NAME
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Setup python ${{ env.PYTHON_VERSION }}
|
||||
uses: actions/setup-python@v5
|
||||
id: setup-python
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
- name: Install initial py deps
|
||||
working-directory: langchain
|
||||
run: |
|
||||
python -m pip install -U uv
|
||||
python -m uv pip install --upgrade --no-cache-dir pip setuptools pyyaml
|
||||
|
||||
- name: Move libs with script
|
||||
run: python langchain/.github/scripts/prep_api_docs_build.py
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Rm old html
|
||||
run:
|
||||
rm -rf langchain-api-docs-html/api_reference_build/html
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: langchain
|
||||
run: |
|
||||
python -m uv pip install $(ls ./libs/partners | xargs -I {} echo "./libs/partners/{}") --overrides ./docs/vercel_overrides.txt
|
||||
python -m uv pip install libs/core libs/langchain libs/text-splitters libs/community libs/experimental libs/standard-tests
|
||||
python -m uv pip install -r docs/api_reference/requirements.txt
|
||||
|
||||
- name: Set Git config
|
||||
working-directory: langchain
|
||||
run: |
|
||||
git config --local user.email "actions@github.com"
|
||||
git config --local user.name "Github Actions"
|
||||
|
||||
- name: Build docs
|
||||
working-directory: langchain
|
||||
run: |
|
||||
python docs/api_reference/create_api_rst.py
|
||||
python -m sphinx -T -E -b html -d ../langchain-api-docs-html/_build/doctrees -c docs/api_reference docs/api_reference ../langchain-api-docs-html/api_reference_build/html -j auto
|
||||
python docs/api_reference/scripts/custom_formatter.py ../langchain-api-docs-html/api_reference_build/html
|
||||
# Default index page is blank so we copy in the actual home page.
|
||||
cp ../langchain-api-docs-html/api_reference_build/html/{reference,index}.html
|
||||
rm -rf ../langchain-api-docs-html/_build/
|
||||
|
||||
# https://github.com/marketplace/actions/add-commit
|
||||
- uses: EndBug/add-and-commit@v9
|
||||
with:
|
||||
cwd: langchain-api-docs-html
|
||||
message: 'Update API docs build'
|
||||
2
.github/workflows/check-broken-links.yml
vendored
2
.github/workflows/check-broken-links.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
check-links:
|
||||
if: github.repository_owner == 'langchain-ai' || github.event_name != 'schedule'
|
||||
if: github.repository_owner == 'langchain-ai'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
62
.github/workflows/check_diffs.yml
vendored
62
.github/workflows/check_diffs.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
merge_group:
|
||||
|
||||
# If another push to the same PR or branch happens while this workflow is still running,
|
||||
# cancel the earlier run in favor of the next run.
|
||||
@@ -18,8 +17,7 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
UV_NO_SYNC: "true"
|
||||
POETRY_VERSION: "1.7.1"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -33,7 +31,6 @@ jobs:
|
||||
uses: Ana06/get-changed-files@v2.2.0
|
||||
- id: set-matrix
|
||||
run: |
|
||||
python -m pip install packaging requests
|
||||
python .github/scripts/check_diff.py ${{ steps.files.outputs.all }} >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
lint: ${{ steps.set-matrix.outputs.lint }}
|
||||
@@ -42,7 +39,6 @@ jobs:
|
||||
compile-integration-tests: ${{ steps.set-matrix.outputs.compile-integration-tests }}
|
||||
dependencies: ${{ steps.set-matrix.outputs.dependencies }}
|
||||
test-doc-imports: ${{ steps.set-matrix.outputs.test-doc-imports }}
|
||||
test-pydantic: ${{ steps.set-matrix.outputs.test-pydantic }}
|
||||
lint:
|
||||
name: cd ${{ matrix.job-configs.working-directory }}
|
||||
needs: [ build ]
|
||||
@@ -50,7 +46,6 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
job-configs: ${{ fromJson(needs.build.outputs.lint) }}
|
||||
fail-fast: false
|
||||
uses: ./.github/workflows/_lint.yml
|
||||
with:
|
||||
working-directory: ${{ matrix.job-configs.working-directory }}
|
||||
@@ -64,34 +59,18 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
job-configs: ${{ fromJson(needs.build.outputs.test) }}
|
||||
fail-fast: false
|
||||
uses: ./.github/workflows/_test.yml
|
||||
with:
|
||||
working-directory: ${{ matrix.job-configs.working-directory }}
|
||||
python-version: ${{ matrix.job-configs.python-version }}
|
||||
secrets: inherit
|
||||
|
||||
test-pydantic:
|
||||
name: cd ${{ matrix.job-configs.working-directory }}
|
||||
needs: [ build ]
|
||||
if: ${{ needs.build.outputs.test-pydantic != '[]' }}
|
||||
strategy:
|
||||
matrix:
|
||||
job-configs: ${{ fromJson(needs.build.outputs.test-pydantic) }}
|
||||
fail-fast: false
|
||||
uses: ./.github/workflows/_test_pydantic.yml
|
||||
with:
|
||||
working-directory: ${{ matrix.job-configs.working-directory }}
|
||||
pydantic-version: ${{ matrix.job-configs.pydantic-version }}
|
||||
secrets: inherit
|
||||
|
||||
test-doc-imports:
|
||||
needs: [ build ]
|
||||
if: ${{ needs.build.outputs.test-doc-imports != '[]' }}
|
||||
strategy:
|
||||
matrix:
|
||||
job-configs: ${{ fromJson(needs.build.outputs.test-doc-imports) }}
|
||||
fail-fast: false
|
||||
uses: ./.github/workflows/_test_doc_imports.yml
|
||||
secrets: inherit
|
||||
with:
|
||||
@@ -104,13 +83,25 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
job-configs: ${{ fromJson(needs.build.outputs.compile-integration-tests) }}
|
||||
fail-fast: false
|
||||
uses: ./.github/workflows/_compile_integration_test.yml
|
||||
with:
|
||||
working-directory: ${{ matrix.job-configs.working-directory }}
|
||||
python-version: ${{ matrix.job-configs.python-version }}
|
||||
secrets: inherit
|
||||
|
||||
dependencies:
|
||||
name: cd ${{ matrix.job-configs.working-directory }}
|
||||
needs: [ build ]
|
||||
if: ${{ needs.build.outputs.dependencies != '[]' }}
|
||||
strategy:
|
||||
matrix:
|
||||
job-configs: ${{ fromJson(needs.build.outputs.dependencies) }}
|
||||
uses: ./.github/workflows/_dependencies.yml
|
||||
with:
|
||||
working-directory: ${{ matrix.job-configs.working-directory }}
|
||||
python-version: ${{ matrix.job-configs.python-version }}
|
||||
secrets: inherit
|
||||
|
||||
extended-tests:
|
||||
name: "cd ${{ matrix.job-configs.working-directory }} / make extended_tests #${{ matrix.job-configs.python-version }}"
|
||||
needs: [ build ]
|
||||
@@ -119,28 +110,31 @@ jobs:
|
||||
matrix:
|
||||
# note different variable for extended test dirs
|
||||
job-configs: ${{ fromJson(needs.build.outputs.extended-tests) }}
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ matrix.job-configs.working-directory }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.job-configs.python-version }} + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
- name: Set up Python ${{ matrix.job-configs.python-version }} + Poetry ${{ env.POETRY_VERSION }}
|
||||
uses: "./.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ matrix.job-configs.python-version }}
|
||||
poetry-version: ${{ env.POETRY_VERSION }}
|
||||
working-directory: ${{ matrix.job-configs.working-directory }}
|
||||
cache-key: extended
|
||||
|
||||
- name: Install dependencies and run extended tests
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Running extended tests, installing dependencies with uv..."
|
||||
uv venv
|
||||
uv sync --group test
|
||||
VIRTUAL_ENV=.venv uv pip install -r extended_testing_deps.txt
|
||||
VIRTUAL_ENV=.venv make extended_tests
|
||||
echo "Running extended tests, installing dependencies with poetry..."
|
||||
poetry install --with test
|
||||
poetry run pip install uv
|
||||
poetry run uv pip install -r extended_testing_deps.txt
|
||||
|
||||
- name: Run extended tests
|
||||
run: make extended_tests
|
||||
|
||||
- name: Ensure the tests did not create any additional files
|
||||
shell: bash
|
||||
@@ -155,7 +149,7 @@ jobs:
|
||||
echo "$STATUS" | grep 'nothing to commit, working tree clean'
|
||||
ci_success:
|
||||
name: "CI Success"
|
||||
needs: [build, lint, test, compile-integration-tests, extended-tests, test-doc-imports, test-pydantic]
|
||||
needs: [build, lint, test, compile-integration-tests, dependencies, extended-tests, test-doc-imports]
|
||||
if: |
|
||||
always()
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
3
.github/workflows/codespell.yml
vendored
3
.github/workflows/codespell.yml
vendored
@@ -3,8 +3,9 @@ name: CI / cd . / make spell_check
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, v0.1, v0.2]
|
||||
branches: [master, v0.1]
|
||||
pull_request:
|
||||
branches: [master, v0.1]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
14
.github/workflows/langchain_release_docker.yml
vendored
Normal file
14
.github/workflows/langchain_release_docker.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: docker/langchain/langchain Release
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Allows to trigger the workflow manually in GitHub UI
|
||||
workflow_call: # Allows triggering from another workflow
|
||||
|
||||
jobs:
|
||||
release:
|
||||
uses: ./.github/workflows/_release_docker.yml
|
||||
with:
|
||||
dockerfile: docker/Dockerfile.base
|
||||
image: langchain/langchain
|
||||
secrets: inherit
|
||||
2
.github/workflows/people.yml
vendored
2
.github/workflows/people.yml
vendored
@@ -14,7 +14,7 @@ on:
|
||||
|
||||
jobs:
|
||||
langchain-people:
|
||||
if: github.repository_owner == 'langchain-ai' || github.event_name != 'schedule'
|
||||
if: github.repository_owner == 'langchain-ai'
|
||||
runs-on: ubuntu-latest
|
||||
permissions: write-all
|
||||
steps:
|
||||
|
||||
71
.github/workflows/run_notebooks.yml
vendored
71
.github/workflows/run_notebooks.yml
vendored
@@ -1,71 +0,0 @@
|
||||
name: Run notebooks
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
python_version:
|
||||
description: 'Python version'
|
||||
required: false
|
||||
default: '3.11'
|
||||
working-directory:
|
||||
description: 'Working directory or subset (e.g., docs/docs/tutorials/llm_chain.ipynb or docs/docs/how_to)'
|
||||
required: false
|
||||
default: 'all'
|
||||
schedule:
|
||||
- cron: '0 13 * * *'
|
||||
|
||||
env:
|
||||
UV_FROZEN: "true"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'langchain-ai/langchain' || github.event_name != 'schedule'
|
||||
name: "Test docs"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python + uv
|
||||
uses: "./.github/actions/uv_setup"
|
||||
with:
|
||||
python-version: ${{ github.event.inputs.python_version || '3.11' }}
|
||||
|
||||
- name: 'Authenticate to Google Cloud'
|
||||
id: 'auth'
|
||||
uses: google-github-actions/auth@v2
|
||||
with:
|
||||
credentials_json: '${{ secrets.GOOGLE_CREDENTIALS }}'
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
uv sync --group dev --group test
|
||||
|
||||
- name: Pre-download files
|
||||
run: |
|
||||
uv run python docs/scripts/cache_data.py
|
||||
curl -s https://raw.githubusercontent.com/lerocha/chinook-database/master/ChinookDatabase/DataSources/Chinook_Sqlite.sql | sqlite3 docs/docs/how_to/Chinook.db
|
||||
cp docs/docs/how_to/Chinook.db docs/docs/tutorials/Chinook.db
|
||||
|
||||
- name: Prepare notebooks
|
||||
run: |
|
||||
uv run python docs/scripts/prepare_notebooks_for_ci.py --comment-install-cells --working-directory ${{ github.event.inputs.working-directory || 'all' }}
|
||||
|
||||
- name: Run notebooks
|
||||
env:
|
||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
|
||||
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
||||
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
TAVILY_API_KEY: ${{ secrets.TAVILY_API_KEY }}
|
||||
TOGETHER_API_KEY: ${{ secrets.TOGETHER_API_KEY }}
|
||||
WORKING_DIRECTORY: ${{ github.event.inputs.working-directory || 'all' }}
|
||||
run: |
|
||||
./docs/scripts/execute_notebooks.sh $WORKING_DIRECTORY
|
||||
81
.github/workflows/scheduled_test.yml
vendored
81
.github/workflows/scheduled_test.yml
vendored
@@ -2,62 +2,32 @@ name: Scheduled tests
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Allows to trigger the workflow manually in GitHub UI
|
||||
inputs:
|
||||
working-directory-force:
|
||||
type: string
|
||||
description: "From which folder this pipeline executes - defaults to all in matrix - example value: libs/partners/anthropic"
|
||||
python-version-force:
|
||||
type: string
|
||||
description: "Python version to use - defaults to 3.9 and 3.11 in matrix - example value: 3.9"
|
||||
schedule:
|
||||
- cron: '0 13 * * *'
|
||||
|
||||
env:
|
||||
POETRY_VERSION: "1.8.4"
|
||||
UV_FROZEN: "true"
|
||||
DEFAULT_LIBS: '["libs/partners/openai", "libs/partners/anthropic", "libs/partners/fireworks", "libs/partners/groq", "libs/partners/mistralai", "libs/partners/xai", "libs/partners/google-vertexai", "libs/partners/google-genai", "libs/partners/aws"]'
|
||||
POETRY_LIBS: ("libs/partners/google-vertexai" "libs/partners/google-genai" "libs/partners/aws")
|
||||
POETRY_VERSION: "1.7.1"
|
||||
|
||||
jobs:
|
||||
compute-matrix:
|
||||
if: github.repository_owner == 'langchain-ai' || github.event_name != 'schedule'
|
||||
runs-on: ubuntu-latest
|
||||
name: Compute matrix
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- name: Set matrix
|
||||
id: set-matrix
|
||||
env:
|
||||
DEFAULT_LIBS: ${{ env.DEFAULT_LIBS }}
|
||||
WORKING_DIRECTORY_FORCE: ${{ github.event.inputs.working-directory-force || '' }}
|
||||
PYTHON_VERSION_FORCE: ${{ github.event.inputs.python-version-force || '' }}
|
||||
run: |
|
||||
# echo "matrix=..." where matrix is a json formatted str with keys python-version and working-directory
|
||||
# python-version should default to 3.9 and 3.11, but is overridden to [PYTHON_VERSION_FORCE] if set
|
||||
# working-directory should default to DEFAULT_LIBS, but is overridden to [WORKING_DIRECTORY_FORCE] if set
|
||||
python_version='["3.9", "3.11"]'
|
||||
working_directory="$DEFAULT_LIBS"
|
||||
if [ -n "$PYTHON_VERSION_FORCE" ]; then
|
||||
python_version="[\"$PYTHON_VERSION_FORCE\"]"
|
||||
fi
|
||||
if [ -n "$WORKING_DIRECTORY_FORCE" ]; then
|
||||
working_directory="[\"$WORKING_DIRECTORY_FORCE\"]"
|
||||
fi
|
||||
matrix="{\"python-version\": $python_version, \"working-directory\": $working_directory}"
|
||||
echo $matrix
|
||||
echo "matrix=$matrix" >> $GITHUB_OUTPUT
|
||||
build:
|
||||
if: github.repository_owner == 'langchain-ai' || github.event_name != 'schedule'
|
||||
if: github.repository_owner == 'langchain-ai'
|
||||
name: Python ${{ matrix.python-version }} - ${{ matrix.working-directory }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: [compute-matrix]
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ${{ fromJSON(needs.compute-matrix.outputs.matrix).python-version }}
|
||||
working-directory: ${{ fromJSON(needs.compute-matrix.outputs.matrix).working-directory }}
|
||||
python-version:
|
||||
- "3.8"
|
||||
- "3.11"
|
||||
working-directory:
|
||||
- "libs/partners/openai"
|
||||
- "libs/partners/anthropic"
|
||||
- "libs/partners/fireworks"
|
||||
- "libs/partners/groq"
|
||||
- "libs/partners/mistralai"
|
||||
- "libs/partners/google-vertexai"
|
||||
- "libs/partners/google-genai"
|
||||
- "libs/partners/aws"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -81,8 +51,7 @@ jobs:
|
||||
mv langchain-google/libs/vertexai langchain/libs/partners/google-vertexai
|
||||
mv langchain-aws/libs/aws langchain/libs/partners/aws
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }} with poetry
|
||||
if: contains(env.POETRY_LIBS, matrix.working-directory)
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: "./langchain/.github/actions/poetry_setup"
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
@@ -90,12 +59,6 @@ jobs:
|
||||
working-directory: langchain/${{ matrix.working-directory }}
|
||||
cache-key: scheduled
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }} + uv
|
||||
if: "!contains(env.POETRY_LIBS, matrix.working-directory)"
|
||||
uses: "./langchain/.github/actions/uv_setup"
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: 'Authenticate to Google Cloud'
|
||||
id: 'auth'
|
||||
uses: google-github-actions/auth@v2
|
||||
@@ -109,20 +72,12 @@ jobs:
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
|
||||
- name: Install dependencies (poetry)
|
||||
if: contains(env.POETRY_LIBS, matrix.working-directory)
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
echo "Running scheduled tests, installing dependencies with poetry..."
|
||||
cd langchain/${{ matrix.working-directory }}
|
||||
poetry install --with=test_integration,test
|
||||
|
||||
- name: Install dependencies (uv)
|
||||
if: "!contains(env.POETRY_LIBS, matrix.working-directory)"
|
||||
run: |
|
||||
echo "Running scheduled tests, installing dependencies with uv..."
|
||||
cd langchain/${{ matrix.working-directory }}
|
||||
uv sync --group test --group test_integration
|
||||
|
||||
- name: Run integration tests
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
@@ -131,15 +86,11 @@ jobs:
|
||||
AZURE_OPENAI_API_BASE: ${{ secrets.AZURE_OPENAI_API_BASE }}
|
||||
AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }}
|
||||
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_CHAT_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LEGACY_CHAT_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_LLM_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_LLM_DEPLOYMENT_NAME }}
|
||||
AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME: ${{ secrets.AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME }}
|
||||
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
||||
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
|
||||
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
||||
HUGGINGFACEHUB_API_TOKEN: ${{ secrets.HUGGINGFACEHUB_API_TOKEN }}
|
||||
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
|
||||
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
|
||||
COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
|
||||
NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }}
|
||||
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: core
|
||||
name: format core
|
||||
language: system
|
||||
entry: make -C libs/core format
|
||||
files: ^libs/core/
|
||||
pass_filenames: false
|
||||
- id: community
|
||||
name: format community
|
||||
language: system
|
||||
entry: make -C libs/community format
|
||||
files: ^libs/community/
|
||||
pass_filenames: false
|
||||
- id: langchain
|
||||
name: format langchain
|
||||
language: system
|
||||
entry: make -C libs/langchain format
|
||||
files: ^libs/langchain/
|
||||
pass_filenames: false
|
||||
- id: standard-tests
|
||||
name: format standard-tests
|
||||
language: system
|
||||
entry: make -C libs/standard-tests format
|
||||
files: ^libs/standard-tests/
|
||||
pass_filenames: false
|
||||
- id: text-splitters
|
||||
name: format text-splitters
|
||||
language: system
|
||||
entry: make -C libs/text-splitters format
|
||||
files: ^libs/text-splitters/
|
||||
pass_filenames: false
|
||||
- id: anthropic
|
||||
name: format partners/anthropic
|
||||
language: system
|
||||
entry: make -C libs/partners/anthropic format
|
||||
files: ^libs/partners/anthropic/
|
||||
pass_filenames: false
|
||||
- id: chroma
|
||||
name: format partners/chroma
|
||||
language: system
|
||||
entry: make -C libs/partners/chroma format
|
||||
files: ^libs/partners/chroma/
|
||||
pass_filenames: false
|
||||
- id: couchbase
|
||||
name: format partners/couchbase
|
||||
language: system
|
||||
entry: make -C libs/partners/couchbase format
|
||||
files: ^libs/partners/couchbase/
|
||||
pass_filenames: false
|
||||
- id: exa
|
||||
name: format partners/exa
|
||||
language: system
|
||||
entry: make -C libs/partners/exa format
|
||||
files: ^libs/partners/exa/
|
||||
pass_filenames: false
|
||||
- id: fireworks
|
||||
name: format partners/fireworks
|
||||
language: system
|
||||
entry: make -C libs/partners/fireworks format
|
||||
files: ^libs/partners/fireworks/
|
||||
pass_filenames: false
|
||||
- id: groq
|
||||
name: format partners/groq
|
||||
language: system
|
||||
entry: make -C libs/partners/groq format
|
||||
files: ^libs/partners/groq/
|
||||
pass_filenames: false
|
||||
- id: huggingface
|
||||
name: format partners/huggingface
|
||||
language: system
|
||||
entry: make -C libs/partners/huggingface format
|
||||
files: ^libs/partners/huggingface/
|
||||
pass_filenames: false
|
||||
- id: mistralai
|
||||
name: format partners/mistralai
|
||||
language: system
|
||||
entry: make -C libs/partners/mistralai format
|
||||
files: ^libs/partners/mistralai/
|
||||
pass_filenames: false
|
||||
- id: nomic
|
||||
name: format partners/nomic
|
||||
language: system
|
||||
entry: make -C libs/partners/nomic format
|
||||
files: ^libs/partners/nomic/
|
||||
pass_filenames: false
|
||||
- id: ollama
|
||||
name: format partners/ollama
|
||||
language: system
|
||||
entry: make -C libs/partners/ollama format
|
||||
files: ^libs/partners/ollama/
|
||||
pass_filenames: false
|
||||
- id: openai
|
||||
name: format partners/openai
|
||||
language: system
|
||||
entry: make -C libs/partners/openai format
|
||||
files: ^libs/partners/openai/
|
||||
pass_filenames: false
|
||||
- id: prompty
|
||||
name: format partners/prompty
|
||||
language: system
|
||||
entry: make -C libs/partners/prompty format
|
||||
files: ^libs/partners/prompty/
|
||||
pass_filenames: false
|
||||
- id: qdrant
|
||||
name: format partners/qdrant
|
||||
language: system
|
||||
entry: make -C libs/partners/qdrant format
|
||||
files: ^libs/partners/qdrant/
|
||||
pass_filenames: false
|
||||
- id: voyageai
|
||||
name: format partners/voyageai
|
||||
language: system
|
||||
entry: make -C libs/partners/voyageai format
|
||||
files: ^libs/partners/voyageai/
|
||||
pass_filenames: false
|
||||
- id: root
|
||||
name: format docs, cookbook
|
||||
language: system
|
||||
entry: make format
|
||||
files: ^(docs|cookbook)/
|
||||
pass_filenames: false
|
||||
73
MIGRATE.md
73
MIGRATE.md
@@ -1,11 +1,70 @@
|
||||
# Migrating
|
||||
|
||||
Please see the following guides for migrating LangChain code:
|
||||
## 🚨Breaking Changes for select chains (SQLDatabase) on 7/28/23
|
||||
|
||||
* Migrate to [LangChain v0.3](https://python.langchain.com/docs/versions/v0_3/)
|
||||
* Migrate to [LangChain v0.2](https://python.langchain.com/docs/versions/v0_2/)
|
||||
* Migrating from [LangChain 0.0.x Chains](https://python.langchain.com/docs/versions/migrating_chains/)
|
||||
* Upgrade to [LangGraph Memory](https://python.langchain.com/docs/versions/migrating_memory/)
|
||||
In an effort to make `langchain` leaner and safer, we are moving select chains to `langchain_experimental`.
|
||||
This migration has already started, but we are remaining backwards compatible until 7/28.
|
||||
On that date, we will remove functionality from `langchain`.
|
||||
Read more about the motivation and the progress [here](https://github.com/langchain-ai/langchain/discussions/8043).
|
||||
|
||||
The [LangChain CLI](https://python.langchain.com/docs/versions/v0_3/#migrate-using-langchain-cli) can help you automatically upgrade your code to use non-deprecated imports.
|
||||
This will be especially helpful if you're still on either version 0.0.x or 0.1.x of LangChain.
|
||||
### Migrating to `langchain_experimental`
|
||||
|
||||
We are moving any experimental components of LangChain, or components with vulnerability issues, into `langchain_experimental`.
|
||||
This guide covers how to migrate.
|
||||
|
||||
### Installation
|
||||
|
||||
Previously:
|
||||
|
||||
`pip install -U langchain`
|
||||
|
||||
Now (only if you want to access things in experimental):
|
||||
|
||||
`pip install -U langchain langchain_experimental`
|
||||
|
||||
### Things in `langchain.experimental`
|
||||
|
||||
Previously:
|
||||
|
||||
`from langchain.experimental import ...`
|
||||
|
||||
Now:
|
||||
|
||||
`from langchain_experimental import ...`
|
||||
|
||||
### PALChain
|
||||
|
||||
Previously:
|
||||
|
||||
`from langchain.chains import PALChain`
|
||||
|
||||
Now:
|
||||
|
||||
`from langchain_experimental.pal_chain import PALChain`
|
||||
|
||||
### SQLDatabaseChain
|
||||
|
||||
Previously:
|
||||
|
||||
`from langchain.chains import SQLDatabaseChain`
|
||||
|
||||
Now:
|
||||
|
||||
`from langchain_experimental.sql import SQLDatabaseChain`
|
||||
|
||||
Alternatively, if you are just interested in using the query generation part of the SQL chain, you can check out this [`SQL question-answering tutorial`](https://python.langchain.com/v0.2/docs/tutorials/sql_qa/#convert-question-to-sql-query)
|
||||
|
||||
`from langchain.chains import create_sql_query_chain`
|
||||
|
||||
### `load_prompt` for Python files
|
||||
|
||||
Note: this only applies if you want to load Python files as prompts.
|
||||
If you want to load json/yaml files, no change is needed.
|
||||
|
||||
Previously:
|
||||
|
||||
`from langchain.prompts import load_prompt`
|
||||
|
||||
Now:
|
||||
|
||||
`from langchain_experimental.prompts import load_prompt`
|
||||
|
||||
44
Makefile
44
Makefile
@@ -1,9 +1,5 @@
|
||||
.PHONY: all clean help docs_build docs_clean docs_linkcheck api_docs_build api_docs_clean api_docs_linkcheck spell_check spell_fix lint lint_package lint_tests format format_diff
|
||||
|
||||
.EXPORT_ALL_VARIABLES:
|
||||
UV_FROZEN = true
|
||||
UV_NO_SYNC = true
|
||||
|
||||
## help: Show this help info.
|
||||
help: Makefile
|
||||
@printf "\n\033[1mUsage: make <TARGETS> ...\033[0m\n\n\033[1mTargets:\033[0m\n\n"
|
||||
@@ -29,20 +25,21 @@ docs_clean:
|
||||
|
||||
## docs_linkcheck: Run linkchecker on the documentation.
|
||||
docs_linkcheck:
|
||||
uv run --no-group test linkchecker _dist/docs/ --ignore-url node_modules
|
||||
poetry run linkchecker _dist/docs/ --ignore-url node_modules
|
||||
|
||||
## api_docs_build: Build the API Reference documentation.
|
||||
api_docs_build:
|
||||
uv run --no-group test python docs/api_reference/create_api_rst.py
|
||||
cd docs/api_reference && uv run --no-group test make html
|
||||
uv run --no-group test python docs/api_reference/scripts/custom_formatter.py docs/api_reference/_build/html/
|
||||
poetry run python docs/api_reference/create_api_rst.py
|
||||
cd docs/api_reference && poetry run make html
|
||||
poetry run python docs/api_reference/scripts/custom_formatter.py docs/api_reference/_build/html/
|
||||
|
||||
API_PKG ?= text-splitters
|
||||
|
||||
api_docs_quick_preview:
|
||||
uv run --no-group test python docs/api_reference/create_api_rst.py $(API_PKG)
|
||||
cd docs/api_reference && uv run make html
|
||||
uv run --no-group test python docs/api_reference/scripts/custom_formatter.py docs/api_reference/_build/html/
|
||||
poetry run pip install "pydantic<2"
|
||||
poetry run python docs/api_reference/create_api_rst.py $(API_PKG)
|
||||
cd docs/api_reference && poetry run make html
|
||||
poetry run python docs/api_reference/scripts/custom_formatter.py docs/api_reference/_build/html/
|
||||
open docs/api_reference/_build/html/reference.html
|
||||
|
||||
## api_docs_clean: Clean the API Reference documentation build artifacts.
|
||||
@@ -54,15 +51,15 @@ api_docs_clean:
|
||||
|
||||
## api_docs_linkcheck: Run linkchecker on the API Reference documentation.
|
||||
api_docs_linkcheck:
|
||||
uv run --no-group test linkchecker docs/api_reference/_build/html/index.html
|
||||
poetry run linkchecker docs/api_reference/_build/html/index.html
|
||||
|
||||
## spell_check: Run codespell on the project.
|
||||
spell_check:
|
||||
uv run --no-group test codespell --toml pyproject.toml
|
||||
poetry run codespell --toml pyproject.toml
|
||||
|
||||
## spell_fix: Run codespell on the project and fix the errors.
|
||||
spell_fix:
|
||||
uv run --no-group test codespell --toml pyproject.toml -w
|
||||
poetry run codespell --toml pyproject.toml -w
|
||||
|
||||
######################
|
||||
# LINTING AND FORMATTING
|
||||
@@ -70,19 +67,12 @@ spell_fix:
|
||||
|
||||
## lint: Run linting on the project.
|
||||
lint lint_package lint_tests:
|
||||
uv run --group lint ruff check docs cookbook
|
||||
uv run --group lint ruff format docs cookbook cookbook --diff
|
||||
uv run --group lint ruff check --select I docs cookbook
|
||||
git --no-pager grep 'from langchain import' docs cookbook | grep -vE 'from langchain import (hub)' && echo "Error: no importing langchain from root in docs, except for hub" && exit 1 || exit 0
|
||||
|
||||
git --no-pager grep 'api.python.langchain.com' -- docs/docs ':!docs/docs/additional_resources/arxiv_references.mdx' ':!docs/docs/integrations/document_loaders/sitemap.ipynb' || exit 0 && \
|
||||
echo "Error: you should link python.langchain.com/api_reference, not api.python.langchain.com in the docs" && \
|
||||
exit 1
|
||||
poetry run ruff check docs templates cookbook
|
||||
poetry run ruff format docs templates cookbook --diff
|
||||
poetry run ruff check --select I docs templates cookbook
|
||||
git grep 'from langchain import' docs/docs templates cookbook | grep -vE 'from langchain import (hub)' && exit 1 || exit 0
|
||||
|
||||
## format: Format the project files.
|
||||
format format_diff:
|
||||
uv run --group lint ruff format docs cookbook
|
||||
uv run --group lint ruff check --select I --fix docs cookbook
|
||||
|
||||
update-package-downloads:
|
||||
uv run python docs/scripts/packages_yml_get_downloads.py
|
||||
poetry run ruff format docs templates cookbook
|
||||
poetry run ruff check --select I --fix docs templates cookbook
|
||||
|
||||
75
README.md
75
README.md
@@ -38,21 +38,18 @@ conda install langchain -c conda-forge
|
||||
|
||||
For these applications, LangChain simplifies the entire application lifecycle:
|
||||
|
||||
|
||||
- **Open-source libraries**: Build your applications using LangChain's open-source
|
||||
[components](https://python.langchain.com/docs/concepts/) and
|
||||
[third-party integrations](https://python.langchain.com/docs/integrations/providers/).
|
||||
Use [LangGraph](https://langchain-ai.github.io/langgraph/) to build stateful agents with first-class streaming and human-in-the-loop support.
|
||||
- **Open-source libraries**: Build your applications using LangChain's open-source [building blocks](https://python.langchain.com/v0.2/docs/concepts#langchain-expression-language-lcel), [components](https://python.langchain.com/v0.2/docs/concepts), and [third-party integrations](https://python.langchain.com/v0.2/docs/integrations/platforms/).
|
||||
Use [LangGraph](/docs/concepts/#langgraph) to build stateful agents with first-class streaming and human-in-the-loop support.
|
||||
- **Productionization**: Inspect, monitor, and evaluate your apps with [LangSmith](https://docs.smith.langchain.com/) so that you can constantly optimize and deploy with confidence.
|
||||
- **Deployment**: Turn your LangGraph applications into production-ready APIs and Assistants with [LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/).
|
||||
- **Deployment**: Turn your LangGraph applications into production-ready APIs and Assistants with [LangGraph Cloud](https://langchain-ai.github.io/langgraph/cloud/).
|
||||
|
||||
### Open-source libraries
|
||||
|
||||
- **`langchain-core`**: Base abstractions.
|
||||
- **Integration packages** (e.g. **`langchain-openai`**, **`langchain-anthropic`**, etc.): Important integrations have been split into lightweight packages that are co-maintained by the LangChain team and the integration developers.
|
||||
- **`langchain-core`**: Base abstractions and LangChain Expression Language.
|
||||
- **`langchain-community`**: Third party integrations.
|
||||
- Some integrations have been further split into **partner packages** that only rely on **`langchain-core`**. Examples include **`langchain_openai`** and **`langchain_anthropic`**.
|
||||
- **`langchain`**: Chains, agents, and retrieval strategies that make up an application's cognitive architecture.
|
||||
- **`langchain-community`**: Third-party integrations that are community maintained.
|
||||
- **[LangGraph](https://langchain-ai.github.io/langgraph)**: LangGraph powers production-grade agents, trusted by Linkedin, Uber, Klarna, GitLab, and many more. Build robust and stateful multi-actor applications with LLMs by modeling steps as edges and nodes in a graph. Integrates smoothly with LangChain, but can be used without it. To learn more about LangGraph, check out our first LangChain Academy course, *Introduction to LangGraph*, available [here](https://academy.langchain.com/courses/intro-to-langgraph).
|
||||
- **[`LangGraph`](https://langchain-ai.github.io/langgraph/)**: A library for building robust and stateful multi-actor applications with LLMs by modeling steps as edges and nodes in a graph. Integrates smoothly with LangChain, but can be used without it.
|
||||
|
||||
### Productionization:
|
||||
|
||||
@@ -60,40 +57,46 @@ For these applications, LangChain simplifies the entire application lifecycle:
|
||||
|
||||
### Deployment:
|
||||
|
||||
- **[LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/)**: Turn your LangGraph applications into production-ready APIs and Assistants.
|
||||
- **[LangGraph Cloud](https://langchain-ai.github.io/langgraph/cloud/)**: Turn your LangGraph applications into production-ready APIs and Assistants.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## 🧱 What can you build with LangChain?
|
||||
|
||||
**❓ Question answering with RAG**
|
||||
|
||||
- [Documentation](https://python.langchain.com/docs/tutorials/rag/)
|
||||
- [Documentation](https://python.langchain.com/v0.2/docs/tutorials/rag/)
|
||||
- End-to-end Example: [Chat LangChain](https://chat.langchain.com) and [repo](https://github.com/langchain-ai/chat-langchain)
|
||||
|
||||
**🧱 Extracting structured output**
|
||||
|
||||
- [Documentation](https://python.langchain.com/docs/tutorials/extraction/)
|
||||
- End-to-end Example: [LangChain Extract](https://github.com/langchain-ai/langchain-extract/)
|
||||
- [Documentation](https://python.langchain.com/v0.2/docs/tutorials/extraction/)
|
||||
- End-to-end Example: [SQL Llama2 Template](https://github.com/langchain-ai/langchain-extract/)
|
||||
|
||||
**🤖 Chatbots**
|
||||
|
||||
- [Documentation](https://python.langchain.com/docs/tutorials/chatbot/)
|
||||
- [Documentation](https://python.langchain.com/v0.2/docs/tutorials/chatbot/)
|
||||
- End-to-end Example: [Web LangChain (web researcher chatbot)](https://weblangchain.vercel.app) and [repo](https://github.com/langchain-ai/weblangchain)
|
||||
|
||||
And much more! Head to the [Tutorials](https://python.langchain.com/docs/tutorials/) section of the docs for more.
|
||||
And much more! Head to the [Tutorials](https://python.langchain.com/v0.2/docs/tutorials/) section of the docs for more.
|
||||
|
||||
## 🚀 How does LangChain help?
|
||||
|
||||
The main value props of the LangChain libraries are:
|
||||
|
||||
1. **Components**: composable building blocks, tools and integrations for working with language models. Components are modular and easy-to-use, whether you are using the rest of the LangChain framework or not.
|
||||
2. **Easy orchestration with LangGraph**: [LangGraph](https://langchain-ai.github.io/langgraph/),
|
||||
built on top of `langchain-core`, has built-in support for [messages](https://python.langchain.com/docs/concepts/messages/), [tools](https://python.langchain.com/docs/concepts/tools/),
|
||||
and other LangChain abstractions. This makes it easy to combine components into
|
||||
production-ready applications with persistence, streaming, and other key features.
|
||||
Check out the LangChain [tutorials page](https://python.langchain.com/docs/tutorials/#orchestration) for examples.
|
||||
1. **Components**: composable building blocks, tools and integrations for working with language models. Components are modular and easy-to-use, whether you are using the rest of the LangChain framework or not
|
||||
2. **Off-the-shelf chains**: built-in assemblages of components for accomplishing higher-level tasks
|
||||
|
||||
Off-the-shelf chains make it easy to get started. Components make it easy to customize existing chains and build new ones.
|
||||
|
||||
## LangChain Expression Language (LCEL)
|
||||
|
||||
LCEL is a key part of LangChain, allowing you to build and organize chains of processes in a straightforward, declarative manner. It was designed to support taking prototypes directly into production without needing to alter any code. This means you can use LCEL to set up everything from basic "prompt + LLM" setups to intricate, multi-step workflows.
|
||||
|
||||
- **[Overview](https://python.langchain.com/v0.2/docs/concepts/#langchain-expression-language-lcel)**: LCEL and its benefits
|
||||
- **[Interface](https://python.langchain.com/v0.2/docs/concepts/#runnable-interface)**: The standard Runnable interface for LCEL objects
|
||||
- **[Primitives](https://python.langchain.com/v0.2/docs/how_to/#langchain-expression-language-lcel)**: More on the primitives LCEL includes
|
||||
- **[Cheatsheet](https://python.langchain.com/v0.2/docs/how_to/lcel_cheatsheet/)**: Quick overview of the most common usage patterns
|
||||
|
||||
## Components
|
||||
|
||||
@@ -101,41 +104,37 @@ Components fall into the following **modules**:
|
||||
|
||||
**📃 Model I/O**
|
||||
|
||||
This includes [prompt management](https://python.langchain.com/docs/concepts/prompt_templates/)
|
||||
and a generic interface for [chat models](https://python.langchain.com/docs/concepts/chat_models/), including a consistent interface for [tool-calling](https://python.langchain.com/docs/concepts/tool_calling/) and [structured output](https://python.langchain.com/docs/concepts/structured_outputs/) across model providers.
|
||||
This includes [prompt management](https://python.langchain.com/v0.2/docs/concepts/#prompt-templates), [prompt optimization](https://python.langchain.com/v0.2/docs/concepts/#example-selectors), a generic interface for [chat models](https://python.langchain.com/v0.2/docs/concepts/#chat-models) and [LLMs](https://python.langchain.com/v0.2/docs/concepts/#llms), and common utilities for working with [model outputs](https://python.langchain.com/v0.2/docs/concepts/#output-parsers).
|
||||
|
||||
**📚 Retrieval**
|
||||
|
||||
Retrieval Augmented Generation involves [loading data](https://python.langchain.com/docs/concepts/document_loaders/) from a variety of sources, [preparing it](https://python.langchain.com/docs/concepts/text_splitters/), then [searching over (a.k.a. retrieving from)](https://python.langchain.com/docs/concepts/retrievers/) it for use in the generation step.
|
||||
Retrieval Augmented Generation involves [loading data](https://python.langchain.com/v0.2/docs/concepts/#document-loaders) from a variety of sources, [preparing it](https://python.langchain.com/v0.2/docs/concepts/#text-splitters), then [searching over (a.k.a. retrieving from)](https://python.langchain.com/v0.2/docs/concepts/#retrievers) it for use in the generation step.
|
||||
|
||||
**🤖 Agents**
|
||||
|
||||
Agents allow an LLM autonomy over how a task is accomplished. Agents make decisions about which Actions to take, then take that Action, observe the result, and repeat until the task is complete. [LangGraph](https://langchain-ai.github.io/langgraph/) makes it easy to use
|
||||
LangChain components to build both [custom](https://langchain-ai.github.io/langgraph/tutorials/)
|
||||
and [built-in](https://langchain-ai.github.io/langgraph/how-tos/create-react-agent/)
|
||||
LLM agents.
|
||||
Agents allow an LLM autonomy over how a task is accomplished. Agents make decisions about which Actions to take, then take that Action, observe the result, and repeat until the task is complete. LangChain provides a [standard interface for agents](https://python.langchain.com/v0.2/docs/concepts/#agents), along with [LangGraph](https://github.com/langchain-ai/langgraph) for building custom agents.
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
Please see [here](https://python.langchain.com) for full documentation, which includes:
|
||||
|
||||
- [Introduction](https://python.langchain.com/docs/introduction/): Overview of the framework and the structure of the docs.
|
||||
- [Tutorials](https://python.langchain.com/docs/tutorials/): If you're looking to build something specific or are more of a hands-on learner, check out our tutorials. This is the best place to get started.
|
||||
- [How-to guides](https://python.langchain.com/docs/how_to/): Answers to “How do I….?” type questions. These guides are goal-oriented and concrete; they're meant to help you complete a specific task.
|
||||
- [Conceptual guide](https://python.langchain.com/docs/concepts/): Conceptual explanations of the key parts of the framework.
|
||||
- [API Reference](https://python.langchain.com/api_reference/): Thorough documentation of every class and method.
|
||||
- [Introduction](https://python.langchain.com/v0.2/docs/introduction/): Overview of the framework and the structure of the docs.
|
||||
- [Tutorials](https://python.langchain.com/docs/use_cases/): If you're looking to build something specific or are more of a hands-on learner, check out our tutorials. This is the best place to get started.
|
||||
- [How-to guides](https://python.langchain.com/v0.2/docs/how_to/): Answers to “How do I….?” type questions. These guides are goal-oriented and concrete; they're meant to help you complete a specific task.
|
||||
- [Conceptual guide](https://python.langchain.com/v0.2/docs/concepts/): Conceptual explanations of the key parts of the framework.
|
||||
- [API Reference](https://api.python.langchain.com): Thorough documentation of every class and method.
|
||||
|
||||
## 🌐 Ecosystem
|
||||
|
||||
- [🦜🛠️ LangSmith](https://docs.smith.langchain.com/): Trace and evaluate your language model applications and intelligent agents to help you move from prototype to production.
|
||||
- [🦜🕸️ LangGraph](https://langchain-ai.github.io/langgraph/): Create stateful, multi-actor applications with LLMs. Integrates smoothly with LangChain, but can be used without it.
|
||||
- [🦜🕸️ LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/#langgraph-platform): Deploy LLM applications built with LangGraph into production.
|
||||
- [🦜🏓 LangServe](https://python.langchain.com/docs/langserve): Deploy LangChain runnables and chains as REST APIs.
|
||||
|
||||
## 💁 Contributing
|
||||
|
||||
As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
|
||||
|
||||
For detailed information on how to contribute, see [here](https://python.langchain.com/docs/contributing/).
|
||||
For detailed information on how to contribute, see [here](https://python.langchain.com/v0.2/docs/contributing/).
|
||||
|
||||
## 🌟 Contributors
|
||||
|
||||
|
||||
37
SECURITY.md
37
SECURITY.md
@@ -1,30 +1,5 @@
|
||||
# Security Policy
|
||||
|
||||
LangChain has a large ecosystem of integrations with various external resources like local and remote file systems, APIs and databases. These integrations allow developers to create versatile applications that combine the power of LLMs with the ability to access, interact with and manipulate external resources.
|
||||
|
||||
## Best practices
|
||||
|
||||
When building such applications developers should remember to follow good security practices:
|
||||
|
||||
* [**Limit Permissions**](https://en.wikipedia.org/wiki/Principle_of_least_privilege): Scope permissions specifically to the application's need. Granting broad or excessive permissions can introduce significant security vulnerabilities. To avoid such vulnerabilities, consider using read-only credentials, disallowing access to sensitive resources, using sandboxing techniques (such as running inside a container), specifying proxy configurations to control external requests, etc. as appropriate for your application.
|
||||
* **Anticipate Potential Misuse**: Just as humans can err, so can Large Language Models (LLMs). Always assume that any system access or credentials may be used in any way allowed by the permissions they are assigned. For example, if a pair of database credentials allows deleting data, it’s safest to assume that any LLM able to use those credentials may in fact delete data.
|
||||
* [**Defense in Depth**](https://en.wikipedia.org/wiki/Defense_in_depth_(computing)): No security technique is perfect. Fine-tuning and good chain design can reduce, but not eliminate, the odds that a Large Language Model (LLM) may make a mistake. It’s best to combine multiple layered security approaches rather than relying on any single layer of defense to ensure security. For example: use both read-only permissions and sandboxing to ensure that LLMs are only able to access data that is explicitly meant for them to use.
|
||||
|
||||
Risks of not doing so include, but are not limited to:
|
||||
* Data corruption or loss.
|
||||
* Unauthorized access to confidential information.
|
||||
* Compromised performance or availability of critical resources.
|
||||
|
||||
Example scenarios with mitigation strategies:
|
||||
|
||||
* A user may ask an agent with access to the file system to delete files that should not be deleted or read the content of files that contain sensitive information. To mitigate, limit the agent to only use a specific directory and only allow it to read or write files that are safe to read or write. Consider further sandboxing the agent by running it in a container.
|
||||
* A user may ask an agent with write access to an external API to write malicious data to the API, or delete data from that API. To mitigate, give the agent read-only API keys, or limit it to only use endpoints that are already resistant to such misuse.
|
||||
* A user may ask an agent with access to a database to drop a table or mutate the schema. To mitigate, scope the credentials to only the tables that the agent needs to access and consider issuing READ-ONLY credentials.
|
||||
|
||||
If you're building applications that access external resources like file systems, APIs
|
||||
or databases, consider speaking with your company's security team to determine how to best
|
||||
design and secure your applications.
|
||||
|
||||
## Reporting OSS Vulnerabilities
|
||||
|
||||
LangChain is partnered with [huntr by Protect AI](https://huntr.com/) to provide
|
||||
@@ -39,7 +14,7 @@ Before reporting a vulnerability, please review:
|
||||
|
||||
1) In-Scope Targets and Out-of-Scope Targets below.
|
||||
2) The [langchain-ai/langchain](https://python.langchain.com/docs/contributing/repo_structure) monorepo structure.
|
||||
3) The [Best practicies](#best-practices) above to
|
||||
3) LangChain [security guidelines](https://python.langchain.com/docs/security) to
|
||||
understand what we consider to be a security vulnerability vs. developer
|
||||
responsibility.
|
||||
|
||||
@@ -58,13 +33,13 @@ The following packages and repositories are eligible for bug bounties:
|
||||
All out of scope targets defined by huntr as well as:
|
||||
|
||||
- **langchain-experimental**: This repository is for experimental code and is not
|
||||
eligible for bug bounties (see [package warning](https://pypi.org/project/langchain-experimental/)), bug reports to it will be marked as interesting or waste of
|
||||
eligible for bug bounties, bug reports to it will be marked as interesting or waste of
|
||||
time and published with no bounty attached.
|
||||
- **tools**: Tools in either langchain or langchain-community are not eligible for bug
|
||||
bounties. This includes the following directories
|
||||
- libs/langchain/langchain/tools
|
||||
- libs/community/langchain_community/tools
|
||||
- Please review the [best practices](#best-practices)
|
||||
- langchain/tools
|
||||
- langchain-community/tools
|
||||
- Please review our [security guidelines](https://python.langchain.com/docs/security)
|
||||
for more details, but generally tools interact with the real world. Developers are
|
||||
expected to understand the security implications of their code and are responsible
|
||||
for the security of their tools.
|
||||
@@ -72,7 +47,7 @@ All out of scope targets defined by huntr as well as:
|
||||
case basis, but likely will not be eligible for a bounty as the code is already
|
||||
documented with guidelines for developers that should be followed for making their
|
||||
application secure.
|
||||
- Any LangSmith related repositories or APIs (see [Reporting LangSmith Vulnerabilities](#reporting-langsmith-vulnerabilities)).
|
||||
- Any LangSmith related repositories or APIs see below.
|
||||
|
||||
## Reporting LangSmith Vulnerabilities
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ Notebook | Description
|
||||
[code-analysis-deeplake.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/code-analysis-deeplake.ipynb) | Analyze its own code base with the help of gpt and activeloop's deep lake.
|
||||
[custom_agent_with_plugin_retri...](https://github.com/langchain-ai/langchain/tree/master/cookbook/custom_agent_with_plugin_retrieval.ipynb) | Build a custom agent that can interact with ai plugins by retrieving tools and creating natural language wrappers around openapi endpoints.
|
||||
[custom_agent_with_plugin_retri...](https://github.com/langchain-ai/langchain/tree/master/cookbook/custom_agent_with_plugin_retrieval_using_plugnplai.ipynb) | Build a custom agent with plugin retrieval functionality, utilizing ai plugins from the `plugnplai` directory.
|
||||
[databricks_sql_db.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/databricks_sql_db.ipynb) | Connect to databricks runtimes and databricks sql.
|
||||
[deeplake_semantic_search_over_...](https://github.com/langchain-ai/langchain/tree/master/cookbook/deeplake_semantic_search_over_chat.ipynb) | Perform semantic search and question-answering over a group chat using activeloop's deep lake with gpt4.
|
||||
[elasticsearch_db_qa.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/elasticsearch_db_qa.ipynb) | Interact with elasticsearch analytics databases in natural language and build search queries via the elasticsearch dsl API.
|
||||
[extraction_openai_tools.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/extraction_openai_tools.ipynb) | Structured Data Extraction with OpenAI Tools
|
||||
@@ -49,7 +50,7 @@ Notebook | Description
|
||||
[press_releases.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/press_releases.ipynb) | Retrieve and query company press release data powered by [Kay.ai](https://kay.ai).
|
||||
[program_aided_language_model.i...](https://github.com/langchain-ai/langchain/tree/master/cookbook/program_aided_language_model.ipynb) | Implement program-aided language models as described in the provided research paper.
|
||||
[qa_citations.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/qa_citations.ipynb) | Different ways to get a model to cite its sources.
|
||||
[rag_upstage_document_parse_groundedness_check.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/rag_upstage_document_parse_groundedness_check.ipynb) | End-to-end RAG example using Upstage Document Parse and Groundedness Check.
|
||||
[rag_upstage_layout_analysis_groundedness_check.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/rag_upstage_layout_analysis_groundedness_check.ipynb) | End-to-end RAG example using Upstage Layout Analysis and Groundedness Check.
|
||||
[retrieval_in_sql.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/retrieval_in_sql.ipynb) | Perform retrieval-augmented-generation (rag) on a PostgreSQL database using pgvector.
|
||||
[sales_agent_with_context.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/sales_agent_with_context.ipynb) | Implement a context-aware ai sales agent, salesgpt, that can have natural sales conversations, interact with other systems, and use a product knowledge base to discuss a company's offerings.
|
||||
[self_query_hotel_search.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/self_query_hotel_search.ipynb) | Build a hotel room search feature with self-querying retrieval, using a specific hotel recommendation dataset.
|
||||
@@ -61,6 +62,4 @@ Notebook | Description
|
||||
[wikibase_agent.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/wikibase_agent.ipynb) | Create a simple wikibase agent that utilizes sparql generation, with testing done on http://wikidata.org.
|
||||
[oracleai_demo.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/oracleai_demo.ipynb) | This guide outlines how to utilize Oracle AI Vector Search alongside Langchain for an end-to-end RAG pipeline, providing step-by-step examples. The process includes loading documents from various sources using OracleDocLoader, summarizing them either within or outside the database with OracleSummary, and generating embeddings similarly through OracleEmbeddings. It also covers chunking documents according to specific requirements using Advanced Oracle Capabilities from OracleTextSplitter, and finally, storing and indexing these documents in a Vector Store for querying with OracleVS.
|
||||
[rag-locally-on-intel-cpu.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/rag-locally-on-intel-cpu.ipynb) | Perform Retrieval-Augmented-Generation (RAG) on locally downloaded open-source models using langchain and open source tools and execute it on Intel Xeon CPU. We showed an example of how to apply RAG on Llama 2 model and enable it to answer the queries related to Intel Q1 2024 earnings release.
|
||||
[visual_RAG_vdms.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/visual_RAG_vdms.ipynb) | Performs Visual Retrieval-Augmented-Generation (RAG) using videos and scene descriptions generated by open source models.
|
||||
[contextual_rag.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/contextual_rag.ipynb) | Performs contextual retrieval-augmented generation (RAG) prepending chunk-specific explanatory context to each chunk before embedding.
|
||||
[rag-agents-locally-on-intel-cpu.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/local_rag_agents_intel_cpu.ipynb) | Build a RAG agent locally with open source models that routes questions through one of two paths to find answers. The agent generates answers based on documents retrieved from either the vector database or retrieved from web search. If the vector database lacks relevant information, the agent opts for web search. Open-source models for LLM and embeddings are used locally on an Intel Xeon CPU to execute this pipeline.
|
||||
[visual_RAG_vdms.ipynb](https://github.com/langchain-ai/langchain/tree/master/cookbook/visual_RAG_vdms.ipynb) | Performs Visual Retrieval-Augmented-Generation (RAG) using videos and scene descriptions generated by open source models.
|
||||
@@ -31,8 +31,8 @@
|
||||
"source": [
|
||||
"# Optional\n",
|
||||
"import os\n",
|
||||
"# os.environ['LANGSMITH_TRACING'] = 'true' # enables tracing\n",
|
||||
"# os.environ['LANGSMITH_API_KEY'] = <your-api-key>"
|
||||
"# os.environ['LANGCHAIN_TRACING_V2'] = 'true' # enables tracing\n",
|
||||
"# os.environ['LANGCHAIN_API_KEY'] = <your-api-key>"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -90,8 +90,7 @@
|
||||
"import os\n",
|
||||
"from getpass import getpass\n",
|
||||
"\n",
|
||||
"if \"OPENAI_API_KEY\" not in os.environ:\n",
|
||||
" os.environ[\"OPENAI_API_KEY\"] = getpass()\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = getpass()\n",
|
||||
"# Please manually enter OpenAI Key"
|
||||
]
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
273
cookbook/databricks_sql_db.ipynb
Normal file
273
cookbook/databricks_sql_db.ipynb
Normal file
@@ -0,0 +1,273 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "707d13a7",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Databricks\n",
|
||||
"\n",
|
||||
"This notebook covers how to connect to the [Databricks runtimes](https://docs.databricks.com/runtime/index.html) and [Databricks SQL](https://www.databricks.com/product/databricks-sql) using the SQLDatabase wrapper of LangChain.\n",
|
||||
"It is broken into 3 parts: installation and setup, connecting to Databricks, and examples."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0076d072",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Installation and Setup"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "739b489b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install databricks-sql-connector"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "73113163",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Connecting to Databricks\n",
|
||||
"\n",
|
||||
"You can connect to [Databricks runtimes](https://docs.databricks.com/runtime/index.html) and [Databricks SQL](https://www.databricks.com/product/databricks-sql) using the `SQLDatabase.from_databricks()` method.\n",
|
||||
"\n",
|
||||
"### Syntax\n",
|
||||
"```python\n",
|
||||
"SQLDatabase.from_databricks(\n",
|
||||
" catalog: str,\n",
|
||||
" schema: str,\n",
|
||||
" host: Optional[str] = None,\n",
|
||||
" api_token: Optional[str] = None,\n",
|
||||
" warehouse_id: Optional[str] = None,\n",
|
||||
" cluster_id: Optional[str] = None,\n",
|
||||
" engine_args: Optional[dict] = None,\n",
|
||||
" **kwargs: Any)\n",
|
||||
"```\n",
|
||||
"### Required Parameters\n",
|
||||
"* `catalog`: The catalog name in the Databricks database.\n",
|
||||
"* `schema`: The schema name in the catalog.\n",
|
||||
"\n",
|
||||
"### Optional Parameters\n",
|
||||
"There following parameters are optional. When executing the method in a Databricks notebook, you don't need to provide them in most of the cases.\n",
|
||||
"* `host`: The Databricks workspace hostname, excluding 'https://' part. Defaults to 'DATABRICKS_HOST' environment variable or current workspace if in a Databricks notebook.\n",
|
||||
"* `api_token`: The Databricks personal access token for accessing the Databricks SQL warehouse or the cluster. Defaults to 'DATABRICKS_TOKEN' environment variable or a temporary one is generated if in a Databricks notebook.\n",
|
||||
"* `warehouse_id`: The warehouse ID in the Databricks SQL.\n",
|
||||
"* `cluster_id`: The cluster ID in the Databricks Runtime. If running in a Databricks notebook and both 'warehouse_id' and 'cluster_id' are None, it uses the ID of the cluster the notebook is attached to.\n",
|
||||
"* `engine_args`: The arguments to be used when connecting Databricks.\n",
|
||||
"* `**kwargs`: Additional keyword arguments for the `SQLDatabase.from_uri` method."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b11c7e48",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Examples"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "8102bca0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Connecting to Databricks with SQLDatabase wrapper\n",
|
||||
"from langchain_community.utilities import SQLDatabase\n",
|
||||
"\n",
|
||||
"db = SQLDatabase.from_databricks(catalog=\"samples\", schema=\"nyctaxi\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "9dd36f58",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Creating a OpenAI Chat LLM wrapper\n",
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"\n",
|
||||
"llm = ChatOpenAI(temperature=0, model_name=\"gpt-4\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5b5c5f1a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### SQL Chain example\n",
|
||||
"\n",
|
||||
"This example demonstrates the use of the [SQL Chain](https://python.langchain.com/en/latest/modules/chains/examples/sqlite.html) for answering a question over a Databricks database."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "36f2270b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain_community.utilities import SQLDatabaseChain\n",
|
||||
"\n",
|
||||
"db_chain = SQLDatabaseChain.from_llm(llm, db, verbose=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "4e2b5f25",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"\n",
|
||||
"\u001b[1m> Entering new SQLDatabaseChain chain...\u001b[0m\n",
|
||||
"What is the average duration of taxi rides that start between midnight and 6am?\n",
|
||||
"SQLQuery:\u001b[32;1m\u001b[1;3mSELECT AVG(UNIX_TIMESTAMP(tpep_dropoff_datetime) - UNIX_TIMESTAMP(tpep_pickup_datetime)) as avg_duration\n",
|
||||
"FROM trips\n",
|
||||
"WHERE HOUR(tpep_pickup_datetime) >= 0 AND HOUR(tpep_pickup_datetime) < 6\u001b[0m\n",
|
||||
"SQLResult: \u001b[33;1m\u001b[1;3m[(987.8122786304605,)]\u001b[0m\n",
|
||||
"Answer:\u001b[32;1m\u001b[1;3mThe average duration of taxi rides that start between midnight and 6am is 987.81 seconds.\u001b[0m\n",
|
||||
"\u001b[1m> Finished chain.\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'The average duration of taxi rides that start between midnight and 6am is 987.81 seconds.'"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"db_chain.run(\n",
|
||||
" \"What is the average duration of taxi rides that start between midnight and 6am?\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e496d5e5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### SQL Database Agent example\n",
|
||||
"\n",
|
||||
"This example demonstrates the use of the [SQL Database Agent](/docs/integrations/tools/sql_database) for answering questions over a Databricks database."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "9918e86a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.agents import create_sql_agent\n",
|
||||
"from langchain_community.agent_toolkits import SQLDatabaseToolkit\n",
|
||||
"\n",
|
||||
"toolkit = SQLDatabaseToolkit(db=db, llm=llm)\n",
|
||||
"agent = create_sql_agent(llm=llm, toolkit=toolkit, verbose=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "c484a76e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"\n",
|
||||
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
|
||||
"\u001b[32;1m\u001b[1;3mAction: list_tables_sql_db\n",
|
||||
"Action Input: \u001b[0m\n",
|
||||
"Observation: \u001b[38;5;200m\u001b[1;3mtrips\u001b[0m\n",
|
||||
"Thought:\u001b[32;1m\u001b[1;3mI should check the schema of the trips table to see if it has the necessary columns for trip distance and duration.\n",
|
||||
"Action: schema_sql_db\n",
|
||||
"Action Input: trips\u001b[0m\n",
|
||||
"Observation: \u001b[33;1m\u001b[1;3m\n",
|
||||
"CREATE TABLE trips (\n",
|
||||
"\ttpep_pickup_datetime TIMESTAMP, \n",
|
||||
"\ttpep_dropoff_datetime TIMESTAMP, \n",
|
||||
"\ttrip_distance FLOAT, \n",
|
||||
"\tfare_amount FLOAT, \n",
|
||||
"\tpickup_zip INT, \n",
|
||||
"\tdropoff_zip INT\n",
|
||||
") USING DELTA\n",
|
||||
"\n",
|
||||
"/*\n",
|
||||
"3 rows from trips table:\n",
|
||||
"tpep_pickup_datetime\ttpep_dropoff_datetime\ttrip_distance\tfare_amount\tpickup_zip\tdropoff_zip\n",
|
||||
"2016-02-14 16:52:13+00:00\t2016-02-14 17:16:04+00:00\t4.94\t19.0\t10282\t10171\n",
|
||||
"2016-02-04 18:44:19+00:00\t2016-02-04 18:46:00+00:00\t0.28\t3.5\t10110\t10110\n",
|
||||
"2016-02-17 17:13:57+00:00\t2016-02-17 17:17:55+00:00\t0.7\t5.0\t10103\t10023\n",
|
||||
"*/\u001b[0m\n",
|
||||
"Thought:\u001b[32;1m\u001b[1;3mThe trips table has the necessary columns for trip distance and duration. I will write a query to find the longest trip distance and its duration.\n",
|
||||
"Action: query_checker_sql_db\n",
|
||||
"Action Input: SELECT trip_distance, tpep_dropoff_datetime - tpep_pickup_datetime as duration FROM trips ORDER BY trip_distance DESC LIMIT 1\u001b[0m\n",
|
||||
"Observation: \u001b[31;1m\u001b[1;3mSELECT trip_distance, tpep_dropoff_datetime - tpep_pickup_datetime as duration FROM trips ORDER BY trip_distance DESC LIMIT 1\u001b[0m\n",
|
||||
"Thought:\u001b[32;1m\u001b[1;3mThe query is correct. I will now execute it to find the longest trip distance and its duration.\n",
|
||||
"Action: query_sql_db\n",
|
||||
"Action Input: SELECT trip_distance, tpep_dropoff_datetime - tpep_pickup_datetime as duration FROM trips ORDER BY trip_distance DESC LIMIT 1\u001b[0m\n",
|
||||
"Observation: \u001b[36;1m\u001b[1;3m[(30.6, '0 00:43:31.000000000')]\u001b[0m\n",
|
||||
"Thought:\u001b[32;1m\u001b[1;3mI now know the final answer.\n",
|
||||
"Final Answer: The longest trip distance is 30.6 miles and it took 43 minutes and 31 seconds.\u001b[0m\n",
|
||||
"\n",
|
||||
"\u001b[1m> Finished chain.\u001b[0m\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'The longest trip distance is 30.6 miles and it took 43 minutes and 31 seconds.'"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"agent.run(\"What is the longest trip distance and how long did it take?\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -124,8 +124,8 @@
|
||||
"# Optional-- If you want to enable Langsmith -- good for debugging\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"os.environ[\"LANGSMITH_TRACING\"] = \"true\"\n",
|
||||
"os.environ[\"LANGSMITH_API_KEY\"] = getpass.getpass()"
|
||||
"os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
|
||||
"os.environ[\"LANGCHAIN_API_KEY\"] = getpass.getpass()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -156,7 +156,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Ensure you have an HF_TOKEN in your development environment:\n",
|
||||
"# Ensure you have an HF_TOKEN in your development enviornment:\n",
|
||||
"# access tokens can be created or copied from the Hugging Face platform (https://huggingface.co/docs/hub/en/security-tokens)\n",
|
||||
"\n",
|
||||
"# Load MongoDB's embedded_movies dataset from Hugging Face\n",
|
||||
|
||||
@@ -71,9 +71,9 @@
|
||||
"# Optional: LangSmith API keys\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"os.environ[\"LANGSMITH_TRACING\"] = \"true\"\n",
|
||||
"os.environ[\"LANGSMITH_ENDPOINT\"] = \"https://api.smith.langchain.com\"\n",
|
||||
"os.environ[\"LANGSMITH_API_KEY\"] = \"api_key\""
|
||||
"os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
|
||||
"os.environ[\"LANGCHAIN_ENDPOINT\"] = \"https://api.smith.langchain.com\"\n",
|
||||
"os.environ[\"LANGCHAIN_API_KEY\"] = \"api_key\""
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"os.environ[\"LANGSMITH_PROJECT\"] = \"movie-qa\""
|
||||
"os.environ[\"LANGCHAIN_PROJECT\"] = \"movie-qa\""
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# RAG using Upstage Document Parse and Groundedness Check\n",
|
||||
"This example illustrates RAG using [Upstage](https://python.langchain.com/docs/integrations/providers/upstage/) Document Parse and Groundedness Check."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import List\n",
|
||||
"\n",
|
||||
"from langchain_community.vectorstores import DocArrayInMemorySearch\n",
|
||||
"from langchain_core.output_parsers import StrOutputParser\n",
|
||||
"from langchain_core.prompts import ChatPromptTemplate\n",
|
||||
"from langchain_core.runnables import RunnablePassthrough\n",
|
||||
"from langchain_core.runnables.base import RunnableSerializable\n",
|
||||
"from langchain_upstage import (\n",
|
||||
" ChatUpstage,\n",
|
||||
" UpstageDocumentParseLoader,\n",
|
||||
" UpstageEmbeddings,\n",
|
||||
" UpstageGroundednessCheck,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"model = ChatUpstage()\n",
|
||||
"\n",
|
||||
"files = [\"/PATH/TO/YOUR/FILE.pdf\", \"/PATH/TO/YOUR/FILE2.pdf\"]\n",
|
||||
"\n",
|
||||
"loader = UpstageDocumentParseLoader(file_path=files, split=\"element\")\n",
|
||||
"\n",
|
||||
"docs = loader.load()\n",
|
||||
"\n",
|
||||
"vectorstore = DocArrayInMemorySearch.from_documents(\n",
|
||||
" docs, embedding=UpstageEmbeddings(model=\"solar-embedding-1-large\")\n",
|
||||
")\n",
|
||||
"retriever = vectorstore.as_retriever()\n",
|
||||
"\n",
|
||||
"template = \"\"\"Answer the question based only on the following context:\n",
|
||||
"{context}\n",
|
||||
"\n",
|
||||
"Question: {question}\n",
|
||||
"\"\"\"\n",
|
||||
"prompt = ChatPromptTemplate.from_template(template)\n",
|
||||
"output_parser = StrOutputParser()\n",
|
||||
"\n",
|
||||
"retrieved_docs = retriever.get_relevant_documents(\"How many parameters in SOLAR model?\")\n",
|
||||
"\n",
|
||||
"groundedness_check = UpstageGroundednessCheck()\n",
|
||||
"groundedness = \"\"\n",
|
||||
"while groundedness != \"grounded\":\n",
|
||||
" chain: RunnableSerializable = RunnablePassthrough() | prompt | model | output_parser\n",
|
||||
"\n",
|
||||
" result = chain.invoke(\n",
|
||||
" {\n",
|
||||
" \"context\": retrieved_docs,\n",
|
||||
" \"question\": \"How many parameters in SOLAR model?\",\n",
|
||||
" }\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" groundedness = groundedness_check.invoke(\n",
|
||||
" {\n",
|
||||
" \"context\": retrieved_docs,\n",
|
||||
" \"answer\": result,\n",
|
||||
" }\n",
|
||||
" )"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# RAG using Upstage Layout Analysis and Groundedness Check\n",
|
||||
"This example illustrates RAG using [Upstage](https://python.langchain.com/docs/integrations/providers/upstage/) Layout Analysis and Groundedness Check."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import List\n",
|
||||
"\n",
|
||||
"from langchain_community.vectorstores import DocArrayInMemorySearch\n",
|
||||
"from langchain_core.output_parsers import StrOutputParser\n",
|
||||
"from langchain_core.prompts import ChatPromptTemplate\n",
|
||||
"from langchain_core.runnables import RunnablePassthrough\n",
|
||||
"from langchain_core.runnables.base import RunnableSerializable\n",
|
||||
"from langchain_upstage import (\n",
|
||||
" ChatUpstage,\n",
|
||||
" UpstageEmbeddings,\n",
|
||||
" UpstageGroundednessCheck,\n",
|
||||
" UpstageLayoutAnalysisLoader,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"model = ChatUpstage()\n",
|
||||
"\n",
|
||||
"files = [\"/PATH/TO/YOUR/FILE.pdf\", \"/PATH/TO/YOUR/FILE2.pdf\"]\n",
|
||||
"\n",
|
||||
"loader = UpstageLayoutAnalysisLoader(file_path=files, split=\"element\")\n",
|
||||
"\n",
|
||||
"docs = loader.load()\n",
|
||||
"\n",
|
||||
"vectorstore = DocArrayInMemorySearch.from_documents(\n",
|
||||
" docs, embedding=UpstageEmbeddings(model=\"solar-embedding-1-large\")\n",
|
||||
")\n",
|
||||
"retriever = vectorstore.as_retriever()\n",
|
||||
"\n",
|
||||
"template = \"\"\"Answer the question based only on the following context:\n",
|
||||
"{context}\n",
|
||||
"\n",
|
||||
"Question: {question}\n",
|
||||
"\"\"\"\n",
|
||||
"prompt = ChatPromptTemplate.from_template(template)\n",
|
||||
"output_parser = StrOutputParser()\n",
|
||||
"\n",
|
||||
"retrieved_docs = retriever.get_relevant_documents(\"How many parameters in SOLAR model?\")\n",
|
||||
"\n",
|
||||
"groundedness_check = UpstageGroundednessCheck()\n",
|
||||
"groundedness = \"\"\n",
|
||||
"while groundedness != \"grounded\":\n",
|
||||
" chain: RunnableSerializable = RunnablePassthrough() | prompt | model | output_parser\n",
|
||||
"\n",
|
||||
" result = chain.invoke(\n",
|
||||
" {\n",
|
||||
" \"context\": retrieved_docs,\n",
|
||||
" \"question\": \"How many parameters in SOLAR model?\",\n",
|
||||
" }\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" groundedness = groundedness_check.invoke(\n",
|
||||
" {\n",
|
||||
" \"context\": retrieved_docs,\n",
|
||||
" \"answer\": result,\n",
|
||||
" }\n",
|
||||
" )"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -144,8 +144,8 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# import os\n",
|
||||
"# os.environ[\"LANGSMITH_TRACING\"] = \"true\"\n",
|
||||
"# os.environ[\"LANGSMITH_PROJECT\"] = \"default\" # Make sure this session actually exists."
|
||||
"# os.environ[\"LANGCHAIN_HANDLER\"] = \"langchain\"\n",
|
||||
"# os.environ[\"LANGCHAIN_SESSION\"] = \"default\" # Make sure this session actually exists."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
3
docker/Dockerfile.base
Normal file
3
docker/Dockerfile.base
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM python:3.11
|
||||
|
||||
RUN pip install langchain
|
||||
12
docker/Makefile
Normal file
12
docker/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
# Makefile
|
||||
|
||||
build_graphdb:
|
||||
docker build --tag graphdb ./graphdb
|
||||
|
||||
start_graphdb:
|
||||
docker-compose up -d graphdb
|
||||
|
||||
down:
|
||||
docker-compose down -v --remove-orphans
|
||||
|
||||
.PHONY: build_graphdb start_graphdb down
|
||||
84
docker/docker-compose.yml
Normal file
84
docker/docker-compose.yml
Normal file
@@ -0,0 +1,84 @@
|
||||
# docker-compose to make it easier to spin up integration tests.
|
||||
# Services should use NON standard ports to avoid collision with
|
||||
# any existing services that might be used for development.
|
||||
# ATTENTION: When adding a service below use a non-standard port
|
||||
# increment by one from the preceding port.
|
||||
# For credentials always use `langchain` and `langchain` for the
|
||||
# username and password.
|
||||
version: "3"
|
||||
name: langchain-tests
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis/redis-stack-server:latest
|
||||
# We use non standard ports since
|
||||
# these instances are used for testing
|
||||
# and users may already have existing
|
||||
# redis instances set up locally
|
||||
# for other projects
|
||||
ports:
|
||||
- "6020:6379"
|
||||
volumes:
|
||||
- ./redis-volume:/data
|
||||
graphdb:
|
||||
image: graphdb
|
||||
ports:
|
||||
- "6021:7200"
|
||||
mongo:
|
||||
image: mongo:latest
|
||||
container_name: mongo_container
|
||||
ports:
|
||||
- "6022:27017"
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: langchain
|
||||
MONGO_INITDB_ROOT_PASSWORD: langchain
|
||||
postgres:
|
||||
image: postgres:16
|
||||
environment:
|
||||
POSTGRES_DB: langchain
|
||||
POSTGRES_USER: langchain
|
||||
POSTGRES_PASSWORD: langchain
|
||||
ports:
|
||||
- "6023:5432"
|
||||
command: |
|
||||
postgres -c log_statement=all
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"psql postgresql://langchain:langchain@localhost/langchain --command 'SELECT 1;' || exit 1",
|
||||
]
|
||||
interval: 5s
|
||||
retries: 60
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
pgvector:
|
||||
# postgres with the pgvector extension
|
||||
image: ankane/pgvector
|
||||
environment:
|
||||
POSTGRES_DB: langchain
|
||||
POSTGRES_USER: langchain
|
||||
POSTGRES_PASSWORD: langchain
|
||||
ports:
|
||||
- "6024:5432"
|
||||
command: |
|
||||
postgres -c log_statement=all
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"psql postgresql://langchain:langchain@localhost/langchain --command 'SELECT 1;' || exit 1",
|
||||
]
|
||||
interval: 5s
|
||||
retries: 60
|
||||
volumes:
|
||||
- postgres_data_pgvector:/var/lib/postgresql/data
|
||||
vdms:
|
||||
image: intellabs/vdms:latest
|
||||
container_name: vdms_container
|
||||
ports:
|
||||
- "6025:55555"
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
postgres_data_pgvector:
|
||||
5
docker/graphdb/Dockerfile
Normal file
5
docker/graphdb/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM ontotext/graphdb:10.5.1
|
||||
RUN mkdir -p /opt/graphdb/dist/data/repositories/langchain
|
||||
COPY config.ttl /opt/graphdb/dist/data/repositories/langchain/
|
||||
COPY graphdb_create.sh /run.sh
|
||||
ENTRYPOINT bash /run.sh
|
||||
46
docker/graphdb/config.ttl
Normal file
46
docker/graphdb/config.ttl
Normal file
@@ -0,0 +1,46 @@
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
|
||||
@prefix rep: <http://www.openrdf.org/config/repository#>.
|
||||
@prefix sr: <http://www.openrdf.org/config/repository/sail#>.
|
||||
@prefix sail: <http://www.openrdf.org/config/sail#>.
|
||||
@prefix graphdb: <http://www.ontotext.com/config/graphdb#>.
|
||||
|
||||
[] a rep:Repository ;
|
||||
rep:repositoryID "langchain" ;
|
||||
rdfs:label "" ;
|
||||
rep:repositoryImpl [
|
||||
rep:repositoryType "graphdb:SailRepository" ;
|
||||
sr:sailImpl [
|
||||
sail:sailType "graphdb:Sail" ;
|
||||
|
||||
graphdb:read-only "false" ;
|
||||
|
||||
# Inference and Validation
|
||||
graphdb:ruleset "empty" ;
|
||||
graphdb:disable-sameAs "true" ;
|
||||
graphdb:check-for-inconsistencies "false" ;
|
||||
|
||||
# Indexing
|
||||
graphdb:entity-id-size "32" ;
|
||||
graphdb:enable-context-index "false" ;
|
||||
graphdb:enablePredicateList "true" ;
|
||||
graphdb:enable-fts-index "false" ;
|
||||
graphdb:fts-indexes ("default" "iri") ;
|
||||
graphdb:fts-string-literals-index "default" ;
|
||||
graphdb:fts-iris-index "none" ;
|
||||
|
||||
# Queries and Updates
|
||||
graphdb:query-timeout "0" ;
|
||||
graphdb:throw-QueryEvaluationException-on-timeout "false" ;
|
||||
graphdb:query-limit-results "0" ;
|
||||
|
||||
# Settable in the file but otherwise hidden in the UI and in the RDF4J console
|
||||
graphdb:base-URL "http://example.org/owlim#" ;
|
||||
graphdb:defaultNS "" ;
|
||||
graphdb:imports "" ;
|
||||
graphdb:repository-type "file-repository" ;
|
||||
graphdb:storage-folder "storage" ;
|
||||
graphdb:entity-index-size "10000000" ;
|
||||
graphdb:in-memory-literal-properties "true" ;
|
||||
graphdb:enable-literal-index "true" ;
|
||||
]
|
||||
].
|
||||
28
docker/graphdb/graphdb_create.sh
Normal file
28
docker/graphdb/graphdb_create.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#! /bin/bash
|
||||
REPOSITORY_ID="langchain"
|
||||
GRAPHDB_URI="http://localhost:7200/"
|
||||
|
||||
echo -e "\nUsing GraphDB: ${GRAPHDB_URI}"
|
||||
|
||||
function startGraphDB {
|
||||
echo -e "\nStarting GraphDB..."
|
||||
exec /opt/graphdb/dist/bin/graphdb
|
||||
}
|
||||
|
||||
function waitGraphDBStart {
|
||||
echo -e "\nWaiting GraphDB to start..."
|
||||
for _ in $(seq 1 5); do
|
||||
CHECK_RES=$(curl --silent --write-out '%{http_code}' --output /dev/null ${GRAPHDB_URI}/rest/repositories)
|
||||
if [ "${CHECK_RES}" = '200' ]; then
|
||||
echo -e "\nUp and running"
|
||||
break
|
||||
fi
|
||||
sleep 30s
|
||||
echo "CHECK_RES: ${CHECK_RES}"
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
startGraphDB &
|
||||
waitGraphDBStart
|
||||
wait
|
||||
@@ -13,25 +13,32 @@ OUTPUT_NEW_DOCS_DIR = $(OUTPUT_NEW_DIR)/docs
|
||||
|
||||
PYTHON = .venv/bin/python
|
||||
|
||||
PARTNER_DEPS_LIST := $(shell find ../libs/partners -mindepth 1 -maxdepth 1 -type d -exec sh -c ' \
|
||||
for dir; do \
|
||||
if find "$$dir" -maxdepth 1 -type f \( -name "pyproject.toml" -o -name "setup.py" \) | grep -q .; then \
|
||||
echo "$$dir"; \
|
||||
fi \
|
||||
done' sh {} + | grep -vE "airbyte|ibm|couchbase|databricks" | tr '\n' ' ')
|
||||
|
||||
PORT ?= 3001
|
||||
|
||||
clean:
|
||||
rm -rf build
|
||||
|
||||
install-vercel-deps:
|
||||
yum -y -q update
|
||||
yum -y -q install gcc bzip2-devel libffi-devel zlib-devel wget tar gzip rsync -y
|
||||
yum -y update
|
||||
yum install gcc bzip2-devel libffi-devel zlib-devel wget tar gzip rsync -y
|
||||
|
||||
install-py-deps:
|
||||
python3 -m venv .venv
|
||||
$(PYTHON) -m pip install -q --upgrade pip
|
||||
$(PYTHON) -m pip install -q --upgrade uv
|
||||
$(PYTHON) -m uv pip install -q --pre -r vercel_requirements.txt
|
||||
$(PYTHON) -m uv pip install -q --pre $$($(PYTHON) scripts/partner_deps_list.py) --overrides vercel_overrides.txt
|
||||
$(PYTHON) -m pip install --upgrade pip
|
||||
$(PYTHON) -m pip install --upgrade uv
|
||||
$(PYTHON) -m uv pip install -r vercel_requirements.txt
|
||||
$(PYTHON) -m uv pip install --editable $(PARTNER_DEPS_LIST)
|
||||
|
||||
generate-files:
|
||||
mkdir -p $(INTERMEDIATE_DIR)
|
||||
cp -rp $(SOURCE_DIR)/* $(INTERMEDIATE_DIR)
|
||||
cp -r $(SOURCE_DIR)/* $(INTERMEDIATE_DIR)
|
||||
|
||||
$(PYTHON) scripts/tool_feat_table.py $(INTERMEDIATE_DIR)
|
||||
|
||||
@@ -39,8 +46,7 @@ generate-files:
|
||||
|
||||
$(PYTHON) scripts/partner_pkg_table.py $(INTERMEDIATE_DIR)
|
||||
|
||||
curl https://raw.githubusercontent.com/langchain-ai/langserve/main/README.md | sed 's/<=/\<=/g' > $(INTERMEDIATE_DIR)/langserve.md
|
||||
cp ../SECURITY.md $(INTERMEDIATE_DIR)/security.md
|
||||
wget -q https://raw.githubusercontent.com/langchain-ai/langserve/main/README.md -O $(INTERMEDIATE_DIR)/langserve.md
|
||||
$(PYTHON) scripts/resolve_local_links.py $(INTERMEDIATE_DIR)/langserve.md https://github.com/langchain-ai/langserve/tree/main/
|
||||
|
||||
copy-infra:
|
||||
@@ -53,14 +59,13 @@ copy-infra:
|
||||
cp package.json $(OUTPUT_NEW_DIR)
|
||||
cp sidebars.js $(OUTPUT_NEW_DIR)
|
||||
cp -r static $(OUTPUT_NEW_DIR)
|
||||
cp -r ../libs/cli/langchain_cli/integration_template $(OUTPUT_NEW_DIR)/src/theme
|
||||
cp yarn.lock $(OUTPUT_NEW_DIR)
|
||||
|
||||
render:
|
||||
$(PYTHON) scripts/notebook_convert.py $(INTERMEDIATE_DIR) $(OUTPUT_NEW_DOCS_DIR)
|
||||
|
||||
md-sync:
|
||||
rsync -avmq --include="*/" --include="*.mdx" --include="*.md" --include="*.png" --include="*/_category_.yml" --exclude="*" $(INTERMEDIATE_DIR)/ $(OUTPUT_NEW_DOCS_DIR)
|
||||
rsync -avm --include="*/" --include="*.mdx" --include="*.md" --include="*.png" --include="*/_category_.yml" --exclude="*" $(INTERMEDIATE_DIR)/ $(OUTPUT_NEW_DOCS_DIR)
|
||||
|
||||
append-related:
|
||||
$(PYTHON) scripts/append_related_links.py $(OUTPUT_NEW_DOCS_DIR)
|
||||
@@ -75,13 +80,16 @@ build: install-py-deps generate-files copy-infra render md-sync append-related
|
||||
vercel-build: install-vercel-deps build generate-references
|
||||
rm -rf docs
|
||||
mv $(OUTPUT_NEW_DOCS_DIR) docs
|
||||
cp -r ../libs/cli/langchain_cli/integration_template src/theme
|
||||
rm -rf build
|
||||
mkdir static/api_reference
|
||||
git clone --depth=1 https://github.com/langchain-ai/langchain-api-docs-html.git
|
||||
mv langchain-api-docs-html/api_reference_build/html/* static/api_reference/
|
||||
rm -rf langchain-api-docs-html
|
||||
git clone --depth=1 https://github.com/baskaryan/langchain-api-docs-build.git
|
||||
mv langchain-api-docs-build/api_reference_build/html/* static/api_reference/
|
||||
rm -rf langchain-api-docs-build
|
||||
NODE_OPTIONS="--max-old-space-size=5000" yarn run docusaurus build
|
||||
mv build v0.2
|
||||
mkdir build
|
||||
mv v0.2 build
|
||||
mv build/v0.2/404.html build
|
||||
|
||||
start:
|
||||
cd $(OUTPUT_NEW_DIR) && yarn && yarn start --port=$(PORT)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# LangChain Documentation
|
||||
|
||||
For more information on contributing to our documentation, see the [Documentation Contributing Guide](https://python.langchain.com/docs/contributing/how_to/documentation)
|
||||
For more information on contributing to our documentation, see the [Documentation Contributing Guide](https://python.langchain.com/docs/contributing/documentation)
|
||||
|
||||
@@ -80,8 +80,6 @@
|
||||
html {
|
||||
--pst-font-family-base: 'Inter';
|
||||
--pst-font-family-heading: 'Inter Tight', sans-serif;
|
||||
|
||||
--pst-icon-versionmodified-deprecated: var(--pst-icon-exclamation-triangle);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
@@ -94,7 +92,7 @@ html {
|
||||
* https://sass-lang.com/documentation/interpolation
|
||||
*/
|
||||
/* Defaults to light mode if data-theme is not set */
|
||||
html:not([data-theme]), html[data-theme=light] {
|
||||
html:not([data-theme]) {
|
||||
--pst-color-primary: #287977;
|
||||
--pst-color-primary-bg: #80D6D3;
|
||||
--pst-color-secondary: #6F3AED;
|
||||
@@ -124,8 +122,58 @@ html:not([data-theme]), html[data-theme=light] {
|
||||
--pst-color-on-background: #F4F9F8;
|
||||
--pst-color-surface: #F4F9F8;
|
||||
--pst-color-on-surface: #222832;
|
||||
--pst-color-deprecated: #f47d2e;
|
||||
--pst-color-deprecated-bg: #fff3e8;
|
||||
}
|
||||
html:not([data-theme]) {
|
||||
--pst-color-link: var(--pst-color-primary);
|
||||
--pst-color-link-hover: var(--pst-color-secondary);
|
||||
}
|
||||
html:not([data-theme]) .only-dark,
|
||||
html:not([data-theme]) .only-dark ~ figcaption {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* NOTE: @each {...} is like a for-loop
|
||||
* https://sass-lang.com/documentation/at-rules/control/each
|
||||
*/
|
||||
html[data-theme=light] {
|
||||
--pst-color-primary: #287977;
|
||||
--pst-color-primary-bg: #80D6D3;
|
||||
--pst-color-secondary: #6F3AED;
|
||||
--pst-color-secondary-bg: #DAD6FE;
|
||||
--pst-color-accent: #c132af;
|
||||
--pst-color-accent-bg: #f8dff5;
|
||||
--pst-color-info: #276be9;
|
||||
--pst-color-info-bg: #dce7fc;
|
||||
--pst-color-warning: #f66a0a;
|
||||
--pst-color-warning-bg: #f8e3d0;
|
||||
--pst-color-success: #00843f;
|
||||
--pst-color-success-bg: #d6ece1;
|
||||
--pst-color-attention: var(--pst-color-warning);
|
||||
--pst-color-attention-bg: var(--pst-color-warning-bg);
|
||||
--pst-color-danger: #d72d47;
|
||||
--pst-color-danger-bg: #f9e1e4;
|
||||
--pst-color-text-base: #222832;
|
||||
--pst-color-text-muted: #48566b;
|
||||
--pst-color-heading-color: #ffffff;
|
||||
--pst-color-shadow: rgba(0, 0, 0, 0.1);
|
||||
--pst-color-border: #d1d5da;
|
||||
--pst-color-border-muted: rgba(23, 23, 26, 0.2);
|
||||
--pst-color-inline-code: #912583;
|
||||
--pst-color-inline-code-links: #246161;
|
||||
--pst-color-target: #f3cf95;
|
||||
--pst-color-background: #ffffff;
|
||||
--pst-color-on-background: #F4F9F8;
|
||||
--pst-color-surface: #F4F9F8;
|
||||
--pst-color-on-surface: #222832;
|
||||
color-scheme: light;
|
||||
}
|
||||
html[data-theme=light] {
|
||||
--pst-color-link: var(--pst-color-primary);
|
||||
--pst-color-link-hover: var(--pst-color-secondary);
|
||||
}
|
||||
html[data-theme=light] .only-dark,
|
||||
html[data-theme=light] .only-dark ~ figcaption {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
html[data-theme=dark] {
|
||||
@@ -158,8 +206,6 @@ html[data-theme=dark] {
|
||||
--pst-color-on-background: #222832;
|
||||
--pst-color-surface: #29313d;
|
||||
--pst-color-on-surface: #f3f4f5;
|
||||
--pst-color-deprecated: #b46f3e;
|
||||
--pst-color-deprecated-bg: #341906;
|
||||
/* Adjust images in dark mode (unless they have class .only-dark or
|
||||
* .dark-light, in which case assume they're already optimized for dark
|
||||
* mode).
|
||||
@@ -170,30 +216,6 @@ html[data-theme=dark] {
|
||||
*/
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
html:not([data-theme]) {
|
||||
--pst-color-link: var(--pst-color-primary);
|
||||
--pst-color-link-hover: var(--pst-color-secondary);
|
||||
}
|
||||
html:not([data-theme]) .only-dark,
|
||||
html:not([data-theme]) .only-dark ~ figcaption {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* NOTE: @each {...} is like a for-loop
|
||||
* https://sass-lang.com/documentation/at-rules/control/each
|
||||
*/
|
||||
html[data-theme=light] {
|
||||
color-scheme: light;
|
||||
}
|
||||
html[data-theme=light] {
|
||||
--pst-color-link: var(--pst-color-primary);
|
||||
--pst-color-link-hover: var(--pst-color-secondary);
|
||||
}
|
||||
html[data-theme=light] .only-dark,
|
||||
html[data-theme=light] .only-dark ~ figcaption {
|
||||
display: none !important;
|
||||
}
|
||||
html[data-theme=dark] {
|
||||
--pst-color-link: var(--pst-color-primary);
|
||||
--pst-color-link-hover: var(--pst-color-secondary);
|
||||
@@ -367,13 +389,6 @@ html[data-theme=dark] .MathJax_SVG * {
|
||||
div.deprecated {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 2em;
|
||||
|
||||
background-color: var(--pst-color-deprecated-bg);
|
||||
border-color: var(--pst-color-deprecated);
|
||||
}
|
||||
|
||||
span.versionmodified.deprecated:before {
|
||||
color: var(--pst-color-deprecated);
|
||||
}
|
||||
|
||||
.admonition-beta.admonition, div.admonition-beta.admonition {
|
||||
@@ -393,4 +408,4 @@ dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.
|
||||
p {
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ from sphinx.util.docutils import SphinxDirective
|
||||
_DIR = Path(__file__).parent.absolute()
|
||||
sys.path.insert(0, os.path.abspath("."))
|
||||
sys.path.insert(0, os.path.abspath("../../libs/langchain"))
|
||||
sys.path.insert(0, os.path.abspath("../../libs/experimental"))
|
||||
|
||||
with (_DIR.parents[1] / "libs" / "langchain" / "pyproject.toml").open("r") as f:
|
||||
data = toml.load(f)
|
||||
@@ -87,18 +88,6 @@ class Beta(BaseAdmonition):
|
||||
def setup(app):
|
||||
app.add_directive("example_links", ExampleLinksDirective)
|
||||
app.add_directive("beta", Beta)
|
||||
app.connect("autodoc-skip-member", skip_private_members)
|
||||
|
||||
|
||||
def skip_private_members(app, what, name, obj, skip, options):
|
||||
if skip:
|
||||
return True
|
||||
if hasattr(obj, "__doc__") and obj.__doc__ and ":private:" in obj.__doc__:
|
||||
return True
|
||||
if name == "__init__" and obj.__objclass__ is object:
|
||||
# dont document default init
|
||||
return True
|
||||
return None
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
@@ -128,7 +117,6 @@ extensions = [
|
||||
"_extensions.gallery_directive",
|
||||
"sphinx_design",
|
||||
"sphinx_copybutton",
|
||||
"sphinxcontrib.googleanalytics",
|
||||
]
|
||||
source_suffix = [".rst", ".md"]
|
||||
|
||||
@@ -235,7 +223,9 @@ html_theme_options = {
|
||||
},
|
||||
],
|
||||
"icon_links_label": "Quick Links",
|
||||
"external_links": [],
|
||||
"external_links": [
|
||||
{"name": "Legacy reference", "url": "https://api.python.langchain.com/"},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -268,8 +258,6 @@ html_show_sourcelink = False
|
||||
# Set canonical URL from the Read the Docs Domain
|
||||
html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "")
|
||||
|
||||
googleanalytics_id = "G-9B66JQQH2F"
|
||||
|
||||
# Tell Jinja2 templates the build is running on Read the Docs
|
||||
if os.environ.get("READTHEDOCS", "") == "True":
|
||||
html_context["READTHEDOCS"] = True
|
||||
|
||||
@@ -72,21 +72,14 @@ def _load_module_members(module_path: str, namespace: str) -> ModuleMembers:
|
||||
Returns:
|
||||
list: A list of loaded module objects.
|
||||
"""
|
||||
|
||||
classes_: List[ClassInfo] = []
|
||||
functions: List[FunctionInfo] = []
|
||||
module = importlib.import_module(module_path)
|
||||
|
||||
if ":private:" in (module.__doc__ or ""):
|
||||
return ModuleMembers(classes_=[], functions=[])
|
||||
|
||||
for name, type_ in inspect.getmembers(module):
|
||||
if not hasattr(type_, "__module__"):
|
||||
continue
|
||||
if type_.__module__ != module_path:
|
||||
continue
|
||||
if ":private:" in (type_.__doc__ or ""):
|
||||
continue
|
||||
|
||||
if inspect.isclass(type_):
|
||||
# The type of the class is used to select a template
|
||||
@@ -486,11 +479,11 @@ def _package_namespace(package_name: str) -> str:
|
||||
Returns:
|
||||
modified package_name: Can be either "langchain" or "langchain_{package_name}"
|
||||
"""
|
||||
if package_name == "langchain":
|
||||
return "langchain"
|
||||
if package_name == "standard-tests":
|
||||
return "langchain_tests"
|
||||
return f"langchain_{package_name.replace('-', '_')}"
|
||||
return (
|
||||
package_name
|
||||
if package_name == "langchain"
|
||||
else f"langchain_{package_name.replace('-', '_')}"
|
||||
)
|
||||
|
||||
|
||||
def _package_dir(package_name: str = "langchain") -> Path:
|
||||
@@ -502,7 +495,6 @@ def _package_dir(package_name: str = "langchain") -> Path:
|
||||
"core",
|
||||
"cli",
|
||||
"text-splitters",
|
||||
"standard-tests",
|
||||
):
|
||||
return ROOT_DIR / "libs" / package_name / _package_namespace(package_name)
|
||||
else:
|
||||
@@ -528,12 +520,7 @@ def _get_package_version(package_dir: Path) -> str:
|
||||
"Aborting the build."
|
||||
)
|
||||
exit(1)
|
||||
try:
|
||||
# uses uv
|
||||
return pyproject["project"]["version"]
|
||||
except KeyError:
|
||||
# uses poetry
|
||||
return pyproject["tool"]["poetry"]["version"]
|
||||
return pyproject["tool"]["poetry"]["version"]
|
||||
|
||||
|
||||
def _out_file_path(package_name: str) -> Path:
|
||||
@@ -543,9 +530,9 @@ def _out_file_path(package_name: str) -> Path:
|
||||
|
||||
def _build_index(dirs: List[str]) -> None:
|
||||
custom_names = {
|
||||
"airbyte": "Airbyte",
|
||||
"aws": "AWS",
|
||||
"ai21": "AI21",
|
||||
"ibm": "IBM",
|
||||
}
|
||||
ordered = ["core", "langchain", "text-splitters", "community", "experimental"]
|
||||
main_ = [dir_ for dir_ in ordered if dir_ in dirs]
|
||||
@@ -613,11 +600,9 @@ For the legacy API reference hosted on ReadTheDocs see [https://api.python.langc
|
||||
]
|
||||
for header_name, dir_ in sorted(
|
||||
zip(integration_headers, integrations),
|
||||
key=lambda h_d: (
|
||||
integrations_to_show.index(h_d[1])
|
||||
if h_d[1] in integrations_to_show
|
||||
else len(integrations_to_show)
|
||||
),
|
||||
key=lambda h_d: integrations_to_show.index(h_d[1])
|
||||
if h_d[1] in integrations_to_show
|
||||
else len(integrations_to_show),
|
||||
)[: len(integrations_to_show)]:
|
||||
integration_grid += f'\n- header: "**{header_name}**"\n content: {_package_namespace(dir_).replace("_", "-")} {_get_package_version(_package_dir(dir_))}\n link: {dir_.replace("-", "_")}/index.html'
|
||||
doc += f"""## Integrations
|
||||
@@ -662,7 +647,7 @@ def main(dirs: Optional[list] = None) -> None:
|
||||
dirs = [
|
||||
dir_
|
||||
for dir_ in os.listdir(ROOT_DIR / "libs")
|
||||
if dir_ not in ("cli", "partners", "packages.yml")
|
||||
if dir_ not in ("cli", "partners", "standard-tests")
|
||||
]
|
||||
dirs += [
|
||||
dir_
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
autodoc_pydantic>=2,<3
|
||||
sphinx>=8,<9
|
||||
autodoc_pydantic>=1,<2
|
||||
sphinx<=7
|
||||
myst-parser>=3
|
||||
sphinx-autobuild>=2024
|
||||
pydata-sphinx-theme>=0.15
|
||||
@@ -8,5 +8,4 @@ myst-nb>=1.1.1
|
||||
pyyaml
|
||||
sphinx-design
|
||||
sphinx-copybutton
|
||||
beautifulsoup4
|
||||
sphinxcontrib-googleanalytics
|
||||
beautifulsoup4
|
||||
@@ -17,10 +17,7 @@ def process_toc_h3_elements(html_content: str) -> str:
|
||||
|
||||
# Process each element
|
||||
for element in toc_h3_elements:
|
||||
try:
|
||||
element = element.a.code.span
|
||||
except Exception:
|
||||
continue
|
||||
element = element.a.code.span
|
||||
# Get the text content of the element
|
||||
content = element.get_text()
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
:member-order: groupwise
|
||||
:show-inheritance: True
|
||||
:special-members: __call__
|
||||
:exclude-members: construct, copy, dict, from_orm, parse_file, parse_obj, parse_raw, schema, schema_json, update_forward_refs, validate, json, is_lc_serializable, to_json, to_json_not_implemented, lc_secrets, lc_attributes, lc_id, get_lc_namespace, model_construct, model_copy, model_dump, model_dump_json, model_parametrized_name, model_post_init, model_rebuild, model_validate, model_validate_json, model_validate_strings, model_extra, model_fields_set, model_json_schema
|
||||
:exclude-members: construct, copy, dict, from_orm, parse_file, parse_obj, parse_raw, schema, schema_json, update_forward_refs, validate, json, is_lc_serializable, to_json, to_json_not_implemented, lc_secrets, lc_attributes, lc_id, get_lc_namespace
|
||||
|
||||
|
||||
{% block attributes %}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
:member-order: groupwise
|
||||
:show-inheritance: True
|
||||
:special-members: __call__
|
||||
:exclude-members: construct, copy, dict, from_orm, parse_file, parse_obj, parse_raw, schema, schema_json, update_forward_refs, validate, json, is_lc_serializable, to_json_not_implemented, lc_secrets, lc_attributes, lc_id, get_lc_namespace, astream_log, transform, atransform, get_output_schema, get_prompts, config_schema, map, pick, pipe, InputType, OutputType, config_specs, output_schema, get_input_schema, get_graph, get_name, input_schema, name, assign, as_tool, get_config_jsonschema, get_input_jsonschema, get_output_jsonschema, model_construct, model_copy, model_dump, model_dump_json, model_parametrized_name, model_post_init, model_rebuild, model_validate, model_validate_json, model_validate_strings, to_json, model_extra, model_fields_set, model_json_schema, predict, apredict, predict_messages, apredict_messages, generate, generate_prompt, agenerate, agenerate_prompt, call_as_llm
|
||||
:exclude-members: construct, copy, dict, from_orm, parse_file, parse_obj, parse_raw, schema, schema_json, update_forward_refs, validate, json, is_lc_serializable, to_json_not_implemented, lc_secrets, lc_attributes, lc_id, get_lc_namespace, astream_log, transform, atransform, get_output_schema, get_prompts, config_schema, map, pick, pipe, with_listeners, with_alisteners, with_config, with_fallbacks, with_types, with_retry, InputType, OutputType, config_specs, output_schema, get_input_schema, get_graph, get_name, input_schema, name, bind, assign, as_tool
|
||||
|
||||
.. NOTE:: {{objname}} implements the standard :py:class:`Runnable Interface <langchain_core.runnables.base.Runnable>`. 🏃
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
eNrtVs1u20YQRoA+CLHoqRAlkvpnkYNhBAnQGg4Qt0ARBIsVOSS3JneZ3aVlxdAhbq49sE/Q1oYVGEnbQ9FLG7THHvoC7r3v0VlKyo+jIkZ6CloBgqSdnZlvZr75qOPFASjNpbj2hAsDikUGf+ivjhcK7legzaOzAkwm45ObN/ZOKsUv3s+MKXXY6bCSt3XBTdbOmUijjHHRjmTR4SKRpxMZz35bZMBiDP/o/BMNyt1KQZj6R3u78XPLWcdr+20/GH2/FUVQGveGiGTMRVo/TR/wsuXEkOTMwNnSXP/AyjLnEbMYO59rKc63pRDQYK7P9wFKl+X8AB4r0CWWAV+cacNMpY9PMS788fuiAK1ZCt/ufrQG9+VpjBnqZ3sVtBy/7+xGxgm8oOf4o7AXhL2uc3Nn70kksTvCuGZWwuswnkYsysC1l5TM68dCus3JLxa31u720uBu5bmcujtNQ3X9zQcXzsYL2wpiTMZZrutToyr46dK1HXZou1mfDDzv540hdhVPuai/Xmzlxr1zENUX7ax7nYS9Xpd86BTsetAfB57ntbKuG4w3GM5wYkiNelEd8EgqsbmUW8seYinfba869DGI1GT1SW/UP/mUs/ocB+ykUqY5PLsU48ZhKTW8FKShzUOcmUIO/HntryOyYicJidcetgceaRHsPOBoKRyWXDUzoIYXQEJR5XmLTJiJMor+SF6KE0l4SsIjUqFHUeWGl0wZCiIuJRKehLa9LaIjlgOtSnpf8wdAMX+agiKhb1v0wipMphCspjlHAqN5sDbGciqogKI0sxfePbTacOvbTaznB3QyM6BJGHjjod8PvHmLcIF0FRFQZH2qLWxcGVxKA5RxivuoZgidTXKI18ilSmmEoJo+xFyvjAlyx9aVySk1JqcVXzsY3HGskIOicbXqX8xmTbZcitTuDwboNWAzqczqwO8hQA1MYXcvYZhKta9LG1ZHsgRqMXFxwJvy1ki6VBupcPde9Z7P/1lqdt8kNfjGU93JpnimwR92ML1g3E0qsRQyl1nR6VgR0eZ/Vfqvq9KpH/j/Vpbe+/WILIlHkXQZShPzB/0+DmfiDVgyicf92B/2euMk8Lv+IBj74A2DQeJ34yhhyXjsRZEX+yNvNGTxYDRmfRS1ggmeIEXtFnJcjbvkOdPRWiqJyqLxG54Y/NjGj9vN4R5qjiUjuYfKGOGa4oYjGxAVzh0RVxFuHXrsT5laSsqKbPj97pVy3ZlpA8XO0uttky6jvqm61a0Weds0Zu0Rks9k5TAFDnMyyMukyh2mNbf6ahNwUVaGHjDFrRbZXmCOtTdNpCqw9pAk7nLoFhs+N5D7L/scze2rdaUurvqnb+eok5nMkVpXL0uWdqlZvhbcNQYqWNH4YQ6acSuwM3JVRLcqJN07N9ajZnLzjSNcHpF3Y5Kr5+LlUTbPK3yOKvs3pmQxjvPexlpfu9h6lQatdTewLgKHDBuy5Pn8b285bDI=
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
eNqFVktv20YQRi75HQtd1KYSxZeeQREocpwUsaU0UmAUQUFsyJG0Fblkdpd6xPCh6eOuv9C4dhGkrU+95eJTD/0F+TWdJUVZzqMFJIj77ezszPfNDPXyfA5CspjfeMO4AkF9hQu5fnku4HkKUv14FoGaxsHpo8Fw9CoV7O1UqUR2ajWaMEPROQtXhh9HNQlU+NPTZ3Gwenfj5nEJt70ZrEodUlLzcFVVo716szt8PLsHd9Png29ay6D+8KGC5dA1D2f9ZqlCSnijyE4splQRJomaAlkAxR9BGCfDfW0V0aUnQKahkmhrI5Lf7QWQqKk+ToM55T4E2ppxP0wD8II4oozrE0+/RRiWH4ULa8rlAgSiYxpK2NkQdOH5MVLF1Ud2WUQnIIuNk/Mp0AD5/fn1Ewmi2p3gqfVfyQoJ5dUNwbJmGw5+/uz6PsZfvcf9OGB8sv598oIlFRLAOKQKzvLt9atbtVuvezHnkCm1fj0DSKo0ZHP4o5fHVT0APlHT9Su7Yb8psNEqgfUFTZKQ+VSfrH0nY/4b8pig3vDDmVRUpfLlKd4O//x9HoGUmMsvg4dFEj994trTPQxv/XaUIhFWnQx8RWzTdonV6rh2x2mR+4ejsyEILLT1r3zC+PL9QE+thuv+T6RZYX2PUQrk5t3N8Lgolv+qldI4DsN44aWJl3GtS7vU4WkYVkqFwvmqEA6LoLStrafHJcVUCHjJ0Y5jysm+wPpi0o/xjlSEaFB0xWKxMDZR6AbRnYE224opHZfDOE+r3CHHZU4jwIfyNaflCikLmOQ25R6yPI4FZ1TjfpxyJVZ64wlnCgIyROFAknhMuhEI5EybYcmgidM0ms26XmauqpZtG67VchBRLzwWaC+bQ7WDWHpdPoEQZOYAowwVi8CDJPanaGk17bZpNZuWvbutXWi5q5ZZRfUtq+Na5RMdaCoEppxlGVKpUIQAAw3e92eaZhbvlcWHLh1Th6QgSjxfn3QNs1iPcV1vGjolJr2AamasjCcesC3NOGZ0JOVDJpV2xfyc21rND/j7em2WtYa7bLg1dFmzXMdI+CTnP9A5W6Zj6iwXjAdelOh8HMMtgFkG1K+AACYC9DnbMbcYE5nyR9ptgkUnUwFe9CzzbrWyFLcw0+E6pmE2c9RniRdFiJmFnUYyqxyZphFDAjQdbX3GD+M0yFzr3TFAKEM2g5xPx2hdAzNSGxmoQ/WnLAx3La/AHUscEwpxWO5qdAXuCBXAIonxdVO4dHexjUet4RwVnUVZ0JkzvY6YLtAOaWRIOs+I18aTFCsoV8I16gWQK9E07JMTbEPsLYHdbBrtttV2Wg3s9d1xrkfBSeWq6ftZn9KQFN2vpxjz4YOmx/YEHyu4qCRjEs9rOL19FMBIpskdxpNU5bPrS2z1L7atXul1r42HXt41ZFu+kuB0G3b7ZP9xt9/7atgbkL3BUX+EX/LZcH/Qsz4nB1Rtet2sNy4v+gcxR850r9uNtnt5cXQvhDkidaRxrAzS7xooxeXFvoEyXV70DGIY+Egj8mhvlA1wCyXJWrCRXIG2mYPEIPubhMkeJpFK/QcC0W6Qx4yMPQYZp8IHmfv+FJO3r09TcpeuSFcArZBe9zaxLXIf/5EAeRAnCR7qzvEVM1RxQuq3yaHmTMBKm5K203adar1u4kYvjiKkUN4hXxcz/8517c1Gu2F9TPt8+GcvRE8Pt1IHOayf/AtKkges
|
||||
@@ -1 +0,0 @@
|
||||
eNqFVW1sU1UYBrcfhgQlEhMlRg8NEBN229vbj63DKGNzOnRu0IqAWebpuaftZbf3XM85d1u3LIQh0YREcxMTEzXRSGmxzI0JBAySaBCjBH/rMEr4YdQoGn+YqInO99y1MGTB/mhOz/u8X8/7vKeT1WHKhcWc5VOWIynHRMIP4U9WOX3eo0K+UClSWWBmub8vnTnkcWtufUFKV7RHIti1wtiRBc5ci4QJK0aGo5EiFQLnqShnmVm6tPy38VARjw5KNkQdEWpHUd2It6BQAwU3z46HOLMpnEKeoDwEVsKgFEeqq4K1NjQxoDyYSW11Q2zsmVSLaYI5DpWaARF1w0gpR8mYXY/p4GIQU+Jhyy4NCoo5KQxyKjxbisE94KwcTCoIt1zVswJ3oAUcok7ecihiYClaY9REOcYRdOhyWoBGrGHagjAhHsdSnRwTSe4JCcB6hjB6WtCcZweOI+CDSsxDDgWEZOAgRihHAcGKboSzzJMI4nHoG9Fh+IYQPY4Lt6LAPNtEWYpwozxw5KWwasBSkEFBCrSIoYPxkAvToFxaAbfjoQAZnP7T6uJIqiSbsSHkuQGLJTegTkhuOfnQxATcKTVYnJqK3HrQgUVQlt1DiQTowES1QLEJmnqlXGBC+rM3qWQGiKOu1KhDmAkJ/PfyY5bbgkyas4HOGlFzDWTo14YodTVsA9+VBS//GHZd2yJY2SNqjFN1tWiqlpvNNSUqDbTmSP9UR6OOSH8JRO0gPRyLh41jo5qQ2HJsUKVmYyip4gb2M4sNLiZDEEerL4xfWXCeXoxhwj/ci0lf+oaQimn/MObFZPz44nvuOaAv6lc7+29OVzdeTxcLR6Ph1tkbAouSQ/zDOWwLOnuN5GsuNdiNmKYnNT063WDJBmnLgn8onmo9Alp1QX10fwVCSk9MlmEi9OJn1fp6vtP3RGOa3y67q9wF0/HPdnOrBRmtKE1dpHYPRZPterRdb0OP9WamOutpMksOYzbDQfo5GMijjeFXScFzhqhZ61xy7HOh622pZbNhH6VWf5tgWOqnX47ruj634ZZIDgtiOSpjOZZKpf4nLjBDpX9C9afpKc1ozSx0mYjvnkNLeS48cPV6KqoeqGjdLZDX62mg0S3RS9ejt+2u1YvWLNP/EM6DejS9Q+R6jQQpxLaYu2h/b7JrqMtJnBzViM08U5PwylMtEMSo9OdQnEQTRipptMbNeLYtnkglcjgWTyaTuqEn4/HsoWEL+7VoOIryjOVtOtPZrXVieHK0dCAbv9q166mO3p7OqZ3adpZlwF8GA88Oc2glTTnI0a8FqWHBOa2A+/aOXf6JNpIi2QSNJUjMMHI5om2BvWkI6JpAyup1CP5N9lUWXqRPvnjg4O3Lgk/Tky9/s/Xc5lUH3jovzu6TX6/45ezOI6OREP78jrW52OrY8edWlkZ6rI+PNl3+80rLD6tv6776+tjIuvvPXKEPP3Lnr6/NnBoYO3l5+sD+gQ2XtpfXbJo811Jq2nbymYO2e8/6bd2b3yA9masb7869f+HLf/rH55tf3PHVSyuvkA/61vxtf3e0+c0H86WP/vrx7Q3pWDqDm1dVP71w8fS9Wy8fOL2+OZza9OpPM8fe/v7dncRYtXFy70Ntj8/O/3x6ei/UPT/ftOz8H/et+B3O/wLqW+ZT
|
||||
@@ -1 +0,0 @@
|
||||
eNqFVX1sU1UU3yBREIiJX4kY4VLY0GSve6/tuo8/MKVjfIxtyAYOcJbb927Xt76++3jvvm2lzAjjDwN+PWUQoghhXWeaMjYYERE1zkxZ+HCJBDIiQqKJMRElUYMxmnle18KQBftHc3vP75x7zu/8zumO3laiGzJV89OyyoiORQY/DGtHr062mMRgO5NRwsJUSqypq2/oNnV5rCDMmGZUFBdjTXZilYV1qsmiU6TR4lahOEoMAzcTIxGkUuxK/t9xRxS3BxiNENVwVCCBd3mKkCOHgptNcYdOFQInh2kQ3QFWkUIqKrOv2sKYGSgaQyqOkuccHU22M5WIYhtFBZsS4dycQVWVMM4FwXmXq9yOwShVsuFtVxvOcKusxAIGwboYDujEMBVmBFrA2XaQiCHqsmaXb4N9aAKHiNosqwRRsETlrURCIaojKFbTSRhqkltJEcKiaOqY2SdVQkw3DQbA7AtOtM4gIVPJOLaBD4pRE6kEEIyCg9FGdJTh2mYe4SA1GYJ4OlCASCt8Q4iVqga3RpiaioSCBOFceuCox5x2AbINCRhimEQxVBB3aNAYojM5Q3PckUFmTv8pdXIkOyWF0ggytQyLMS1DncF0WW12dHTAnS0MWSeSTW42aNMkKA22EJEBtKmjN0ywBPJ6MxGmBrMG7hHMUSCOaIwjqkgleMA60rxV1oqQREIK0JkS7b5mFGmlIoRoHFaA7+SEl9WPNU2RRWzbi+02prPC4exc7jWnbH1xIDuVWR/6cnkUr4mBvlXEO90ep6u/nTMYllUFBMopGFJKahn7x5MNGhYjEIfLzo6VnHDum4yhhtVTg8W6+rtC2kxbPViPej3HJ9/rpgr6Ilavf829z2WNd55zOwXBWTpwV2AjpopWTwgrBhm4TfJtlxTMhpvjvRwv9OVYUkDaLGx1l/BlH4BWNVAf6UxCSGYaOxLQEXLuTG92Ug/XVee6+V3eI4lK6I71SZUuFyFXKaonGrJnDwneCl6o8HjQ8pqGtD/7TMOUzRho0EH6IWjIslzze8WwqUaIlPJP2fYxx52y7GFTYB4Zl11T0Cz7p5Xw8Dw/VnhfpA4DIqv2iwl3eXn5/8QFZgizBu36OL6cc5U2TFRZ4tk4hqbynNh12XySdj6Q0aL7IO/kk0Oj+6Knzsfj2ZjKJs3JknUazgFecOvrlpWuEr2Vonc58QXXR6pWY6n2RDsnKtSUOAYLn3AZQbQzawy5giVBF1/mFjwCCXqDJWUlPC9K7qDXzQtC0OPqbpWxlRKcAmqmtFkhR/1VnB/DyuHqM7Kxeis31PpqVvrTjdxaGqTAXwMGnlWqkmQ90UGOVirzNAy4TpLgvta3wRosE8vFoFfkyyTscvOuEm4pzE1OQLcFkrC3Q+aPZXtyYiMN5y+Zv3tGXuYz/cW3qqun+2Z/9dmqM8NnBy/emHXr0tKH/yh85iEH+fb1G6P7pQMjg86ea03JP4fqr+8bX/jDzr7huf4ratXlby5vad9Y+1PfhqsPvrSkL33he27uxU+7Dx/e8/Pe0c2PBV6pGSk4kQ7zK6rnRZTT57k5X3YuOpfobGmoqVpndj7wFC5Ynz5Yd81aNX9425MlS26+W3le6dpGN885crNr6MK8Ga8W0LbruxY1mkOHpsX3Lvz97YX9czw7l00729/4xdewh0+9kx59fvXQJX91y4G6zYFZvxSMR45pgx0zbzniZ55eUTRv1+fCP3t9obpnH89r2tMZmfneE4FDC94PzC7sUh8dKcRp6+TV8BuvBXZX/rr/5IJ0eZzygZc3HRzdss/sPra4tvGF4x/5Rv7aVxP68bfFQNT4+PS8g+n+7afy8/L+BTWeI00=
|
||||
@@ -1 +0,0 @@
|
||||
eNqNVktv20YQRi75HQtdlATiU9Tzpjh2GzgvVA6KICiIDTmStloumd2lHjF8aPq46y80rl0EaZtTb7n01EN/QX5NZ5emIhvuAxBAzrczs/P4ZqjX5wuQiuXixjsmNEiaaBTU5vW5hJclKP3dWQZ6lqenTx6Pj96Ukn2YaV2ooefRgrmaLhhfu0meeQqoTGanL/J0/fHGzeMGHsdzWDeGpKEXfO3oo3ud3mj8xXwf7pYvHz/rr9LO4aGG1TjyH84f9Rot0sAbpbVYzqgmTBE9A7IEig9JmCDjA6OV0VUsQZVcK9QNEanujlMo9MyY03RBRQKp0WYi4WUKcZpnlAlj8fwrhGF1LVxrU6GWIBGdUK5g50DSZZzkWCqhrzllGZ2Cqg9OzmdAU6zvD2+fKpDOaIpWm9+LNRZUOBcFVl7otvH32yhJMH5nXyR5ysR088v0FStaJIUJpxrOquPNmzvenbd7uRBgO7V5OwcoHMrZAn7dq+JyHoCY6tnmTdgN39XY0bqAzXtaFJwl1Fh6X6tc/Ix1LLDf8O2Z0lSX6vUp3g5//XmegVKYy4+PD+skvv8PX1evPw26fng2BokM2/wkpkysTu9hJpsPB5K1SNgjYyhI6IcRCbpDP8Af+ezh0T8kZ4n1DUYpsTYfb949rsnyb1xpTHLO82VcFrGttaF2YyhKzluNusOVVDcOSdDYcuv5cUMzzQEv+XLHMRXkQCK/mEpyvKOUHBXqqVgul+5FFGZAzGSgzpYxjeMmz6uiNYfkuCloBvjSvOS02SJNCdNKp7mH+U9yKRg1eJKXQsu1OXgqmIaUjLFxoEg+IaMMJHbEqCFlUKXdc3t9I1lPThCGboTz0tSvYpYaFxcW3oNcxSMxBQ7KWmOIXLMMYijyZIaaQS/sRZ2w3/Z3j40L00DHHzjYT38w9P3miYmylBLztSlyqjR2IMUo0yv+goFv/e1oXHXZH0YdE5KGrIgTY9lxu7U8QbnruwHKTMUpNWUJbJFEyrY1xh2jbY1LIdbGF0uqynpekoqr3boQvW606kYe+vSCoO0WYlpVPzVJB77vmzSXTKRxVpiEItevgbkFum6nBlKYSjB2vWALMWki2H+0b9wWSDlVSoizF9Z7EFpvW5iZcMOB2+9XaMKKOMsQ82s9g1itCpmVGcMKmHr0TbUSnpemtOZsAsAVZ3PYLecncKemJtJkxjivNNvbFCvQaHY6Nk1cERpxWFWa4RXQakYWTGFZ5PipqRQDN9rFrF5lvMCGzk2KQddea+SMGX4OycAi5cIw3L5OSyRQ1Ye+tbZA1QcMu3tygjOIgyVxlH13MOj1/aCHg767y80eOGl9mvjPcxzsNcHJgwT5aV4uj36LfJrMFnk6HhGHmKGgIjVMNmS6djtc0dkSrlTUU1Q4k/oCb2ZDuLQ+TFTOi7VjnuTg/8fmknqDHeXI6a10kWUQkXuIbh0+w2UJ0pD/iRFr7T2Oe1IDuTXCnW4W5m2yV006XyNrQvLH+wOXjHG/oTWuJks75ZJbtQPzkcGxHF6Oltw3fz2EPaKcjJgscqlt3LfRHQDJMDBysVTqJe9e6mkfP3ZRu3NdU6uVbj9zsSl+Y9h2o8HJ3wjDCKE=
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
eNqFVVtsFFUYLjQEHwjXJvqiHDcIATrb2QvdbuVib0CF2tpWuQXXszNnd6ednTPMOdN2aUoCKAaqwTEEgiY8yHZXNxWoLSGKoIlNNMELGqLUEEN4gBhM0BBF5AH/M7tLCzS4D5uz5//+2/f9/9ld2S5iMY0aUwY1gxMLKxx+MGdX1iLbbML4a5kk4Qmqplua29qP2pY29kyCc5NVV1RgU/NigycsamqKV6HJii5fRZIwhuOEpaNUTf0y9fteTxL3RDjtJAbzVCOf7A+WI08RBTdbej0W1QmcPDYjlgesCoVSDC6uEhrSkihKo097+srROBQzpjEO2R/AryW6TlEt4FEjX8SQoSkEcYqShHCUorYXNSKVGos4gk5trOspZBCiCghkR9hIwZHqTFxYhJnUcG0YMS1p6gTFLQikGXEvWku7EbaICAoR4QpwKk6tur/OSVrqTmDOUBIS4yQB+FbBB1WJLoyKjm2VSAGJUcMgXPIDX7LfHxYx3MLyjAlXAee4S9NTEUawpSQiULCtcxbpAGfhoBKmWJopFBXgGpTHIWLENYMgCpakth26j1ELgX6mRRIgk9ZFyoEexbYwFydBgWUzDsBCBi96iZGYrbuO3eDjslAkEhusm1jIHR8xTAhHqc0RxLOAAkS64BtCNBom3LIEtXUVRYngOF8eOFopr2hAE5AIUxIkiaGDXo8Js0YsrrmT0+txke7pgVYnRhIl6ZR2Itt0WUyZLnWMWyCapw/k8ohZ1yyiCnILQbdOgNJoB1E4QLf2ZRMEq7Ax+9MJyrgz9NAOHAfiiMklYihUhQTOR/HtmlmOVBLTgc6cInR1l8zJdRJiSlgHvjN5L+cENk1dU7CwVwgZBwuDI4laHjbnxHxJsEkGd07VFOuoaEnByhpI9gaCXv+JHgk2RTN02DlJx1BSxnTtpycaTKx0Qhyp8Bw4mbzzsYkYypyBJqw0t90XUjDtDGArWRkcnnhv2QbMF3GydS0PpysYx9MFvD6fNzR0X2CWMhRnIIZ1RobukXzPJQe7EZDkSkn2HSuypMNo84RzNOQLf5BfX0Z2ZyAkt9muNChCvvk6W3h83m9eV1Tz15K56XpQxzmz2tLKkT+E2oiJxO4hX2W17KsO+tGapvbBukKa9knFGGq3YPRjIEhDUfyskrCNTqLm6iaVfcwz3pZYNh32kUuFlxfEEj+ddFCW5bGFj0RasCCaITKmA+Fw+H/iAjOEOyOiP0kOS/5Qe77LZcHNY2gyz/zzXagnI+qBihY8AjleTxGNHomevJ6gf3OuULSkqc5ncI7Ivhcbarv4ho6e+hhes622pTbVpqnm+pM9kqJTW5U4/IcRyR2IHu6MoYAcCIZUfywmK1gNh6pilWQZVn3hUDQoV/nl0NEuDTs5n9eH4pTGdXK8brVUh+HJkdrcsXGy9ZteqGlqrBvcKLXSKAX+2jHwbFCDZNqIBePo5NzUsOAWyYB7a80mZ6RKCSvRyqgfk6pQQPYvk2phb4oDdG9A0uJ1cP8rd2byL9Lov/P7HytxP6Xr93/7/JfPlb0eIcuvf5jWpgXW1cz+4a1nh+ZmDq/zBz+Zx25c3PNj96GyaRumn71Zeu3NJy7La7c8fv3UjdPJc9l9kSM3r1ddWrWyCa/8ovaac7Bs7z8HX/UN7JjyyoJ921/eOGNxy6w3MrfC5zuG3xld/+mSfmvLATKtf+HQ3KWXvrpNW38bOXD8yh9HPp4zf/fhtiMz7uxcX3bz7b+vXpxTcWFkntMqlx5WLnz3+/mGedOHm++896Sx7fbI7CZlhXNo1EQzT17d+2fnY33kyp7LVbfONJzdYcXrnxr+6d2Zo1NPLV7Sf+CvVUt/PnRuFjR5925pyefLN6zwTykp+Q/z/kl9
|
||||
@@ -1 +0,0 @@
|
||||
eNqFVX1sE2UY3wTE8I8wM4mJH6+XTWKy6/qxdusSldExRDI3tiIwstS3d2/bW6/3Hve+t62bSxRQo0TxAtEYNU7oOlMHbDhCdBA1CiJgAokai4gfKPCHGgU/QgLB524tDFmwf7R37/N7vn7P73m7bribGEyhWumIonFiYInDC7PWDRtkrUkY35BNEZ6gcqa1pT28zTSUfGWCc53VV1djXXFhjScMqiuSS6Kp6m5PdYowhuOEZaJUTh+/aXa/kMK9EU6TRGNCPfK4vTVVSCii4GRNv2BQlcCTYDJiCGCVKJSicftoZQLzBQzxBEE9BMOPgRQNtTc9JAx02nGoTFQbJ6nYlInoExnVNMJFL+Rxe71BOxynVC1k0nDKycRxt6KmI4xgQ0pEDMJMlbNIFzjbDjJhkqHoNhM2uAFN4hDR4opGEAVLSukjMopRA0HfukES0J7STaoQliTTwNx+0mTEDZNxABYyuNAKRmKm6jj2gA9KUxNpBBCcggPrgf4c2u0hIBylJkcQzwA2EOmGbwixVNPhlCWoqcooShAulgeORtplN6DYkAiTEiSFoYN+QYcZEYMrDuP9goN0nv7T6tRIdkkqpUlk6g6Lad2hjnFD0eLCwACc2RpRDCLb5BaCdk6B0mgXkThAOweGEwTLoLRNmQRl3Bq7Tjs7gTiic5FoEpUhgbU93qfoVUgmMRXozEn2XB1xWrkkIbqIVeA7O+lljWJdVxUJ2/Zqe4wjBQ2Jdi3Xm3O21ERQoMatPQ3FOqpb0yB1DbldvhqXd7RXZBwrmgpaFVUMJWV1xz4x1aBjKQlxxMIaWdlJ5x1TMZRZQ81Yamm/JqTNtDWEjVSg5t2p54apgb6INRxqvT5dwXg1nc/l8bhqx64JzNKaZA3FsMrI2BWSr7jkYDd8ojsguj07iiypIG2esLb5PcG3Qas6qI+sz0JIbrJ1GZgIOXJwuLC0W1uWFad5sqQs0wjTsfY1GUoV8taidqIje/eQJ1Dv9tS7A2hJc3gkVEgTnnYYY2EDpB+DgSwuDn9YSphaksi50LRjzwtX27KXTYV95GLhxoJh2a9WpsbtdufvuyHSgAVRNDtjxhcMBv8nLjBDuDVu9ye6g6K3NjzZpb+mI4+m85y89gr1ZO16oKKKGyCv1lNEoxuip6/HHejIFYoWFdnaC88Rt+fh0PLuhse6Fre2xVem+jzJjh5fI2vc3StKKjVlkcPdT0RHEL3cyqO6On8s6CXRqOQP+GpxjEheH/H7PCQgByQpSrZ1K9jKeVweFKc0rpKdoSYxhOHKEdsd2VjDjasfbWheGhpZJbbRKAX+whh41qhGsu3EADlaOSc1LLhBsuDe1rDaGq+TglLULwf8xIu9sZgkLoK9KQroikAy9u3g/Mc8lZ28kfaXlt+z8ZYS5zMj/FLLso8Xzt3/wSOvnr/93JLn86+93Dfa1nqrIBzedcc3X/yq7vIlX7j3u86yeX/W0dOXTv9xc6LrqP7jvs/OdV3a/cCeJ1Y8+N6Xv43mT0zcxWbMydC17y+KTSxpnbv+zZmHT4yuKmvV5/j7jn6/t9nvOlw5W9hCrPL5q5eHBz+cVVZResl7UaicSctajgQP1izY/PP+82e2b/n0r1PNrm/fmDh5KDT+yuCTvyh/5zcd+OeZY0097nnBNGY/LbztueMVg7PPlh24u+b1Y4dKT219a9aajr2Ll+3A8x+/M1I+uuGrxvHNFyJb0x99XVnx7OD96Z3o8/KzP5zZaP3+4ieDG1cMoYoL72w/t/bizSUlly/PKDm+/Ok6XFpS8i/VnBjV
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
eNqFVWtsFFUUbnkkqFEUjIQfhMvK409nO/vuFh+UbbEIpbUPeYVu7s7c7U47O3c6987SpTbGAqlEfIwv0BoSZdkla4E2gJoIKlHUgIkVjbEgkEhC1KAhKgHxB56Z7kKRBvfH5u4933l95zt3e3MpYjCFaqUDisaJgSUOP5jVmzNIp0kY35RNEp6gcqahvql5p2koI/MSnOussrwc64obazxhUF2R3BJNlqc85UnCGG4jLBOjcvpk6ZVuVxJ3RTntIBpzVSKP6PWXIVcRBTdru10GVQmcXCYjhgusEoVSNG5fJRSkJFGMxua4etbZjlQmqm2QVGzKRPAJjGoa4YIXAoteb9j255SqhdAaTjqhOU4pajrKCDakRNQgzFQ5i7aDs+0gEyYZim63boOr0CgOEa1N0QiiYEkqG4iM4tRA0KhukAT0o6RIGcKSZBqY2ydNRtwwGQdgIYMbtTASN1XHcT34oDQ1kUYAwSk4sPXEQA7PNusIx6jJEcQzoH1EUvANIZZqOtyyBDVVGcUIwsXywNFIu+0GFBsSZVKCJDF00O3SYSjE4IpDcbfLQTqn/7Q6NpJdkkppBzJ1h8W07lDHuKFoba6eHrizRaEYRLbJLQRdNwZKY+1E4gBd15NLECyDtF7MJCjj1tAtYtkHxBGdC0STqAwJrD1tGxS9DMkkrgKdecmeq6NGK99BiC5gFfjOjnpZg1jXVUXCtr3cHuNAQTSCXcut5rytLQEkp3Hr/apiHeUNadC2hkS3z+/2DnYJjGNFU0GcgoqhpKzu2D8ca9Cx1AFxhMLeWNlR571jMZRZu+qwVN90U0ibaWsXNpJB//6x94apgb6IlYs03JquYLyRzuf2eNyhoZsCs7QmWbviWGVk6DrJ113ysBs+QQwKomdvkSUVpM0T1s6A6N8NWtVBfWRjFkJyk/VmYCLkqy9zhS19p35ZcZpnSqZlqmE61uElhlKGvCHURHRk7x7yBCtFT6VfRI/VNQ9ECmmaxx3GULMB0o/DQGqKw89JCVPrIHI+Mu7YR1w32rKXTYV95ELhiYJh2T+tjF8UxZH5t0UasCCKZmfM+MLh8P/EBWYItw7Y/QliWPCGmke7DPjXjKDxPEffuUI9WbseqGjubZA36imi0W3R49fjC6/JF4oWFNk6BOeo6KmuTnR0tixuaazgy6TGmvjy9TWNCjvYJUgqNWWBw2NPBEcQXdwaQRX+gOz1xn1BjyRVhCpiPtGPpbg/RPxB2eP1xXamFGzlPW4PaqO0TSX7IkuECIYnR2hyZGPlqlevqKpbGhlYJTTSGAX+mjHwrFGNZJuIAXK08k5qWHCDZMG9sWq1daBCCkuxIA544uGgT/QGhMWwN0UBXRdIxn4dnD+VZ7KjL9LRUjT7uSklzmfi8pfql3266N6jHx+r2NZ6orFp7c+tmzaIm3d81l/7Q7zP/8EbWxbu/77h6ul5NUe+3Xj2H9Y148KEygsH92y7vG/LPad+O37RbG3JXfrz7dMPz2raPPlkxfCrrpaz0x7YPnfFJ++m2nfcfdeFeQ3VfXV/hYefCqzE8/u3Hf8Dr359bdngfcFY5HLq737/1R3HQp2rntg6YWH4zJEz8Tt/DEyaPzx95taXZwz2oYd8F58ns89NWX5/tvbJCV8/uL32uzvmnqi6cj49vHe2q6r/2YFzqdLX3jqy4M0lc2q/ELZPevSRny4dXhSY+Wt16+Zv5nTuFhZ8Ho384pse2vQC2zr5/KkFv/fOmjrS/srUWM1KLTj58feuqQc/an0aqLh2bWJJ36HzQaO0pORfBzAQdg==
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
eNqFVV9sU1UY39wD+KKMqKghcqzgg+62t+3d2i4+MDoQso0NNkRmluX03NP10tt7ruee260sC5Fh4p8IuZoYNegD61otExhiJMH/+oBBgolRM2I0IAaNYmKiSEIIfueuhSEL9qE5Pd/v+/f7ft/pjnKecsdgVv2UYQnKMRHww/F2lDl90qWO2FnKUZFherGnu7dvwuXGzIqMELbTGgph2whiS2Q4sw0SJCwXyodDOeo4eIg6xRTTC6fq/xwN5PDIoGBZajmBVhRWI1oTCtRQcPPEaIAzk8Ip4DqUB8BKGJRiCXm11rg/MDYgPZhOTXlDTOzqVIkqDrMsKpQIRFQjkYR0FIyZ1ZgWzvkxBc4bZmHQoZiTzCCnjmsKZ3ArOEsHnTqEG7bsWYLb0CwOUWvIsChiYMkZ26iO0owj6NDmNAONGHnahDAhLsdCniwdCe46AoDVDEG0yaFp1/Qdh8EHFZiLLAoIwcDBGaYc+QRLuhFOMVcgiMehb0Tz8A0h1lk23DoZ5po6SlGEa+WBIy8EZQOGhAw6JENzGDoYDdgwDcqF4XM7GvCR/uk/rc6NJEsyGcsi1/ZZLNg+dY7ghjUUGBuDO6kGg1NdklsNOjAHylJbKREAHRgrZyjWQVO7ixnmCG/6BpUcAOKoLRRqEaZDAu/toW2G3YR0mjaBzgqRc/Vl6FWylNoKNoHv0qyXdxDbtmkQLO0hOcapqloUWcuN5ooUlQJas4T3XlutjlBPAURtITUY1YKRgyOKI7BhmaBKxcRQUsn27UfnGmxMshBHqS6MV5p13j8XwxxvsguT7t7rQkqmvUnMcy3aO3PvuWuBvqhXTvbcmK5qvJYuGgyHg7Hp6wI7BYt4k2lsOnT6KslXXSqwG1FFbVHU8P4aSyZIW2S8CS0RexO0aoP66HgJQgrX2VGEidAvj5Wr67m3u6M2zR/qFhfbYTreB2u40YQiMdRLbSR3D4VbWtVwq6qhR7v6ppLVNH3zDmO6j4P00zCQ1bXhl0nGtbJUryTnHftM4FpbctlM2EehVN8mGJb86RU1VVVnHrwpksOCGJbMWIwmEon/iQvMUOEdlv0pakKJxPpmu2zW+mfQfJ6zD1y1npKsBypafhPktXpqaHRT9Pz1qFp/pVq0Yuje+3AeVMPrmb15deeax7ra9GQ7zXQazdqWtcl3RxRiMldXBLzyVPEFMSK8GaThqB6JtUTj8ZYEiUS1uE5xOE5icaKSdBxrE3kDe5VwMIyGGBsy6YHkGiWJ4clRen3ZeOX2LevbutYlpx5XNrIUA/76MPBsMYuWeikHOXoVPzUsOKclcN/YtsU7HCcJkmomJJzCNJJOE2UV7E1NQFcFUpSvg/9v8lRp9kX6/OSy5xfW+Z+Gzl0d2c/URTu3d5xrGt9X3P3L90nj2Iqzdz3X+O3iPQ8d3TW86cW7r/xz5qtV3Q0/PvJK48Cqj9fd3nX5yGh297J953Ov5ztDBzafPnF+tH7B0QtaeW3zfQtvGz97T/s365VDn5xe/mzkllNLO/Zu3fCW+tKmDy8cP3XpzqX9+IGWnZcvxgzx6vHhW0fKe36u/7o8/tpfJ1ZueLpx5Z57H2746bue1iVnXl505OzvPX989Okzuy6lXvhiyXTg4rnJ8TsunXyj9OuCurorVxrqflt9aPvf0MW/54vuGA==
|
||||
@@ -1 +0,0 @@
|
||||
eNqFVE9oHFUYj7RYWy/qIdBi7XSJipK3O7N/kt1ACem2SUtNN82upV3R8vbNtzuTnZ2ZzrxdktYSTBpEFONDyMGDUjPZrWvMJrZasLUQ04rF9mBPXQJV8OBBUDFeCkJ9s9lNUhLinN58f3/f7/e9N1IqgGWrhv7YtKpTsDCh/MdmIyULTufBpueLOaCKITt9sXhiMm+p1ecVSk27w+fDpurFOlUsw1SJlxg5X0Hy5cC2cQZsJ2XIQ9XsWU8OD56iRhZ029MhSKI/2Cp4GkHc8tpZj2VowE+evA2Wh3uJwZHo1DUp6l7PudfdDEMGzbUQDedlQAFkG7oOFPl5RdHvj3jOlRTAMh9m3FEMm7K5dfAqmBAwKQKdGLKqZ9gXmTOq2SrIkNYwhTJxK9bmZ+UsgImwphaguJzFZrFpairBrt83wLtP13EiOmTCenfZHQfxKXXKrnQ1cPj6hjibuiB6A0Gvf3YQ2RSrusb5QBrmkIpmzX91rcPEJMvroLpSrLicPLM2xrDZVC8msfgjJbFFFDaFrVxb8NJau5XXqZoDVor2rW9Xd662C3glyds+90hhe0gnbCqNNRvmVkheSSlzVQJIbEOiNNNgSQM9QxU2KYntFy2wTb5lMFrkJWneHnG4InD7h1J9MT6NHWmoeb/pGecAV4d9222prYK/XYiDKbiqC1Jbhyh1iAGhpzcxHa23SWwoxlzCwrqd5oIcbIhfIkpez4Jcjm4oe9WzOpbF+2tqTqWofim4WO4vc4KiKFZf2DTSghxnze3oBCKRyP/U5cwAZZfd+ZAYQf72xPKUoWCyKmyUuXy16niKLh6OqGWTyFU8jWhh0+iN8YiBZLkOGqkyu8bPp0TJX+g5FMoETbNPhTMnjukZ6UjyWPdXg4hoRl5GlD8vgGoLMUhZVQhJaWhvC4fTYdkfScvBFIhhWQqmAnIklArKZLKgYlaWvJKQMYyMBpVoN4piogCK19aGlQ6cPNrVezg6fQL1GymD85fAnGfd0KEYB4uvIyvXWvMLbkGRp/d3nWSXwyRCUiESDJBwyp9OE7Sf35vGAq0siOO+DrVn7C2+phY33biz590nmmrfllfevzOwID51/pMpe2L+9N3m37fvf3N7y5X+92bb5hP389c+/yD17x83L4x9/Pj1Bzj9z9PPjb6xaC3NzA0v/vnRr2Yltm3AW+q5tG9h/npPMu7smtn69uG7O0YGKs33fhEPOVvHvWPPfnav+eXb8sFXj1/9sjwQpt91a3/tWfrZ+Ymgzpsk9tKtJydi20I7F98Z2bEwGv564sXvKxfojzd2z9tHb+3tHH6wc994NfmhLzVW2d2yOPz3N62dHPfDh1ua8G8wusTP/wHDg2Hi
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
eNrFVs1u20YQbk8FfGrfYEu0zUWUSMk/EouicGU7DQzHjiUgcX5grJZjiTa5y+wuFSuGDnXzAnyE1ooUCHYSowF6aHrvoS+gHvos3ZWov1h2bioPIndmduabb2ZnddqpAxceo5+ee1QCx0SqhYhPOxyeRiDki3YAssbc1s52qXwWca/3dU3KUDiZDA69NKayxlnokTRhQaZuZwIQAldBtCrMbfRenBgBPt6X7AioMByUXUohY2ii1o9ODM58UF9GJIAbSkuYwkGlFpXB91EACKND5cBoPtGbmQu+VhIfRy6YOVMwSkGaWSu7aGWzBe1DSA44UFaSR9Ds1AC7Kst/P/m8VWNCxpdXkL/BhEAoTaCEuR6txhfV516YQi4c+FhCl+gYfWri7hFAaGLfq0N7sCt+i8PQ9wjW+syhwnOeJGHKRghX1V2dq6kooDJ+vyoalKwOwWR2Goptiqx0bjltvT02hcQe9RVjpo8VrnbY1/8xqQgxOVLOzKSScXuw+fWkDRPxyy1MtktTLjEntfgl5sHy4m+Tch5R6QUQd4o7V8MlynG4XNq20yuXU451UvFF/+X0fz12OWJ8tLWripYzrWXTsn+fCgGSN0zCVKT4F+v1kE0faFXW4jM7l33FQYSqUeHnttomI3HaUpWDv//qJN316/bmuO5ftNZUFeM/74ObQvYy2iYS6X5Bdt7JrjhLi+j2Vvm8mIQp66L1kIRjmYG6lgz66VtEapgLkN9F8sDMX5Y5puJAVXJ92DUdUovoEbjd4sx+uShiUgNTx1FdH7+izCRa0jPG1HAF1PcCT5rJAVSF18u4tWhZVu+bGy05BIpCjaSVKxQKH/GrKAQZv9NEmLZl2svlIR0Pe2jWzsExTvC0NR6F6KsbLMd4htboRutr8OQedhPQpufG79X3vmWXCkubh7u5xrN77vpBtFHYy9eLzzfO6h6Ou3baRlXGqj68KW6YA9ZL/TaJO2t7d1e37hTPH5i7rMIUDWWs6KKMQrsEXHVm3CU+i1x18Dm01fbd1b34Xd7NYbti5Qp52110rbz5w3apP+J+Uv3HVYb/fPa03ysOShpwX/UllwsulthBJ4aeBIZjTCmN1HBtOCeG52q9qKrcNh4EW+XSpheuB7d3+L27e3sra7uuMp/2ogSD6WlgITzlkvZdDibkDQNyPGMfPUmpYcnCfdXfysxwaOT7iUhoyimBoTAaAaVhJEcz3bZTBovklKjZRP2nubCQkJJE3K/4jBzNpmaGiYLqUReODcdKTes1jmSfPqeaGv1yDONK6FBV54NYyNBC4zp4ij+Jb4bXN5mCN5BMwxqZJeB+BA4DgHMPfUsk1yg6YHxI0uiZOxzUYJHzmD6m92uNMZr5wyCYJuHnXxGpKlLxSIP4gPTh/b+AuCgKUaUx2RTzL4QnBfgH36M78pboI5k/BPmMmdLrn9D51+DLqTN5/eBk4cfmJgsnol93zIf30MyEppTGRAJTV8XkP/uZV0Zz4s744IbILjWvATQrw0mdMZHLf6ahi3k=
|
||||
@@ -1 +0,0 @@
|
||||
eNqFVFtoHFUYTolC+6DGPoig6DikYjVnd2ZndzMbKzZuL2rZbmhWkqZoODvz7840szOTmbMhsSTUJFaxIBy0D9EX22x2yxqbhkYLSZVKo/hgvWC8rGBKKb6JBFGRIKlnNru5kBDn6cx//f7v/84ZLPSA4+qWuW1cNwk4WCHsx6WDBQe6s+CS4XwGiGapuZZ4a2I06+ilXRohttvk92Nb92GTaI5l64pPsTL+HtGfAdfFaXBzSUvtK/Wc4DO4t5NYXWC6fBMnCoFgA8dXg5jl2AnesQxgJz7rgsMzr2IxJCbxTG0aJpzuciL3BBd4mu9/0Uu2VDA8p2LgrApIQq5lmkBQgBUXAoEI31/QAKtsrvmaupxmuYRObsA6gRUFbILAVCxVN9P0g/TLut3AqZAyMIGi4tUsk0GLXQA2wobeA/nlLHoR27ahK9jz+4+z/uMV0Ij02bDRXfRmQ2xkk9DLzVUc/pY+Rq3JCT4p7BMu9iKXYN00GDnIwAxS3i77Z9Y6bKx0sTqosjaaX06+sDbGculYDCvx1nUlsaNodAw7mXDw0lq7kzWJngFaiLZsbFdxrraTfKLoa5xcV9jtMxU6lsKGC5MrJK+kFNleJCSEkSBeXlcaiNOHFIt1oGeFC1UCDTDTRKOjoiifd8C1mRphKM/SSNYdzLFlwZdfFCoCOhc/tLrqnbl9bHH04zZQGzgxzMUVwnmS4ES5KSA3BWXuYCwxHq20SWy6p8mEg003xXa1v6qLgqJlzS5Qi9FNFVHiVyd2WH9Dz+gEVS4P26P3S3NBQRBKj24Z6UCGMeN1zEmRSOR/6jJmgNApbz4kCkgMJ5anDAU7StxmmctXsIIn7+FhiOq3iFzFU43mtozeHE9Q7ihWQCNdpVfYuVMQQ23d4YNEFk1RS0J7RAwFDriZxg97kWJYWRUR9gwBKguil9ASJ6UkSRZCycakIAmhSESVQI4EcTgYUTGoycbRHh3TougTubRlpQ2YiB5AUaxogFrLsqGFfUcPN8eei463oyNW0mL8JTDj2bRMyLeCw5RKi+XW7O47kGfpR5qP0ilZlbCohOQQqGE5pabQM+xKVQW0IpCc93CUn7tXmEwdZpqde/j09pryV5t48/rzs3vrhjt3zX2/o/6t/eTqoatPNfQu5Pidp3Klu776W/3ul/eGr8yo3w4VBicGzt956+TJSw/OFAfmj52YnmnpspYWFuf2/P7S5x+dGhqIT409W//Qjrvdww+8zo9q6qvXIve8XfdNQas9E9s9MjL155kbL8zfuHb26/HZNxY++Tf2eH/m1/fvmPssdvP0a+c+XbzJvVMw84+N3Lt3Dzku3fqxbvr+7vh2Y3fkp7862oU/1J/1pfr7hhd/eOTdpej16SUG//bt2pptpd+e/Ied/wPrJ3ik
|
||||
@@ -1 +0,0 @@
|
||||
eNqFVFtoHFUYjqRSwSC13qA+dBi0iMnZnZm9JBuKIdlUMZoLydY2qTGcPfPv7jSzM+PM2bhpaNW0aoqiHARffIg1m92yrmmDrSmkBaVWS40SGwpdwRuC+FJqQayIEM9sdnMhIQ7zcM75b9//f985o7khsB3NNO4oaAYFGxPKNw4bzdnwYgoceiybBJow1UxXZ09kImVrxUcTlFpOo9eLLc2DDZqwTUsjHmImvUOyNwmOg+PgZKKmOlwcGhGTOD1AzUEwHLFRkCXFXyeIFSd+cmBEtE0d+EpMOWCL3EpMjsSg7tG+BKaC5giyUCsoTeLhfjfYVEF3jUTHKRWQDzmmYQBFCk8uKUpIPJxLAFZ5Xz9WbcskTIey6XVYT2FCwKIIDGKqmhFnH8cPaVadoEJMxxTyxM1ZGgbLDwJYCOvaEGSXothpbFm6RrBr9x7k9Qtl0IgOW7DenHd7Q7xlg7KZ5goOb9cwH60hSB5f0COdTiOHYs3Q+XCQjjmkrFWyz642WJgM8jyoTBvLLgVPrfYxHTbZjklnz5qU2CYJNontZND/yepzO2VQLQksF+5aX65sXCnn88iyp356TWJn2CBsMoZ1B6aXh7wckue8+JAURJI8syY1UHsYEZNXYCekqcoAdTDiNMEmZLnhpA2OxdUIR7M8jKac0QwnC+Yu58oC+rDzmRWqt2daOXHswj5Q6wQ5KHQSKriSEOSGRiXEf+Gp9kghXC4T2ZCn6YiNDSfGudpT0UWOJFLGIKj58IaKKIorHdu8vq4lNYrKl4fz6G5Zxi9JUnHXpp42JPlk3IoZXygU+p+8fDJA2Rm3PyRLSA5GlroM+PuKwkaRS1ewjCfr4uGIHtnEcwVPxVvY1HtjPEqoL18GjTSVnefrAUneCy0BpS0tB1r2d3MisdZntpE9Z9OI6GZKRZQ/Q4BKgkhTVhRA8dXLUa6imKrU1/tIwBfAIQC5ISjHfH5/dGJIwywve2QhbppxHU6Fn0RhTBKAekqyYbnW3o7m9qfDhf2o24yafH4RzOdsmAZke8DmSmX5Uml+923I8vDu5l52pkH1YVkNYCkqSyEpGEUt/EpVBLQskIz7cJSeu1e5TG1+9MXVnW/eVVX6qiNvf3PworTt2MClubPKdfuxyPyBjkszz7e0SfkL53ZduXJt6oPjt2YfeuOv+YXP6pvmRrVXLu79cir/zk4ycn38+8z4whPXbvzSfvPXu2v+DC68J97btL2mu+bhP8R3T8Zf+zxwz/0/z28d3/r4+92iT9NqZz8q/BD753Jbwbr59U+Zq7efOzIW7t/9wKdptKMQr/6u4aXj51tfr741r3W8NRD+vfa+21u+Cm05+u+53x58dnf8hv+FsTunjgTHehdPxPpf5uAXF6urDu0Y+fZvvv4PjzlyYA==
|
||||
@@ -1 +0,0 @@
|
||||
eNqFVFtoHFUYTokPKgiiFYq0OFncoJizO5fNZDeCNdk0aau5mKzG1pZ4dubPzjSzM9OZs2nWECE3bxXlPIgIBbHZ7Oo2bROSEqXqg82DSsVL2+AKaqUWX0SxL7aIxDOb3VxIiPN05r9+//d/54zk+sFxdcvcNqWbBBysEPbj0pGcA0dT4JKxbBKIZqmZjvau2ETK0Qt+jRDbrQ8Gsa0HsEk0x7J1JaBYyWC/EEyC6+IEuJm4paYL/YO+JB7oIVYfmK6vnhN4MVTD+cpBzPLcoM+xDGAnX8oFx8e8isWQmMQzdWuYcLrLCdwjnLjbN3TYS7ZUMDynYuCUCkhCrmWaQJDIivOiGPEN5TTAKpvrp4q7M5rlEjqzAetZrChgEwSmYqm6maCnEy/odg2nQq+BCeQVr2aRDJrvA7ARNvR+yC5n0Wls24auYM8fPML6T5VAI5K2YaM7782G2MgmofMNZRzBjjSj1uT4gCQH+OkB5BKsmwYjBxmYQcraRf/5tQ4bK32sDiqtjWaXk8+sjbFcOtmKlfaudSWxo2h0EjtJOTS71u6kTKIngeaiHRvblZyr7aSAIATqZtYVdtOmQid7seHCzArJKyl5thcJ8TLihfl1pYE4aaRYrAN9jz9TJtAAM0E0OiEI4fcdcG2mRhjNsjSSckcybFlw8fNcSUAn259YXfU9mSa2OPpJN6g1nCBz7QrhPElwQrhe4uslkWtpjU1FS21im+5pJuZg0+1lu9pT1kVO0VJmH6j56KaKKPhWJ3ZYf0NP6gSVLg/bo/dLMyGe5wvVW0Y6kGTMeB0zUiQS+Z+6jBkgdM6bDwk8EuTY8pS1oYMFbrPM5StYwpP18DBED24RuYqnHM1tGb05Hkk8mC+BRrpKP2bnHl5ofuqobodaUolYZ7eEY2pjW4smiOcGkGJYKRUR9gwBKgpigNACVydH4nI4HhGgThIFrMp8KKQoUi3Pi1iWa+WJfh3TvBAQuIRlJQw4G21GUaxogLqKsqG5pgNtDa37olPPok4rbjH+YpjxbFomZLvAYUql+WJrdvcdyLL0zoYDdC6sSlgA4CMRlY/wYh1qZFeqLKAVgWS8h6P43A0zmTrMtHDlgeO3VxS/ytgbX+2/8Pj28R7/idP37q0+991wYH/V8cCeQw/5X//CP9b2Z+ajYx13pI/t+3b8VOXPt365uKM+fGjSeu0GXNp9pXLo8tvzv3194doHP+zq6RsefvHNuezehb9vG334pfsGaMPl2c+u3v/onbY22r7r+tMB+k5ofvzH7Yt/PP9N8zPx8cF3l6rf+nTxxuGdX/5eNVt47NT0ibuarn3/5K9+cecr55svLdysHTNf/dAfbqvakfmntk65KugTfzXW2NcXuep/X87DrW0VFUtLlRVwZG7wJpvlP8uBc0g=
|
||||
@@ -1 +0,0 @@
|
||||
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
|
||||
@@ -1 +0,0 @@
|
||||
eNqFVF1sU1UcH4EQgh8jkviwGHdpNkzcTntv292uJSTUzokfc4M1OoZkOT33rL309t7Lved2K8semEuQzECOidHNgMC6FmvdWAbhQRiJEGIUH5SZWKMkU+ODihhYxPiC53btPrJl3qdz/5+//+//O2cgm8SGKWvqurysEmxARNiPSQeyBj5kYZMMZhKYxDQp3dbaHh61DLlQGyNENwMuF9RlJ1RJzNB0GTmRlnAlBVcCmyaMYjMd0aRU4XifIwF7u4gWx6rpCHAC7/bWc45yELPs73MYmoLZyWGZ2HAwL9IYEpXYpp4YJM+YXEqzDE6FCezoP2CnaxJWbDdSoCVh4AENwNRUFRPgZg140c3bdQhO6GwiYhl2ed7J92djGEps3tsVW9IxzSR0csUMExAhrBOAVaRJshqln0QPy3o9J+FuBRKcQ3afIkk0F8dYB1CRkzgzn0XPQ11XZARtv+sgw5QvDQNISscr3Tl7ZsCoUAm9FCzjcLWlGOUqg+wRnfz5XmASKKsKIw0okEHK6EX/p0sdOkRxVgeU1kkz88njS2M0k461QNTavqwkNFCMjkEjIXqnltoNSyVyAtNsqG1lu5JzsZ3HKQhO3+SywmZKRXSsGyomnlwgeSElx3blAbwIeOHSstKYGCmANNaBnuHHywQqWI2SGB0VvO5zBjZ1plL8ZoalEcscSLNl4ZufZ0vCOtv68uKqn0g3scXRK69jqZ4TRK4VEc6WCSf4Ax5PoMHHvdASzodKbcKr7mkybEDV7Ga7er6siyyKWWocS7nQqoooOBYnZhrEipyQCShdKrZH+5emvTzPF7avGWngBGPG7pj2+P3+/6nLmMGEXrDnAwIPBDFsT+kNNHg7C9xqmfNXs4QnY+NhiGrWiFzEU47m1oxeDQ9jXezMlUADWaKX2bmLF8QWEkniSE8qrvsO9xgopYY8ncGLvQApmiUBwp4nDIqC6CW0wCHkE/0SFn2i6PF4PW7kbkT+Rh77fA1+UWh0jyZlSHOCU+CimhZV8ESoGYQgimHQXpQNzTbtezXY8mIo3wH2ahGN8ReGjGdVU3GmHRtMqTRXbM3uvoEzLH1vcB+90Ch5oC+CBD9r7UWIB8+xK1UW0IJA0vbDUXwGjzCZGsx0/bfqoU0VxW99+PhXL13ftWWwC+eH3jtW8/W3ePxU09+nT592wN0j+JVvtt7amRd++bE2WHlq8/S/Z7oHNz5+5amPL/d+9+DO/d9nD+2ufjDd79958sbdDzY9cnJjZ3vNTyc2DAnJur8cwZmpz86eeMzSz+34sOoL59SB7XTYW3f/3rNXnWbHDH23Y/b2r1f3jE1cnD52Dbr/6HMHb94RCfxz7o1Hj4683Xxr60fDkcC1e+q2qqMHa1x0dtcP4ZHmGxPb5obfig/8PGM9Ke+4273h6Xdeq9ofOVK3eej9uervwZeVbKiHD9dXVFr/1Fatq6j4D8RVhls=
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user