chore: update branch with changes from master (#32277)

Co-authored-by: Maxime Grenu <69890511+cluster2600@users.noreply.github.com>
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: jmaillefaud <jonathan.maillefaud@evooq.ch>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
Co-authored-by: tanwirahmad <tanwirahmad@users.noreply.github.com>
Co-authored-by: Christophe Bornet <cbornet@hotmail.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niceg <79145285+growmuye@users.noreply.github.com>
Co-authored-by: Chaitanya varma <varmac301@gmail.com>
Co-authored-by: dishaprakash <57954147+dishaprakash@users.noreply.github.com>
Co-authored-by: Chester Curme <chester.curme@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Kanav Bansal <13186335+bansalkanav@users.noreply.github.com>
Co-authored-by: Aleksandr Filippov <71711753+alex-feel@users.noreply.github.com>
Co-authored-by: Alex Feel <afilippov@spotware.com>
This commit is contained in:
Mason Daugherty
2025-07-28 10:39:41 -04:00
committed by GitHub
parent 3496e1739e
commit 5e9eb19a83
449 changed files with 16481 additions and 5327 deletions

View File

@@ -1,72 +1,116 @@
### 1. Avoid Breaking Changes (Stable Public Interfaces)
# Global Development Guidelines for LangChain Projects
* Carefully preserve **function signatures**, argument positions, and names for any exported/public methods.
* Be cautious when **renaming**, **removing**, or **reordering** arguments — even small changes can break downstream consumers.
* Use keyword-only arguments or clearly mark experimental features to isolate unstable APIs.
## Core Development Principles
Bad:
### 1. Maintain Stable Public Interfaces ⚠️ CRITICAL
**Always attempt to preserve function signatures, argument positions, and names for exported/public methods.**
**Bad - Breaking Change:**
```python
def get_user(id, verbose=False): # Changed from `user_id`
pass
```
Good:
**Good - Stable Interface:**
```python
def get_user(user_id: str, verbose: bool = False): # Maintains stable interface
def get_user(user_id: str, verbose: bool = False) -> User:
"""Retrieve user by ID with optional verbose output."""
pass
```
🧠 *Ask yourself:* “Would this change break someone's code if they used it last week?”
**Before making ANY changes to public APIs:**
---
- Check if the function/class is exported in `__init__.py`
- Look for existing usage patterns in tests and examples
- Use keyword-only arguments for new parameters: `*, new_param: str = "default"`
- Mark experimental features clearly with docstring warnings (using reStructuredText, like `.. warning::`)
### 2. Simplify Code and Use Clear Variable Names
🧠 *Ask yourself:* "Would this change break someone's code if they used it last week?"
* Prefer descriptive, **self-explanatory variable names**. Avoid overly short or cryptic identifiers.
* Break up overly long or deeply nested functions for **readability and maintainability**.
* Avoid unnecessary abstraction or premature optimization.
* All generated Python code must include type hints and return types.
### 2. Code Quality Standards
Bad:
**All Python code MUST include type hints and return types.**
**Bad:**
```python
def p(u, d):
return [x for x in u if x not in d]
```
Good:
**Good:**
```python
def filter_unknown_users(users: List[str], known_users: Set[str]) -> List[str]:
def filter_unknown_users(users: list[str], known_users: set[str]) -> list[str]:
"""Filter out users that are not in the known users set.
Args:
users: List of user identifiers to filter.
known_users: Set of known/valid user identifiers.
Returns:
List of users that are not in the known_users set.
"""
return [user for user in users if user not in known_users]
```
---
**Style Requirements:**
### 3. Ensure Unit Tests Cover New and Updated Functionality
- Use descriptive, **self-explanatory variable names**. Avoid overly short or cryptic identifiers.
- Attempt to break up complex functions (>20 lines) into smaller, focused functions where it makes sense
- Avoid unnecessary abstraction or premature optimization
- Follow existing patterns in the codebase you're modifying
* Every new feature or bugfix should be **covered by a unit test**.
* Test edge cases and failure conditions.
* Use `pytest`, `unittest`, or the projects existing framework consistently.
### 3. Testing Requirements
Checklist:
**Every new feature or bugfix MUST be covered by unit tests.**
* [ ] Does the test suite fail if your new logic is broken?
* [ ] Are all expected behaviors exercised (happy path, invalid input, etc)?
* [ ] Do tests use fixtures or mocks where needed?
**Test Organization:**
---
- Unit tests: `tests/unit_tests/` (no network calls allowed)
- Integration tests: `tests/integration_tests/` (network calls permitted)
- Use `pytest` as the testing framework
### 4. Look for Suspicious or Risky Code
**Test Quality Checklist:**
* Watch out for:
- [ ] Tests fail when your new logic is broken
- [ ] Happy path is covered
- [ ] Edge cases and error conditions are tested
- [ ] Use fixtures/mocks for external dependencies
- [ ] Tests are deterministic (no flaky tests)
* Use of `eval()`, `exec()`, or `pickle` on user-controlled input.
* Silent failure modes (`except: pass`).
* Unreachable code or commented-out blocks.
* Race conditions or resource leaks (file handles, sockets, threads).
Checklist questions:
Bad:
- [ ] Does the test suite fail if your new logic is broken?
- [ ] Are all expected behaviors exercised (happy path, invalid input, etc)?
- [ ] Do tests use fixtures or mocks where needed?
```python
def test_filter_unknown_users():
"""Test filtering unknown users from a list."""
users = ["alice", "bob", "charlie"]
known_users = {"alice", "bob"}
result = filter_unknown_users(users, known_users)
assert result == ["charlie"]
assert len(result) == 1
```
### 4. Security and Risk Assessment
**Security Checklist:**
- No `eval()`, `exec()`, or `pickle` on user-controlled input
- Proper exception handling (no bare `except:`) and use a `msg` variable for error messages
- Remove unreachable/commented code before committing
- Race conditions or resource leaks (file handles, sockets, threads).
- Ensure proper resource cleanup (file handles, connections)
**Bad:**
```python
def load_config(path):
@@ -74,7 +118,7 @@ def load_config(path):
return eval(f.read()) # ⚠️ Never eval config
```
Good:
**Good:**
```python
import json
@@ -84,68 +128,198 @@ def load_config(path: str) -> dict:
return json.load(f)
```
---
### 5. Documentation Standards
### 5. Use Google-Style Docstrings (with Args section)
**Use Google-style docstrings with Args section for all public functions.**
* All public functions should include a **Google-style docstring**.
* Include an `Args:` section where relevant.
* Types should NOT be written in the docstring — use type hints instead.
Bad:
**Insufficient Documentation:**
```python
def send_email(to, msg):
"""Send an email to a recipient."""
```
Good:
**Complete Documentation:**
```python
def send_email(to: str, msg: str) -> None:
def send_email(to: str, msg: str, *, priority: str = "normal") -> bool:
"""
Sends an email to a recipient.
Send an email to a recipient with specified priority.
Args:
to: The email address of the recipient.
msg: The message body.
msg: The message body to send.
priority: Email priority level (``'low'``, ``'normal'``, ``'high'``).
Returns:
True if email was sent successfully, False otherwise.
Raises:
InvalidEmailError: If the email address format is invalid.
SMTPConnectionError: If unable to connect to email server.
"""
```
**Documentation Guidelines:**
- Types go in function signatures, NOT in docstrings
- Focus on "why" rather than "what" in descriptions
- Document all parameters, return values, and exceptions
- Keep descriptions concise but clear
- Use reStructuredText for docstrings to enable rich formatting
📌 *Tip:* Keep descriptions concise but clear. Only document return values if non-obvious.
### 6. Architectural Improvements
**When you encounter code that could be improved, suggest better designs:**
**Poor Design:**
```python
def process_data(data, db_conn, email_client, logger):
# Function doing too many things
validated = validate_data(data)
result = db_conn.save(validated)
email_client.send_notification(result)
logger.log(f"Processed {len(data)} items")
return result
```
**Better Design:**
```python
@dataclass
class ProcessingResult:
"""Result of data processing operation."""
items_processed: int
success: bool
errors: List[str] = field(default_factory=list)
class DataProcessor:
"""Handles data validation, storage, and notification."""
def __init__(self, db_conn: Database, email_client: EmailClient):
self.db = db_conn
self.email = email_client
def process(self, data: List[dict]) -> ProcessingResult:
"""Process and store data with notifications."""
validated = self._validate_data(data)
result = self.db.save(validated)
self._notify_completion(result)
return result
```
**Design Improvement Areas:**
If there's a **cleaner**, **more scalable**, or **simpler** design, highlight it and suggest improvements that would:
- Reduce code duplication through shared utilities
- Make unit testing easier
- Improve separation of concerns (single responsibility)
- Make unit testing easier through dependency injection
- Add clarity without adding complexity
- Prefer dataclasses for structured data
## Development Tools & Commands
### Package Management
```bash
# Add package
uv add package-name
# Sync project dependencies
uv sync
uv lock
```
### Testing
```bash
# Run unit tests (no network)
make test
# Don't run integration tests, as API keys must be set
# Run specific test file
uv run --group test pytest tests/unit_tests/test_specific.py
```
### Code Quality
```bash
# Lint code
make lint
# Format code
make format
# Type checking
uv run --group lint mypy .
```
### Dependency Management Patterns
**Local Development Dependencies:**
```toml
[tool.uv.sources]
langchain-core = { path = "../core", editable = true }
langchain-tests = { path = "../standard-tests", editable = true }
```
**For tools, use the `@tool` decorator from `langchain_core.tools`:**
```python
from langchain_core.tools import tool
@tool
def search_database(query: str) -> str:
"""Search the database for relevant information.
Args:
query: The search query string.
"""
# Implementation here
return results
```
## Commit Standards
**Use Conventional Commits format for PR titles:**
- `feat(core): add multi-tenant support`
- `fix(cli): resolve flag parsing error`
- `docs: update API usage examples`
- `docs(openai): update API usage examples`
## Framework-Specific Guidelines
- Follow the existing patterns in `langchain-core` for base abstractions
- Use `langchain_core.callbacks` for execution tracking
- Implement proper streaming support where applicable
- Avoid deprecated components like legacy `LLMChain`
### Partner Integrations
- Follow the established patterns in existing partner libraries
- Implement standard interfaces (`BaseChatModel`, `BaseEmbeddings`, etc.)
- Include comprehensive integration tests
- Document API key requirements and authentication
---
### 6. Propose Better Designs When Applicable
## Quick Reference Checklist
* If there's a **cleaner**, **more scalable**, or **simpler** design, highlight it.
* Suggest improvements, even if they require some refactoring — especially if the new code would:
Before submitting code changes:
* Reduce duplication
* Make unit testing easier
* Improve separation of concerns
* Add clarity without adding complexity
Instead of:
```python
def save(data, db_conn):
# manually serializes fields
```
You might suggest:
```python
# Suggest using dataclasses or Pydantic for automatic serialization and validation
```
### 7. Misc
* When suggesting package installation commands, use `uv pip install` as this project uses `uv`.
* When creating tools for agents, use the @tool decorator from langchain_core.tools. The tool's docstring serves as its functional description for the agent.
* Avoid suggesting deprecated components, such as the legacy LLMChain.
* We use Conventional Commits format for pull request titles. Example PR titles:
* feat(core): add multitenant support
* fix(cli): resolve flag parsing error
* docs: update API usage examples
* docs(openai): update API usage examples
- [ ] **Breaking Changes**: Verified no public API changes
- [ ] **Type Hints**: All functions have complete type annotations
- [ ] **Tests**: New functionality is fully tested
- [ ] **Security**: No dangerous patterns (eval, silent failures, etc.)
- [ ] **Documentation**: Google-style docstrings for public functions
- [ ] **Code Quality**: `make lint` and `make format` pass
- [ ] **Architecture**: Suggested improvements where applicable
- [ ] **Commit Message**: Follows Conventional Commits format

View File

@@ -16,6 +16,7 @@ LANGCHAIN_DIRS = [
"libs/core",
"libs/text-splitters",
"libs/langchain",
"libs/langchain_v1",
]
# when set to True, we are ignoring core dependents

View File

@@ -73,6 +73,7 @@ def main():
for p in package_yaml["packages"]
if (p["repo"].startswith("langchain-ai/") or p.get("include_in_api_ref"))
and p["repo"] != "langchain-ai/langchain"
and p["name"] != "langchain-ai21" # Skip AI21 due to dependency conflicts
])
# Move libraries to their new locations
@@ -82,6 +83,7 @@ def main():
if not p.get("disabled", False)
and (p["repo"].startswith("langchain-ai/") or p.get("include_in_api_ref"))
and p["repo"] != "langchain-ai/langchain"
and p["name"] != "langchain-ai21" # Skip AI21 due to dependency conflicts
])
# Delete ones without a pyproject.toml

