> ## Documentation Index
> Fetch the complete documentation index at: https://powercontext.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# LangChain

> Recall before each model request and optionally capture one successful completed turn without changing agent state.

> [!WARNING]
>
> Source install only: `powercontext-langchain==0.0.1` is not published to PyPI. The documented Git URL follows mutable `master`, and the focused package test does not exercise that VCS installation path. Reproducibility is **Not validated**; pin a reviewed commit and its dependencies.

`PowerContextMiddleware` integrates with LangChain `create_agent`. It supports sync and async execution, changes only the current model request, and optionally captures a completed turn as Source evidence. It has no adapter-owned PowerContext tools.

## Maturity and installation

| Item | Status |
| - | - |
| Package | Source install only; not PyPI |
| Version | `0.0.1` |
| Runtime | Python `>=3.11,<4.0`; LangChain `>=1.3,<2` |
| Invocation | Sync and async |
| Mutable-branch reproducibility | **Not validated** |
| Real model-provider round trip in the documented evidence | **Not validated** |

Install the Server and middleware from the reviewed source commit:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
uv tool install --force "powercontext[cli,server] @ git+https://github.com/oceanbase/powercontext.git@3e629eb163ba0ddf2935ce3b3fbaced0f9371977"
uv pip install "powercontext-langchain @ git+https://github.com/oceanbase/powercontext.git@3e629eb163ba0ddf2935ce3b3fbaced0f9371977#subdirectory=integrations/langchain"
powercontext server run
```

For a local checkout at the same commit:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
git -C /path/to/powercontext checkout 3e629eb163ba0ddf2935ce3b3fbaced0f9371977
uv pip install /path/to/powercontext/integrations/langchain
```

> [!NOTE]
>
> The middleware is independent of `powercontext-langgraph`. LangChain may install LangGraph internally, but the two PowerContext adapters have separate settings, Scope types, and lifecycle behavior.

## Minimum use

The example assumes your application already owns an initialized chat model and its normal agent or model-call loop. PowerContext supplies middleware; it does not choose or create that model. Verify Scope and recall first with the focused middleware tests or a model-free fake, then place the middleware around the real call.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from langchain.agents import create_agent
from powercontext_langchain import PowerContextMiddleware, PowerContextScope

agent = create_agent(
    model,
    tools=application_tools,
    middleware=[PowerContextMiddleware()],
    context_schema=PowerContextScope,
)

result = await agent.ainvoke(
    {
        "messages": [
            {
                "role": "user",
                "content": "What should happen after changing the OpenAPI contract?",
            }
        ]
    },
    context=PowerContextScope(scope_id="project:powercontext-101"),
)
```

The same middleware supports `invoke` and `stream` in a synchronous application, and `ainvoke` and `astream` in an async application.

> [!WARNING]
>
> Do not call a synchronous agent method from an already running event loop. The host still runs, but PowerContext recall and capture are skipped and the middleware logs one warning. Use the async agent API there.

## Execution flow

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
before every model request
→ read latest human message
→ resolve per-invocation Scope and connection settings
→ prepare_context(query <= 8192 chars, max_bytes)
→ append an untrusted block to this ModelRequest.system_message
→ call model without changing agent state
→ after successful agent completion, optionally capture latest user + final response
```

Recall runs before every model request. It is not once per run like the Pydantic AI Capability, and it is not once per human turn with a cross-step cache like LangGraph. A later model step can therefore see Memory written earlier in the same run by an application-owned tool.

The middleware overrides only the current `ModelRequest.system_message`. It never writes the recalled block to framework state or a checkpointer. The existing system message remains first; the untrusted context block is appended for that one request.

## Capture is opt-in

Enable capture only after deciding that user and final model content may be stored durably:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
middleware = PowerContextMiddleware(auto_capture=True)
```

`auto_capture` defaults to `False`. `after_agent` or `aafter_agent` captures only after successful completion, using the latest non-empty user message plus either a serializable `structured_response` or the final non-empty assistant response.

| Included | Excluded |
| - | - |
| Latest user text | Tool output |
| Final assistant text | Intermediate tool-calling messages |
| Serializable `structured_response` | Recalled PowerContext block |
| Truncation metadata | Aborted run or run without a final response |

The combined Source payload has a separate 200,000 Python-character ceiling. The adapter divides the available budget between user and assistant text and records truncation flags.

> [!NOTE]
>
> Capture creates a Source. It does not create or approve Memory, and the middleware does not flush. Server extraction may run later through the scheduler or an explicit Client operation, and may produce a no-op.

## Scope and configuration

Pass `PowerContextScope` on each invocation when one agent serves more than one tenant. Per-invocation values for Scope, base URL, token, and timeout override environment values.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
scope = PowerContextScope(
    scope_id="tenant:acme:project:api",
    base_url="https://context.example.com",
    token="opaque-server-token",
    timeout=8.0,
)

result = await agent.ainvoke(state, context=scope)
```

