Files
langchain/libs/langchain_v1/pyproject.toml
Sydney Runkle dde2012b83 feat: threading context through create_agent flows + middleware (#34978)
Closes https://github.com/langchain-ai/langchain/issues/33956

* Making `ModelRequest` generic on `ContextT` and `ResponseT` so that we
can thread type information through to `wrap_model_call`
* Making builtin middlewares generic on `ContextT` and `ResponseT` so
their context and response types can be inferred from the `create_agent`
signature

See new tests that verify backwards compatibility (for cases where folks
use custom middleware that wasn't parametrized).

This fixes:
1. Lack of access to context and response types in `wrap_model_call`
2. Lack of cohesion between middleware context + response types with
those specified in `create_agent`

See examples below:

### Type-safe context and response access

```python
class MyMiddleware(AgentMiddleware[AgentState[AnalysisResult], UserContext, AnalysisResult]):
    def wrap_model_call(
        self,
        request: ModelRequest[UserContext],
        handler: Callable[[ModelRequest[UserContext]], ModelResponse[AnalysisResult]],
    ) -> ModelResponse[AnalysisResult]:
        #  Now type-safe: IDE knows user_id exists and is str
        user_id: str = request.runtime.context["user_id"]

        #  mypy error: "session_id" doesn't exist on UserContext
        request.runtime.context["session_id"]

        response = handler(request)

        if response.structured_response is not None:
            #  Now type-safe: IDE knows sentiment exists and is str
            sentiment: str = response.structured_response.sentiment

            #  mypy error: "summary" doesn't exist on AnalysisResult
            response.structured_response.summary

        return response
```

### Mismatched middleware/schema caught at `create_agent`

```python
class SessionMiddleware(AgentMiddleware[AgentState[Any], SessionContext, Any]):
    ...

#  mypy error: SessionMiddleware expects SessionContext, not UserContext
create_agent(
    model=model,
    middleware=[SessionMiddleware()],
    context_schema=UserContext,  # mismatch!
)

class AnalysisMiddleware(AgentMiddleware[AgentState[AnalysisResult], ContextT, AnalysisResult]):
    ...

#  mypy error: AnalysisMiddleware expects AnalysisResult, not SummaryResult
create_agent(
    model=model,
    middleware=[AnalysisMiddleware()],
    response_format=SummaryResult,  # mismatch!
)
```
2026-02-05 07:41:27 -05:00

196 lines
5.7 KiB
TOML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "langchain"
description = "Building applications with LLMs through composability"
license = { text = "MIT" }
readme = "README.md"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Topic :: Software Development :: Libraries :: Python Modules",
]
version = "1.2.8"
requires-python = ">=3.10.0,<4.0.0"
dependencies = [
"langchain-core>=1.2.8,<2.0.0",
"langgraph>=1.0.7,<1.1.0",
"pydantic>=2.7.4,<3.0.0",
]
[project.optional-dependencies]
community = ["langchain-community"]
anthropic = ["langchain-anthropic"]
openai = ["langchain-openai"]
azure-ai = ["langchain-azure-ai"]
#cohere = ["langchain-cohere"]
google-vertexai = ["langchain-google-vertexai"]
google-genai = ["langchain-google-genai"]
fireworks = ["langchain-fireworks"]
ollama = ["langchain-ollama"]
together = ["langchain-together"]
mistralai = ["langchain-mistralai"]
huggingface = ["langchain-huggingface"]
groq = ["langchain-groq"]
aws = ["langchain-aws"]
deepseek = ["langchain-deepseek"]
xai = ["langchain-xai"]
perplexity = ["langchain-perplexity"]
[project.urls]
Homepage = "https://docs.langchain.com/"
Documentation = "https://reference.langchain.com/python/langchain/langchain/"
Repository = "https://github.com/langchain-ai/langchain"
Issues = "https://github.com/langchain-ai/langchain/issues"
Changelog = "https://github.com/langchain-ai/langchain/releases?q=tag%3A%22langchain%3D%3D1%22"
Twitter = "https://x.com/LangChain"
Slack = "https://www.langchain.com/join-community"
Reddit = "https://www.reddit.com/r/LangChain/"
[dependency-groups]
test = [
"pytest>=8.0.0,<9.0.0",
"pytest-cov>=4.0.0,<8.0.0",
"pytest-watcher>=0.2.6,<1.0.0",
"pytest-asyncio>=0.23.2,<2.0.0",
"pytest-socket>=0.6.0,<1.0.0",
"pytest-xdist<4.0.0,>=3.6.1",
"pytest-mock",
"syrupy>=4.0.2,<5.0.0",
"toml>=0.10.2,<1.0.0",
"blockbuster>=1.5.26,<1.6.0",
"langchain-tests",
"langchain-openai",
]
lint = [
"ruff>=0.14.11,<0.15.0",
]
typing = [
"mypy>=1.19.1,<1.20.0",
"types-toml>=0.10.8.20240310,<1.0.0.0",
]
test_integration = [
"vcrpy>=8.0.0,<9.0.0",
"wrapt>=1.15.0,<2.0.0",
"python-dotenv>=1.0.0,<2.0.0",
"langchainhub>=0.1.16,<1.0.0",
"langchain-core",
"langchain-text-splitters",
]
[tool.uv]
prerelease = "allow"
constraint-dependencies = ["urllib3>=2.6.3"]
[tool.uv.sources]
langchain-core = { path = "../core", editable = true }
langchain-tests = { path = "../standard-tests", editable = true }
langchain-text-splitters = { path = "../text-splitters", editable = true }
langchain-openai = { path = "../partners/openai", editable = true }
[tool.ruff]
line-length = 100
[tool.mypy]
strict = true
enable_error_code = "deprecated"
warn_unreachable = true
exclude = [
# Exclude agents tests except middleware_typing/ which has type-checked tests
"tests/unit_tests/agents/middleware/",
"tests/unit_tests/agents/specifications/",
"tests/unit_tests/agents/test_.*\\.py",
]
# TODO: activate for 'strict' checking
warn_return_any = false
[[tool.mypy.overrides]]
module = ["pytest_socket.*", "vcr.*"]
ignore_missing_imports = true
[tool.ruff.format]
docstring-code-format = true
[tool.ruff.lint]
select = [
"ALL"
]
ignore = [
"C90", # McCabe complexity
"COM812", # Messes with the formatter
"CPY", # No copyright
"FIX002", # Line contains TODO
"PERF203", # Rarely useful
"PLR09", # Too many something (arg, statements, etc)
"TD002", # Missing author in TODO
"TD003", # Missing issue link in TODO
# TODO rules
"ANN401", # Any in type annotations
"BLE", # Blind exceptions
]
unfixable = [
"B028", # People should intentionally tune the stacklevel
]
flake8-annotations.allow-star-arg-any = true
allowed-confusables = [""]
[tool.ruff.lint.flake8-tidy-imports]
ban-relative-imports = "all"
[tool.ruff.lint.pydocstyle]
convention = "google"
ignore-var-parameters = true # ignore missing documentation for *args and **kwargs parameters
[tool.ruff.lint.extend-per-file-ignores]
"tests/unit_tests/agents/*" = [
"ANN", # Annotations, needs to fix
"ARG", # Arguments, needs to fix
]
"tests/unit_tests/agents/test_responses_spec.py" = ["F821"]
"tests/unit_tests/agents/test_return_direct_spec.py" = ["F821"]
"tests/unit_tests/agents/test_react_agent.py" = ["ALL"]
"tests/*" = [
"D1", # Documentation rules
"S101", # Tests need assertions
"S311", # Standard pseudo-random generators are not suitable for cryptographic purposes
"SLF001", # Private member access in tests
"PLR2004", # Magic values are perfectly fine in unit tests (e.g. 0, 1, 2, etc.)
]
"scripts/*" = [
"INP", # Scripts are not in a package
]
[tool.coverage.run]
omit = ["tests/*"]
[tool.pytest.ini_options]
addopts = "--strict-markers --strict-config --durations=5 --snapshot-warn-unused -vv"
markers = [
"requires: mark tests as requiring a specific library",
"scheduled: mark tests to run in scheduled testing",
"compile: mark placeholder test used to compile integration tests without running them",
]
asyncio_mode = "auto"
filterwarnings = [
"ignore::langchain_core._api.beta_decorator.LangChainBetaWarning",
"ignore::langchain_core._api.deprecation.LangChainDeprecationWarning:tests",
"ignore::langchain_core._api.deprecation.LangChainPendingDeprecationWarning:tests",
]