View File

@@ -1,4 +1,4 @@
name: compile-integration-test
name: '🔗 Compile Integration Tests'
on:
workflow_call:
@@ -25,24 +25,24 @@ jobs:
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: 'Python ${{ inputs.python-version }}'
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ inputs.python-version }} + uv
- name: '🐍 Set up Python ${{ inputs.python-version }} + UV'
uses: "./.github/actions/uv_setup"
with:
python-version: ${{ inputs.python-version }}
- name: Install integration dependencies
- name: '📦 Install Integration Dependencies'
shell: bash
run: uv sync --group test --group test_integration
- name: Check integration tests compile
- name: '🔗 Check Integration Tests Compile'
shell: bash
run: uv run pytest -m compile tests/integration_tests
- name: Ensure the tests did not create any additional files
- name: '🧹 Verify Clean Working Directory'
shell: bash
run: |
set -eu

View File

@@ -1,4 +1,4 @@
name: Integration Tests
name: '🚀 Integration Tests'
on:
workflow_dispatch:
@@ -24,20 +24,20 @@ jobs:
run:
working-directory: ${{ inputs.working-directory }}
runs-on: ubuntu-latest
name: Python ${{ inputs.python-version }}
name: '🚀 Integration Tests (Python ${{ inputs.python-version }})'
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ inputs.python-version }} + uv
- name: '🐍 Set up Python ${{ inputs.python-version }} + UV'
uses: "./.github/actions/uv_setup"
with:
python-version: ${{ inputs.python-version }}
- name: Install dependencies
- name: '📦 Install Integration Dependencies'
shell: bash
run: uv sync --group test --group test_integration
- name: Run integration tests
- name: '🚀 Run Integration Tests'
shell: bash
env:
AI21_API_KEY: ${{ secrets.AI21_API_KEY }}

