Configure LangGraph¶
powercontext-langgraph connects a LangGraph graph to a running
PowerContext Server through the public Python Client. It integrates at the node and tool level, using LangGraph
primitives that are stable public API. It never starts or embeds the Server.
Install¶
The package is not yet published to PyPI, so install it from source alongside a running Server:
uv pip install "powercontext-langgraph @ git+https://github.com/oceanbase/powercontext.git@master#subdirectory=integrations/langgraph"
powercontext server run
From a checkout you can install the local path instead: uv pip install ./integrations/langgraph. The adapter is not
currently published on PyPI, so use one of these source installations.
The package depends on powercontext[client], langgraph, langchain-core, and pydantic-settings. It does not
pull in the Server; point it at a Server you run separately.
Three components¶
powercontext_tools()returnslangchain_core.tools.BaseToolinstances —powercontext_search,powercontext_remember, andpowercontext_context— for model-initiated Memory read and write. Add them to aToolNodeor any tool list.PowerContextRecallis apre_model_hook. It reads the latest human message, requests one boundedPreparedContext, and supplies a complete, ordered model input on thellm_input_messageschannel — the prepared content as a single leading system message, followed by the run's messages. That context reaches the model but never enters the persistedmessageshistory, so it cannot accumulate across turns under a checkpointer.PowerContextScopeis a dataclass intended for the graphcontext_schema. It carries the durable scope, and optional per-run connection overrides, for one run.
Use it as the pre_model_hook of create_react_agent, which wires the llm_input_messages channel for you:
from langgraph.prebuilt import create_react_agent
from powercontext_langgraph import PowerContextRecall, PowerContextScope, powercontext_tools
agent = create_react_agent(
model,
tools=powercontext_tools(),
pre_model_hook=PowerContextRecall(),
context_schema=PowerContextScope,
checkpointer=my_checkpointer,
)
await agent.ainvoke(state, context=PowerContextScope(scope_id="git:github.com/acme/api"))
The recall hook and the Memory tools are async, so drive the graph with ainvoke/astream; a synchronous
invoke/stream cannot run them.
In a custom graph, add an llm_input_messages channel to the state and have the model step read it:
from typing import Annotated
from typing_extensions import TypedDict
from langchain_core.messages import BaseMessage
from langgraph.graph import StateGraph, START
from langgraph.graph.message import add_messages
from powercontext_langgraph import PowerContextRecall, PowerContextScope
class AgentState(TypedDict):
messages: Annotated[list[BaseMessage], add_messages]
llm_input_messages: list[BaseMessage]
def call_model(state: AgentState):
model_input = state.get("llm_input_messages") or state["messages"]
...
builder = StateGraph(AgentState, context_schema=PowerContextScope)
builder.add_node("recall", PowerContextRecall())
builder.add_node("model", call_model)
builder.add_edge(START, "recall")
builder.add_edge("recall", "model")
graph = builder.compile(checkpointer=my_checkpointer)
await graph.ainvoke(state, context=PowerContextScope(scope_id="git:github.com/acme/api"))
The recall hook and the tools read the active PowerContextScope from the LangGraph runtime, so a single value on
context configures the whole run. Outside a run — for example when a tool is exercised directly — they fall back to
the environment settings below.
Configure the connection¶
Configuration is read through pydantic-settings with the prefix POWERCONTEXT_LANGGRAPH_.
| Variable | Default | Purpose |
|---|---|---|
POWERCONTEXT_LANGGRAPH_BASE_URL |
http://127.0.0.1:8000 |
PowerContext Server URL |
POWERCONTEXT_LANGGRAPH_TOKEN |
unset | Bare token forwarded to PowerContextClient |
POWERCONTEXT_LANGGRAPH_SCOPE_ID |
derived | Durable scope shared across runs |
POWERCONTEXT_LANGGRAPH_TIMEOUT |
10 |
Client timeout in seconds |
POWERCONTEXT_LANGGRAPH_MAX_BYTES |
8000 |
Prepared-context size limit |
PowerContextScope(base_url=..., token=..., timeout=...) overrides these per run. A field left as None on the
scope falls back to the environment value.
POWERCONTEXT_LANGGRAPH_TOKEN carries a bare token, not a complete Authorization header value. This differs from the
POWERCONTEXT_*_AUTHORIZATION convention used by the Codex, Claude Code, and DeepSeek Harness plugins.
PowerContextClient accepts the bare token and composes Authorization: Bearer <token> internally. The token is
used only to authenticate the Client; it never appears in graph state or agent-visible message content.
Resolve the scope¶
The scope for a run is resolved in this order:
- an explicit
scope_idonPowerContextScope, orPOWERCONTEXT_LANGGRAPH_SCOPE_ID; - a scope derived from the current Git remote;
- otherwise the adapter raises
MissingScopeError.
This priority is inverted relative to the Codex plugin, which prefers the Git- or path-derived local scope. A LangGraph deployment is typically a long-running service whose working directory has no relationship to the project, so explicit configuration is the primary path and Git derivation is the fallback. When neither is available the adapter raises rather than defaulting to a shared local scope, which would place unrelated tenants together.
Treat recalled context as untrusted history¶
PowerContextRecall injects the prepared content as a system message labelled as untrusted historical evidence.
Memory content originates from prior model output and user input; presenting it as authoritative system instruction
would extend the prompt-injection surface to historical data. The model must still check current code, the current
user request, and system instructions before acting on recalled content.
When the Server returns an empty result the node adds nothing and returns the state unchanged.
Fail open when the Server is unavailable¶
Server unavailability must not interrupt graph execution. PowerContextRecall handles Client errors internally and
returns the state unmodified, so the graph still reaches its end. A configuration fault — HTTP 401 or 403, usually a
missing or wrong POWERCONTEXT_LANGGRAPH_TOKEN — is logged once at error level; other transient faults are logged at
debug level. The Memory tools return a short (PowerContext unavailable: ...) string rather than raising, so a model
that called a tool can retry or choose another strategy instead of concluding that no memory exists.
Why this package does not implement BaseStore¶
BaseStore is LangGraph's cross-thread long-term memory interface and appears to be the intended seam for an
integration of this kind. It is not usable as one. BaseStore.batch must service GetOp, PutOp (upsert and
delete), and SearchOp. Only SearchOp maps onto the PowerContext Memory model; the others require get, upsert, and
delete by a caller-assigned key, which Memory does not provide — entry identity and versioning are assigned by the
Server. Implementing only search and raising for the rest produces an object that passes assembly-time validation but
fails at runtime inside unrelated nodes or tools, which is worse than providing no store. The adapter therefore
integrates at the node and tool level and does not occupy the store parameter of compile().
Current scope¶
Included: Memory read and write, and bounded context preparation.
Not included: automatic trajectory capture, checkpointing, Handoff, Artifact Candidate review, and Experience or
Skill generation. Use powercontext_remember for explicit writes; automatic capture of a run as Source evidence is
not part of this adapter.