LangGraph
Verified as a sealed mission 2026-09-27 — general questions, live weather and BBC News through HexaEight-verified services, search of this machine’s documents, “who am I”, and conversation memory across turns.
As a sealed mission
Section titled “As a sealed mission”HexaEight decides who may ask and which command may run; LangGraph does the work. It is a
direct mission — the same one-card mission every framework
uses — and the answer is LangGraph’s, headed Answered by LangGraph.
hexaeight-activate enable langgraph # from your agent's folderhexaeight-activate enable langgraph --venv ~/my-env # or use an environment you already haveThen choose runmission → LangGraph_v1_Runner in the workspace. Requires agent r30, harness engine r41 and
Activate 1.0.68 or later, and Python 3.10–3.13 (or uv). The mission
bundle is the integration-langgraph-v1 release; the runner, pinned requirements and install-by-hand steps are in
integration_examples/langgraph.
| the one command | python3 runner.py --question-file question.txt — pinned to runner.py’s sha256 |
| the LangGraph half | a prebuilt ReAct graph (create_react_agent) over the tools, with the conversation so far passed as messages |
| model | ChatAnthropic on the turn’s route, with the turn’s token as a bearer header — no provider key in the file |
| pinned | langgraph==1.2.12, langchain-anthropic==1.7.4, anthropic==1.8.0 |
| its own output | to langgraph-run.log in the turn’s folder, with one [tool] line per tool call |
Live weather and news are asked for fresh on every turn. Measured: in a long session LangGraph’s model repeated headlines from earlier in the conversation instead of calling the tool; the runner’s instructions now forbid that, and its log shows one [tool] line per real call.
To serve it to other people’s software, run the same enable inside a runner’s folder — see
Serving it to other people and systems.
As a process engine
Section titled “As a process engine”Verified 2026-08-19 — PASS, 6s. Session persistence: native SqliteSaver checkpointer.
LangGraph’s checkpointer rehydrates graph state from disk, so there is no transcript to manage. The
session id is the thread_id.
Licence: use the
langgraphlibrary only.langgraph-api/ LangGraph Platform is Elastic Licence 2.0, which prohibits offering it as a hosted service — do not pull it into a product you deploy for others. The library itself is MIT.
The runner
Section titled “The runner”import sys, ossys.path.insert(0, os.path.expanduser("~/agenttests"))import azcfg, hetool
from langchain_openai import ChatOpenAIfrom langchain_core.tools import toolfrom langgraph.prebuilt import create_react_agentfrom langgraph.checkpoint.sqlite import SqliteSaver
DB = os.path.expanduser("~/agenttests/langgraph/checkpoints.sqlite")
c = azcfg.load()llm = ChatOpenAI(model=c["model"], base_url=c["base_url"], api_key=c["api_key"], temperature=0)
@tooldef get_working_folder() -> str: """Return the agent's current working folder (absolute path). Takes no arguments.""" return hetool.get_working_folder()
@tooldef run_shell(command: str) -> str: """Run a shell command in the working folder and return its output.""" return hetool.run_shell(command)
TOOLS = [get_working_folder, run_shell]
def invoke(thread_id, message): """No local transcript — LangGraph rehydrates state from the checkpoint.""" with SqliteSaver.from_conn_string(DB) as saver: agent = create_react_agent(llm, TOOLS, checkpointer=saver) cfg = {"configurable": {"thread_id": thread_id}} result = agent.invoke({"messages": [{"role": "user", "content": message}]}, cfg) return result["messages"][-1].content.strip()Engine definition
Section titled “Engine definition”{ "type": "process", "file": "/home/you/langgraph/.venv/bin/python3", "nativeSession": true, "argsNew": ["/home/you/he_adapter.py", "/home/you/langgraph_session.py", "", "{message}"], "argsResume": ["/home/you/he_adapter.py", "/home/you/langgraph_session.py", "{sessionId}", "{message}"], "replyField": "result", "sessionIdField": "session_id", "approve": false, "workdir": "/home/you/work", "proxy": { "shape": "openai", "baseUrlEnv": "OPENAI_BASE_URL", "keyEnv": "OPENAI_API_KEY", "modelEnv": "OPENAI_MODEL", "model": "<route>|<provider model>" }}Adoption
Section titled “Adoption”- Keep your graph as it is — any compiled graph works,
create_react_agentis just the short example. - Pass HBIA’s
sidas thethread_idinconfigurable. - Attach a
SqliteSaver(or any checkpointer) so state survives between processes. - Build
ChatOpenAIfromazcfg.load(). - Seal the engine, point
external.engineat it, restart.
Gotchas
Section titled “Gotchas”SqliteSaver.from_conn_string is a context manager. Use with; the connection must be open for
the whole invoke, and closing it early gives an agent that silently forgets.
Every hop routes through the proxy. A reason → tool → answer loop makes multiple LLM calls, all routed. Good for gating, and worth knowing when reading metering: one turn is not one call.
A tool with no arguments needs saying so. "Takes no arguments." in the docstring stops models
inventing a parameter and failing the call.
temperature=0 for deterministic testing; drop it in production if you want variety.
Build the LLM at module scope only if the route is stable. In this runner azcfg.load() runs at
import, which is fine because the env is injected per spawn. If you ever reuse the process across
turns, move it inside invoke.