View File

@@ -1,4 +1,6 @@
name: lint
name: '🧹 Code Linting'
# Runs code quality checks using ruff, mypy, and other linting tools
# Checks both package code and test code for consistency
on:
workflow_call:
@@ -24,19 +26,21 @@ env:
UV_FROZEN: "true"
jobs:
# Linting job - runs quality checks on package and test code
build:
name: "make lint #${{ inputs.python-version }}"
name: 'Python ${{ inputs.python-version }}'
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: '📋 Checkout Code'
uses: actions/checkout@v4
- name: Set up Python ${{ inputs.python-version }} + uv
- name: '🐍 Set up Python ${{ inputs.python-version }} + UV'
uses: "./.github/actions/uv_setup"
with:
python-version: ${{ inputs.python-version }}
- name: Install dependencies
- name: '📦 Install Lint & Typing Dependencies'
# Also installs dev/lint/test/typing dependencies, to ensure we have
# type hints for as many of our libraries as possible.
# This helps catch errors that require dependencies to be spotted, for example:
@@ -49,12 +53,12 @@ jobs:
run: |
uv sync --group lint --group typing
- name: Analysing the code with our lint
- name: '🔍 Analyze Package Code with Linters'
working-directory: ${{ inputs.working-directory }}
run: |
make lint_package
- name: Install unit test dependencies
- name: '📦 Install Unit Test Dependencies'
# Also installs dev/lint/test/typing dependencies, to ensure we have
# type hints for as many of our libraries as possible.
# This helps catch errors that require dependencies to be spotted, for example:
@@ -67,13 +71,13 @@ jobs:
working-directory: ${{ inputs.working-directory }}
run: |
uv sync --inexact --group test
- name: Install unit+integration test dependencies
- 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
- name: Analysing the code with our lint
- name: '🔍 Analyze Test Code with Linters'
working-directory: ${{ inputs.working-directory }}
run: |
make lint_tests

