Skip to content

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.

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.

Terminal window
hexaeight-activate enable langgraph # from your agent's folder
hexaeight-activate enable langgraph --venv ~/my-env # or use an environment you already have

Then 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 commandpython3 runner.py --question-file question.txt — pinned to runner.py’s sha256
the LangGraph halfa prebuilt ReAct graph (create_react_agent) over the tools, with the conversation so far passed as messages
modelChatAnthropic on the turn’s route, with the turn’s token as a bearer header — no provider key in the file
pinnedlanggraph==1.2.12, langchain-anthropic==1.7.4, anthropic==1.8.0
its own outputto 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.


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 langgraph library 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.


import sys, os
sys.path.insert(0, os.path.expanduser("~/agenttests"))
import azcfg, hetool
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
from 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)
@tool
def get_working_folder() -> str:
"""Return the agent's current working folder (absolute path). Takes no arguments."""
return hetool.get_working_folder()
@tool
def 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()

{
"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>" }
}

  1. Keep your graph as it is — any compiled graph works, create_react_agent is just the short example.
  2. Pass HBIA’s sid as the thread_id in configurable.
  3. Attach a SqliteSaver (or any checkpointer) so state survives between processes.
  4. Build ChatOpenAI from azcfg.load().
  5. Seal the engine, point external.engine at it, restart.

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.