| Setting | Default |
| - | -: |
| `POWERCONTEXT_LANGCHAIN_BASE_URL` | `http://127.0.0.1:8000` |
| `POWERCONTEXT_LANGCHAIN_TOKEN` | unset |
| `POWERCONTEXT_LANGCHAIN_SCOPE_ID` | derived or error |
| `POWERCONTEXT_LANGCHAIN_TIMEOUT` | `10` seconds |
| `POWERCONTEXT_LANGCHAIN_MAX_BYTES` | `8000`; accepted range `512`–`32768` bytes |

Scope precedence is:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
PowerContextScope(scope_id=...)
→ POWERCONTEXT_LANGCHAIN_SCOPE_ID
→ normalized network Git origin
→ MissingScopeError
```

There is no local-path fallback. HTTP(S), SSH, Git, and SCP-like network remotes are normalized without credentials. An overlong explicit Scope is replaced by a bounded SHA-256 identifier.

The token convention is a bare token without `Bearer `. The adapter does not strictly validate that syntax. The shared `PowerContextClient` rejects plaintext HTTP to non-loopback hosts unless the caller supplies an explicitly trusted transport.

## Failure, privacy, and Scope boundary

Automatic recall and capture are independent fail-open paths. Missing Scope, malformed configuration, request validation, authentication failures, timeouts, Server failures, or an unserializable structured response do not replace the model result or abort the host run. HTTP 401/403 is logged as configuration trouble, not treated as empty Memory.

The middleware does not add explicit PowerContext tools. If the application wraps Python Client mutations as its own tools, their failure contract and permissions belong to the application; automatic fail-open behavior does not make those mutations successful.

> [!WARNING]
>
> Recall can contain old user or model text. Treat it as untrusted evidence, not an instruction, identity proof, or permission grant. Scope chooses a data partition; derive it from an authenticated tenant/project mapping when isolation matters.

Capture can store ordinary prompts, code, business data, and final model output. This adapter does not promise complete secret redaction. Keep `auto_capture=False` until the application has content filtering, consent, retention, and deletion rules. Tool output is excluded, but that alone is not a privacy policy.

## Compare with LangGraph

The difference is where recall lives. Pick the lifecycle already owned by your application rather than wrapping one framework to imitate the other.

| Capability | LangChain | LangGraph |
| - | - | - |
| Recall frequency | Every model request | Once per human turn, cached across model steps |
| Adapter-owned tools | None | Three Memory tools |
| Automatic capture | Optional completed-turn Source; default off | None |
| Invocation | Sync and async | Async only |
| Injection channel | Current `ModelRequest.system_message` | Ephemeral `llm_input_messages` |
| Framework state mutation | None | Recall does not mutate persisted `messages` |
| Flush | None | None |

## Currently unsupported or not validated

| Item | Status |
| - | - |
| Adapter-owned PowerContext tools | **Unsupported** |
| Automatic or final flush | **Unsupported** |
| Handoff and Candidate Review | **Unsupported** |
| Experience and Skill operations | **Unsupported** |
| Failed or aborted-run capture | **Unsupported** |
| Complete secret redaction | **Unsupported** |
| Reproducible install from mutable `master` | **Not validated** |
| Real external-provider round trip in the documented evidence | **Not validated** |

## Completion checklist

* The Server runs separately, and the source-installed middleware is pinned to a reviewed commit.
* Sync code runs outside an event loop; async code uses `ainvoke` or `astream`.
* A captured model request contains the untrusted recall block, while returned and checkpointed state does not.
* Tests expect recall before every model request, not once per run or once per turn.
* Every invocation receives the intended Scope; a cross-Scope negative test proves tenant isolation.
* `MAX_BYTES` is between 512 and 32,768, queries over 8,192 characters are expected to be clamped, and remote transport uses HTTPS.
* With the Server unavailable, the model flow continues and 401/403 remains distinguishable from empty Memory.
* `auto_capture` remains off unless completed-turn storage has an explicit privacy and retention policy.
* When capture is enabled, checks inspect Source rather than assuming Memory or flush.
* Unsupported and Not validated items remain distinct in deployment notes.

> [!TIP]
>
> Seed one explicit Memory, inspect a model request, and inspect framework state. Enable capture only in a separate run, then verify the Source journal and the absence of an automatic flush.

Continue with [Framework tricks](https://powercontext.mintlify.site/en/frameworks/tricks.md) for cross-framework Scope, transport, budget, and failure checks.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.