View File

@@ -1,5 +1,5 @@
name: Release
run-name: Release ${{ inputs.working-directory }} by @${{ github.actor }}
name: '🚀 Package Release'
run-name: '🚀 Release ${{ inputs.working-directory }} by @${{ github.actor }}'
on:
workflow_call:
inputs:
@@ -18,7 +18,7 @@ on:
required: false
type: boolean
default: false
description: "Release from a non-master branch (danger!)"
description: "Release from a non-master branch (danger!) - Only use for hotfixes"
env:
PYTHON_VERSION: "3.11"
@@ -26,6 +26,8 @@ env:
UV_NO_SYNC: "true"
jobs:
# Build the distribution package and extract version info
# Runs in isolated environment with minimal permissions for security
build:
if: github.ref == 'refs/heads/master' || inputs.dangerous-nonmaster-release
environment: Scheduled testing

View File

@@ -1,4 +1,6 @@
name: test
name: '🧪 Unit Testing'
# Runs unit tests with both current and minimum supported dependency versions
# to ensure compatibility across the supported range
on:
workflow_call:
@@ -20,31 +22,33 @@ env:
UV_NO_SYNC: "true"
jobs:
# Main test job - runs unit tests with current deps, then retests with minimum versions
build:
defaults:
run:
working-directory: ${{ inputs.working-directory }}
runs-on: ubuntu-latest
timeout-minutes: 20
name: "make test #${{ inputs.python-version }}"
name: 'Python ${{ inputs.python-version }}'
steps:
- uses: actions/checkout@v4
- name: '📋 Checkout Code'
uses: actions/checkout@v4
- name: Set up Python ${{ inputs.python-version }} + uv
- name: '🐍 Set up Python ${{ inputs.python-version }} + UV'
uses: "./.github/actions/uv_setup"
id: setup-python
with:
python-version: ${{ inputs.python-version }}
- name: Install dependencies
- name: '📦 Install Test Dependencies'
shell: bash
run: uv sync --group test --dev
- name: Run core tests
- name: '🧪 Run Core Unit Tests'
shell: bash
run: |
make test
- name: Get minimum versions
- name: '🔍 Calculate Minimum Dependency Versions'
working-directory: ${{ inputs.working-directory }}
id: min-version
shell: bash
@@ -55,7 +59,7 @@ jobs:
echo "min-versions=$min_versions" >> "$GITHUB_OUTPUT"
echo "min-versions=$min_versions"
- name: Run unit tests with minimum dependency versions
- name: '🧪 Run Tests with Minimum Dependencies'
if: ${{ steps.min-version.outputs.min-versions != '' }}
env:
MIN_VERSIONS: ${{ steps.min-version.outputs.min-versions }}
@@ -64,7 +68,7 @@ jobs:
make tests
working-directory: ${{ inputs.working-directory }}
- name: Ensure the tests did not create any additional files
- name: '🧹 Verify Clean Working Directory'
shell: bash
run: |
set -eu

View File

@@ -1,4 +1,4 @@
name: test_doc_imports
name: '📑 Documentation Import Testing'
on:
workflow_call:
@@ -18,29 +18,30 @@ jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 20
name: "check doc imports #${{ inputs.python-version }}"
name: '🔍 Check Doc Imports (Python ${{ inputs.python-version }})'
steps:
- uses: actions/checkout@v4
- name: '📋 Checkout Code'
uses: actions/checkout@v4
- name: Set up Python ${{ inputs.python-version }} + uv
- name: '🐍 Set up Python ${{ inputs.python-version }} + UV'
uses: "./.github/actions/uv_setup"
with:
python-version: ${{ inputs.python-version }}
- name: Install dependencies
- name: '📦 Install Test Dependencies'
shell: bash
run: uv sync --group test
- name: Install langchain editable
- name: '📦 Install LangChain in Editable Mode'
run: |
VIRTUAL_ENV=.venv uv pip install langchain-experimental langchain-community -e libs/core libs/langchain
- name: Check doc imports
- name: '🔍 Validate Documentation Import Statements'
shell: bash
run: |
uv run python docs/scripts/check_imports.py
- name: Ensure the test did not create any additional files
- name: '🧹 Verify Clean Working Directory'
shell: bash
run: |
set -eu

