CodeVetter · Repo Unpack · Extension points
langchain-ai/langchain
The framework is built around extension. Agents are extended via AgentMiddleware subclasses (six hook points + state_schema + transformers), custom tools (BaseTool/@tool/dict provider tools), custom state/context schemas, structured-output strategies, checkpointers/stores/caches from LangGraph, and stream transformers. Models and embeddings plug in through partner packages implementing core abstractions plus registry entries in _BUILTIN_PROVIDERS, validated by the langchain-tests conformance suite. Shell execution is extensible via BaseExecutionPolicy.
- AgentMiddleware is the primary extension point: subclasses override any of before_agent/before_model/after_model/after_agent/wrap_model_call/wrap_tool_call (sync and/or async variants); decorators @before_agent/@before_model/@after_agent/@after_model/@dynamic_prompt/@wrap_model_call/@wrap_tool_call offer a functional alternative.
- Middleware can declare `state_schema` (merged into agent state), `tools` (registered on the agent), `transformers` (stream post-processors), `trace_policy`, and `can_jump_to` per hook — factory.py inspects which hooks are overridden to decide which graph nodes to add.
- New chat-model providers are added by implementing BaseChatModel in a partner package and adding a (module_path, class_name, creator_func) entry to `_BUILTIN_PROVIDERS`; custom creator lambdas handle non-standard constructors (e.g. huggingface's from_model_id, ibm's model_id kwarg).
- New embeddings providers follow the identical registry pattern in embeddings/base.py `_BUILTIN_PROVIDERS`.
- Partner packages prove conformance by subclassing langchain-tests suites (unit_tests/chat_models.py, integration_tests/vectorstores.py, etc.) rather than writing their own contract tests.
- Tools plug in as BaseTool subclasses, @tool-decorated callables, or raw dicts (provider built-in tools); tools can inject runtime/state/store via ToolRuntime/InjectedState/InjectedStore annotations.
- Agent state is extensible two ways: a custom `state_schema` TypedDict passed to create_agent (wins field conflicts over middleware schemas since it's merged last), or middleware-declared state_schema attributes.
- Structured output strategies are pluggable ResponseFormat implementations (ToolStrategy, ProviderStrategy, AutoStrategy); callers can also pass raw Pydantic/dataclass/TypedDict/JSON-schema which get wrapped in AutoStrategy.
- Persistence/streaming extension points come straight from LangGraph: create_agent accepts checkpointer (Checkpointer), store (BaseStore), cache (BaseCache), interrupt_before/after node names, and user `transformers` factories appended to the default pipeline.
- Shell execution policy is pluggable via BaseExecutionPolicy subclasses — built-ins are HostExecutionPolicy, DockerExecutionPolicy, CodexSandboxExecutionPolicy, each implementing process launch and post-spawn limits.
- Multi-agent composition is supported by naming an agent (`name=` becomes a subgraph node name) and by SubagentTransformer, which is always registered on the compiled graph to reshape nested-agent stream events.
- Observability is extensible per-middleware via TracePolicy and process-wide via configure_trace_policy; all wrap_* hooks are traced through LangSmith `traceable` with scrubbed inputs.