View File

@@ -1,4 +1,4 @@
name: test pydantic intermediate versions
name: '🐍 Pydantic Version Testing'
on:
workflow_call:
@@ -31,29 +31,30 @@ jobs:
working-directory: ${{ inputs.working-directory }}
runs-on: ubuntu-latest
timeout-minutes: 20
name: "make test # pydantic: ~=${{ inputs.pydantic-version }}, python: ${{ inputs.python-version }}, "
name: 'Pydantic ~=${{ inputs.pydantic-version }}'
steps:
- uses: actions/checkout@v4
- name: '📋 Checkout Code'
uses: actions/checkout@v4
- name: Set up Python ${{ inputs.python-version }} + uv
- name: '🐍 Set up Python ${{ inputs.python-version }} + UV'
uses: "./.github/actions/uv_setup"
with:
python-version: ${{ inputs.python-version }}
- name: Install dependencies
- name: '📦 Install Test Dependencies'
shell: bash
run: uv sync --group test
- name: Overwrite pydantic version
- name: '🔄 Install Specific Pydantic Version'
shell: bash
run: VIRTUAL_ENV=.venv uv pip install pydantic~=${{ inputs.pydantic-version }}
- name: Run core tests
- name: '🧪 Run Core Tests'
shell: bash
run: |
make test
- name: Ensure the tests did not create any additional files
- name: '🧹 Verify Clean Working Directory'
shell: bash
run: |
set -eu

View File

@@ -1,4 +1,4 @@
name: test-release
name: '🧪 Test Release Package'
on:
workflow_call:
@@ -29,7 +29,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python + uv
- name: '🐍 Set up Python + UV'
uses: "./.github/actions/uv_setup"
with:
python-version: ${{ env.PYTHON_VERSION }}
@@ -45,17 +45,17 @@ jobs:
# > It is strongly advised to separate jobs for building [...]
# > from the publish job.
# https://github.com/pypa/gh-action-pypi-publish#non-goals
- name: Build project for distribution
- name: '📦 Build Project for Distribution'
run: uv build
working-directory: ${{ inputs.working-directory }}
- name: Upload build
- name: '⬆️ Upload Build Artifacts'
uses: actions/upload-artifact@v4
with:
name: test-dist
path: ${{ inputs.working-directory }}/dist/
- name: Check Version
- name: '🔍 Extract Version Information'
id: check-version
shell: python
working-directory: ${{ inputs.working-directory }}

View File

@@ -1,17 +1,20 @@
name: API Docs Build
name: '📚 API Documentation Build'
# Runs daily or can be triggered manually for immediate updates
on:
workflow_dispatch:
schedule:
- cron: '0 13 * * *'
- cron: '0 13 * * *' # Daily at 1PM UTC
env:
PYTHON_VERSION: "3.11"
jobs:
# Only runs on main repository to prevent unnecessary builds on forks
build:
if: github.repository == 'langchain-ai/langchain' || github.event_name != 'schedule'
runs-on: ubuntu-latest
permissions: write-all
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
@@ -22,7 +25,7 @@ jobs:
path: langchain-api-docs-html
token: ${{ secrets.TOKEN_GITHUB_API_DOCS_HTML }}
- name: Get repos with yq
- name: '📋 Extract Repository List with yq'
id: get-unsorted-repos
uses: mikefarah/yq@master
with:
@@ -41,7 +44,7 @@ jobs:
| .repo
' langchain/libs/packages.yml
- name: Parse YAML and checkout repos
- name: '📋 Parse YAML & Checkout Repositories'
env:
REPOS_UNSORTED: ${{ steps.get-unsorted-repos.outputs.result }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -49,48 +52,59 @@ jobs:
# Get unique repositories
REPOS=$(echo "$REPOS_UNSORTED" | sort -u)
# Checkout each unique repository that is in langchain-ai org
# Checkout each unique repository
for repo in $REPOS; do
# Validate repository format (allow any org with proper format)
if [[ ! "$repo" =~ ^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$ ]]; then
echo "Error: Invalid repository format: $repo"
exit 1
fi
REPO_NAME=$(echo $repo | cut -d'/' -f2)
# Additional validation for repo name
if [[ ! "$REPO_NAME" =~ ^[a-zA-Z0-9_.-]+$ ]]; then
echo "Error: Invalid repository name: $REPO_NAME"
exit 1
fi
echo "Checking out $repo to $REPO_NAME"
git clone --depth 1 https://github.com/$repo.git $REPO_NAME
done
- name: Setup Python ${{ env.PYTHON_VERSION }}
- 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
- name: '📦 Install Initial Python Dependencies'
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
- name: '📦 Organize Library Directories'
run: python langchain/.github/scripts/prep_api_docs_build.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Rm old html
- name: '🧹 Remove Old HTML Files'
run:
rm -rf langchain-api-docs-html/api_reference_build/html
- name: Install dependencies
- name: '📦 Install Documentation 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
- name: '🔧 Configure Git Settings'
working-directory: langchain
run: |
git config --local user.email "actions@github.com"
git config --local user.name "Github Actions"
- name: Build docs
- name: '📚 Build API Documentation'
working-directory: langchain
run: |
python docs/api_reference/create_api_rst.py

View File

@@ -1,4 +1,4 @@
name: Check Broken Links
name: '🔗 Check Broken Links'
on:
workflow_dispatch:
@@ -14,15 +14,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js 18.x
- name: '🟢 Setup Node.js 18.x'
uses: actions/setup-node@v4
with:
node-version: 18.x
cache: "yarn"
cache-dependency-path: ./docs/yarn.lock
- name: Install dependencies
- name: '📦 Install Node Dependencies'
run: yarn install --immutable --mode=skip-build
working-directory: ./docs
- name: Check broken links
- name: '🔍 Scan Documentation for Broken Links'
run: yarn check-broken-links
working-directory: ./docs

View File

@@ -1,4 +1,6 @@
name: Check `core` Version Equality
name: '🔍 Check `core` Version Equality'
# Ensures version numbers in pyproject.toml and version.py stay in sync
# Prevents releases with mismatched version numbers
on:
pull_request:
@@ -16,7 +18,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Check version equality
- name: '✅ Verify pyproject.toml & version.py Match'
run: |
PYPROJECT_VERSION=$(grep -Po '(?<=^version = ")[^"]*' libs/core/pyproject.toml)
VERSION_PY_VERSION=$(grep -Po '(?<=^VERSION = ")[^"]*' libs/core/langchain_core/version.py)

View File

@@ -1,4 +1,4 @@
name: CI
name: '🔧 CI'
on:
push:
@@ -6,6 +6,7 @@ on:
pull_request:
merge_group:
# Optimizes CI performance by canceling redundant workflow runs
# 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.
#
@@ -24,16 +25,23 @@ env:
UV_NO_SYNC: "true"
jobs:
# This job analyzes which files changed and creates a dynamic test matrix
# to only run tests/lints for the affected packages, improving CI efficiency
build:
name: 'Detect Changes & Set Matrix'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- name: '📋 Checkout Code'
uses: actions/checkout@v4
- name: '🐍 Setup Python 3.11'
uses: actions/setup-python@v5
with:
python-version: '3.11'
- id: files
- name: '📂 Get Changed Files'
id: files
uses: Ana06/get-changed-files@v2.3.0
- id: set-matrix
- name: '🔍 Analyze Changed Files & Generate Build Matrix'
id: set-matrix
run: |
python -m pip install packaging requests
python .github/scripts/check_diff.py ${{ steps.files.outputs.all }} >> $GITHUB_OUTPUT
@@ -45,8 +53,8 @@ jobs:
dependencies: ${{ steps.set-matrix.outputs.dependencies }}
test-doc-imports: ${{ steps.set-matrix.outputs.test-doc-imports }}
test-pydantic: ${{ steps.set-matrix.outputs.test-pydantic }}
# Run linting only on packages that have changed files
lint:
name: cd ${{ matrix.job-configs.working-directory }}
needs: [ build ]
if: ${{ needs.build.outputs.lint != '[]' }}
strategy:
@@ -59,8 +67,8 @@ jobs:
python-version: ${{ matrix.job-configs.python-version }}
secrets: inherit
# Run unit tests only on packages that have changed files
test:
name: cd ${{ matrix.job-configs.working-directory }}
needs: [ build ]
if: ${{ needs.build.outputs.test != '[]' }}
strategy:
@@ -73,8 +81,8 @@ jobs:
python-version: ${{ matrix.job-configs.python-version }}
secrets: inherit
# Test compatibility with different Pydantic versions for affected packages
test-pydantic:
name: cd ${{ matrix.job-configs.working-directory }}
needs: [ build ]
if: ${{ needs.build.outputs.test-pydantic != '[]' }}
strategy:
@@ -95,12 +103,12 @@ jobs:
job-configs: ${{ fromJson(needs.build.outputs.test-doc-imports) }}
fail-fast: false
uses: ./.github/workflows/_test_doc_imports.yml
secrets: inherit
with:
python-version: ${{ matrix.job-configs.python-version }}
secrets: inherit
# Verify integration tests compile without actually running them (faster feedback)
compile-integration-tests:
name: cd ${{ matrix.job-configs.working-directory }}
needs: [ build ]
if: ${{ needs.build.outputs.compile-integration-tests != '[]' }}
strategy:
@@ -113,8 +121,9 @@ jobs:
python-version: ${{ matrix.job-configs.python-version }}
secrets: inherit
# Run extended test suites that require additional dependencies
extended-tests:
name: "cd ${{ matrix.job-configs.working-directory }} / make extended_tests #${{ matrix.job-configs.python-version }}"
name: 'Extended Tests'
needs: [ build ]
if: ${{ needs.build.outputs.extended-tests != '[]' }}
strategy:
@@ -130,12 +139,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.job-configs.python-version }} + uv
- name: '🐍 Set up Python ${{ matrix.job-configs.python-version }} + UV'
uses: "./.github/actions/uv_setup"
with:
python-version: ${{ matrix.job-configs.python-version }}
- name: Install dependencies and run extended tests
- name: '📦 Install Dependencies & Run Extended Tests'
shell: bash
run: |
echo "Running extended tests, installing dependencies with uv..."
@@ -144,7 +153,7 @@ jobs:
VIRTUAL_ENV=.venv uv pip install -r extended_testing_deps.txt
VIRTUAL_ENV=.venv make extended_tests
- name: Ensure the tests did not create any additional files
- name: '🧹 Verify Clean Working Directory'
shell: bash
run: |
set -eu
@@ -156,8 +165,9 @@ jobs:
# and `set -e` above will cause the step to fail.
echo "$STATUS" | grep 'nothing to commit, working tree clean'
# Final status check - ensures all required jobs passed before allowing merge
ci_success:
name: "CI Success"
name: '✅ CI Success'
needs: [build, lint, test, compile-integration-tests, extended-tests, test-doc-imports, test-pydantic]
if: |
always()
@@ -167,7 +177,7 @@ jobs:
RESULTS_JSON: ${{ toJSON(needs.*.result) }}
EXIT_CODE: ${{!contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && '0' || '1'}}
steps:
- name: "CI Success"
- name: '🎉 All Checks Passed'
run: |
echo $JOBS_JSON
echo $RESULTS_JSON

View File

@@ -1,4 +1,4 @@
name: Integration Docs Lint
name: '📑 Integration Docs Lint'
on:
push:
@@ -33,6 +33,6 @@ jobs:
*.ipynb
*.md
*.mdx
- name: Check new docs
- name: '🔍 Check New Documentation Templates'
run: |
python docs/scripts/check_templates.py ${{ steps.files.outputs.added }}

View File

@@ -1,35 +0,0 @@
name: CI / cd . / make spell_check
on:
push:
branches: [master, v0.1, v0.2]
pull_request:
permissions:
contents: read
jobs:
codespell:
name: (Check for spelling errors)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Dependencies
run: |
pip install toml
- name: Extract Ignore Words List
run: |
# Use a Python script to extract the ignore words list from pyproject.toml
python .github/workflows/extract_ignored_words_list.py
id: extract_ignore_words
# - name: Codespell
# uses: codespell-project/actions-codespell@v2
# with:
# skip: guide_imports.json,*.ambr,./cookbook/data/imdb_top_1000.csv,*.lock
# ignore_words_list: ${{ steps.extract_ignore_words.outputs.ignore_words_list }}
# exclude_file: ./.github/workflows/codespell-exclude

View File

@@ -1,4 +1,4 @@
name: CodSpeed
name: '⚡ CodSpeed'
on:
push:
@@ -18,7 +18,7 @@ env:
jobs:
codspeed:
name: Run benchmarks
name: 'Benchmark'
runs-on: ubuntu-latest
strategy:
matrix:
@@ -38,7 +38,7 @@ jobs:
- uses: actions/checkout@v4
# We have to use 3.12 as 3.13 is not yet supported
- name: Install uv
- name: '📦 Install UV Package Manager'
uses: astral-sh/setup-uv@v6
with:
python-version: "3.12"
@@ -47,11 +47,11 @@ jobs:
with:
python-version: "3.12"
- name: Install dependencies
- name: '📦 Install Test Dependencies'
run: uv sync --group test
working-directory: ${{ matrix.working-directory }}
- name: Run benchmarks ${{ matrix.working-directory }}
- name: '⚡ Run Benchmarks: ${{ matrix.working-directory }}'
uses: CodSpeedHQ/action@v3
with:
token: ${{ secrets.CODSPEED_TOKEN }}

View File

@@ -1,4 +1,4 @@
name: LangChain People
name: '👥 LangChain People'
on:
schedule:
@@ -14,13 +14,13 @@ jobs:
permissions:
contents: write
steps:
- name: Dump GitHub context
- name: '📋 Dump GitHub Context'
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v4
# Ref: https://github.com/actions/runner/issues/2033
- name: Fix git safe.directory in container
- name: '🔧 Fix Git Safe Directory in Container'
run: mkdir -p /home/runner/work/_temp/_github_home && printf "[safe]\n\tdirectory = /github/workspace" > /home/runner/work/_temp/_github_home/.gitconfig
- uses: ./.github/actions/people
with:

View File

@@ -4,6 +4,7 @@
# Purpose:
# Enforces Conventional Commits format for pull request titles to maintain a
# clear, consistent, and machine-readable change history across our repository.
# This helps with automated changelog generation and semantic versioning.
#
# Enforced Commit Message Format (Conventional Commits 1.0.0):
# <type>[optional scope]: <description>
@@ -45,7 +46,7 @@
# • Conventional Commits spec: https://www.conventionalcommits.org/en/v1.0.0/
# -----------------------------------------------------------------------------
name: PR Title Lint
name: '🏷️ PR Title Lint'
permissions:
pull-requests: read
@@ -55,11 +56,12 @@ on:
types: [opened, edited, synchronize]
jobs:
# Validates that PR title follows Conventional Commits specification
lint-pr-title:
name: Validate PR Title
name: 'Validate PR Title Format'
runs-on: ubuntu-latest
steps:
- name: Validate PR Title
- name: '✅ Validate Conventional Commits Format'
uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -81,6 +83,7 @@ jobs:
core
cli
langchain
langchain_v1
standard-tests
text-splitters
docs

View File

@@ -1,4 +1,4 @@
name: Run Notebooks
name: '📝 Run Documentation Notebooks'
on:
workflow_dispatch:
@@ -24,43 +24,43 @@ jobs:
build:
runs-on: ubuntu-latest
if: github.repository == 'langchain-ai/langchain' || github.event_name != 'schedule'
name: "Test docs"
name: '📑 Test Documentation Notebooks'
steps:
- uses: actions/checkout@v4
- name: Set up Python + uv
- 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'
- name: '🔐 Authenticate to Google Cloud'
id: 'auth'
uses: google-github-actions/auth@v2
with:
credentials_json: '${{ secrets.GOOGLE_CREDENTIALS }}'
- name: Configure AWS 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
- name: '📦 Install Dependencies'
run: |
uv sync --group dev --group test
- name: Pre-download files
- name: '📦 Pre-download Test 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
- name: '🔧 Prepare Notebooks for CI'
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
- name: '🚀 Execute Notebooks'
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}

View File

@@ -1,7 +1,7 @@
name: Scheduled Tests
name: '⏰ Scheduled Integration Tests'
on:
workflow_dispatch: # Allows to trigger the workflow manually in GitHub UI
workflow_dispatch: # Allows maintainers to trigger the workflow manually in GitHub UI
inputs:
working-directory-force:
type: string
@@ -10,7 +10,7 @@ on:
type: string
description: "Python version to use - defaults to 3.9 and 3.11 in matrix - example value: 3.9"
schedule:
- cron: '0 13 * * *'
- cron: '0 13 * * *' # Runs daily at 1PM UTC (9AM EDT/6AM PDT)
permissions:
contents: read
@@ -22,14 +22,16 @@ env:
POETRY_LIBS: ("libs/partners/google-vertexai" "libs/partners/google-genai" "libs/partners/aws")
jobs:
# Generate dynamic test matrix based on input parameters or defaults
# Only runs on the main repo (for scheduled runs) or when manually triggered
compute-matrix:
if: github.repository_owner == 'langchain-ai' || github.event_name != 'schedule'
runs-on: ubuntu-latest
name: Compute matrix
name: '📋 Compute Test Matrix'
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Set matrix
- name: '🔢 Generate Python & Library Matrix'
id: set-matrix
env:
DEFAULT_LIBS: ${{ env.DEFAULT_LIBS }}
@@ -50,9 +52,11 @@ jobs:
matrix="{\"python-version\": $python_version, \"working-directory\": $working_directory}"
echo $matrix
echo "matrix=$matrix" >> $GITHUB_OUTPUT
# Run integration tests against partner libraries with live API credentials
# Tests are run with both Poetry and UV depending on the library's setup
build:
if: github.repository_owner == 'langchain-ai' || github.event_name != 'schedule'
name: Python ${{ matrix.python-version }} - ${{ matrix.working-directory }}
name: '🐍 Python ${{ matrix.python-version }}: ${{ matrix.working-directory }}'
runs-on: ubuntu-latest
needs: [compute-matrix]
timeout-minutes: 20
@@ -75,7 +79,7 @@ jobs:
repository: langchain-ai/langchain-aws
path: langchain-aws
- name: Move libs
- name: '📦 Organize External Libraries'
run: |
rm -rf \
langchain/libs/partners/google-genai \
@@ -84,7 +88,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
- name: '🐍 Set up Python ${{ matrix.python-version }} + Poetry'
if: contains(env.POETRY_LIBS, matrix.working-directory)
uses: "./langchain/.github/actions/poetry_setup"
with:
@@ -93,40 +97,40 @@ jobs:
working-directory: langchain/${{ matrix.working-directory }}
cache-key: scheduled
- name: Set up Python ${{ matrix.python-version }} + uv
- 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'
- name: '🔐 Authenticate to Google Cloud'
id: 'auth'
uses: google-github-actions/auth@v2
with:
credentials_json: '${{ secrets.GOOGLE_CREDENTIALS }}'
- name: Configure AWS 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 (poetry)
- name: '📦 Install Dependencies (Poetry)'
if: contains(env.POETRY_LIBS, matrix.working-directory)
run: |
echo "Running scheduled tests, installing dependencies with poetry..."
cd langchain/${{ matrix.working-directory }}
poetry install --with=test_integration,test
- name: Install dependencies (uv)
- 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
- name: '🚀 Run Integration Tests'
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
@@ -155,14 +159,15 @@ jobs:
cd langchain/${{ matrix.working-directory }}
make integration_tests
- name: Remove external libraries
- name: '🧹 Clean up External Libraries'
# Clean up external libraries to avoid affecting git status check
run: |
rm -rf \
langchain/libs/partners/google-genai \
langchain/libs/partners/google-vertexai \
langchain/libs/partners/aws
- name: Ensure tests did not create additional files
- name: '🧹 Verify Clean Working Directory'
working-directory: langchain
run: |
set -eu