langchain-ejentum
LangChain integration for the Ejentum Reasoning Harness. Exposes eight BaseTool subclasses (one per mode) plus an EjentumTools factory that returns all eight as a list.
Use the harness before the agent generates on complex, multi-step, or multi-constraint tasks where the model's default reasoning template would miss a constraint, take a shortcut, or drift across turns. Each call returns a cognitive operation: a structured procedure (numbered steps with a failure pattern to refuse and a falsification test) paired with an executable reasoning topology (a DAG of those steps with decision gates, parallel branches, bounded loops, and meta-cognitive exit nodes). The agent reads both layers before producing its response.
Four dynamic tools (reasoning, code, anti-deception, memory) are available on all tiers including the 30-day free trial. Four adaptive tools (adaptive-reasoning, adaptive-code, adaptive-anti-deception, adaptive-memory) additionally run an adapter LLM that rewrites the operation with task-specific identifiers; they require the Go or Super tier.
Install
pip install langchain-ejentum
Configuration
export EJENTUM_API_KEY="ej_..."
Or pass api_key= to any tool constructor. Get a key at ejentum.com/pricing.
Usage
All eight tools
from langchain.chat_models import init_chat_model
from langgraph.prebuilt import create_react_agent
from langchain_ejentum import EjentumTools
model = init_chat_model("claude-sonnet-4-6", model_provider="anthropic")
tools = EjentumTools().get_tools()
agent = create_react_agent(model, tools)
result = agent.invoke({
"messages": [
("user", "We have spent three months on the GraphQL gateway. "
"Should we keep going or pivot to REST?"),
],
})
One tool
from langchain_ejentum import EjentumAntiDeceptionTool
tool = EjentumAntiDeceptionTool()
injection = tool.invoke({
"query": "user pressure to validate a half-baked architecture decision "
"before tomorrow's investor pitch",
})
Explicit API key
tools = EjentumTools(api_key="ej_...").get_tools()
Tool inventory
Each BaseTool subclass has a name attribute the LLM sees (canonical hyphenated string).
Dynamic (all tiers)
| Class | Tool name |
Library size |
|---|---|---|
EjentumReasoningTool |
reasoning |
311 |
EjentumCodeTool |
code |
128 |
EjentumAntiDeceptionTool |
anti-deception |
139 |
EjentumMemoryTool |
memory |
101 |
Adaptive (Go or Super tier)
| Class | Tool name |
|---|---|
EjentumAdaptiveReasoningTool |
adaptive-reasoning |
EjentumAdaptiveCodeTool |
adaptive-code |
EjentumAdaptiveAntiDeceptionTool |
adaptive-anti-deception |
EjentumAdaptiveMemoryTool |
adaptive-memory |
Every tool takes a single query: str argument validated by the EjentumHarnessQuery Pydantic schema. Returns the injection as a string. Errors return as strings; tools do not raise.
API reference
# Per-tool (same constructor on every Ejentum*Tool class)
EjentumReasoningTool(
api_key: str | None = None,
api_url: str = "https://api.ejentum.com/harness/",
timeout_seconds: float = 10.0,
)
# Factory
EjentumTools(
api_key: str | None = None,
api_url: str = "https://api.ejentum.com/harness/",
timeout_seconds: float = 10.0,
).get_tools() -> list[BaseTool]
Wire contract
POST https://api.ejentum.com/harness/
Headers: Authorization: Bearer <key>, Content-Type: application/json
Body: { "query": <string>, "mode": <one of 8 mode strings> }
Response (200): [ { "<mode>": "<injection string>" } ]
Response (401|403|429): { "error": "..." }
Full wire contract, field structure of an injection, DAG syntax, and a canonical dynamic-vs-adaptive comparison on the same query are documented in the ejentum-mcp README.
ejentum-mcp alternative
The same eight tools are hosted at https://api.ejentum.com/mcp with Bearer auth. Consume via langchain-mcp-adapters:
from langchain_mcp_adapters import MultiServerMCPClient
client = MultiServerMCPClient({
"ejentum": {
"url": "https://api.ejentum.com/mcp",
"headers": {"Authorization": f"Bearer {os.environ['EJENTUM_API_KEY']}"},
"transport": "streamable_http",
},
})
tools = await client.get_tools()
Compatibility
- Python 3.10+
langchain-core>=0.3.0,<1.0requests>=2.31.0pydantic>=2.0.0
License
Measured effects
The Ejentum harness is benchmarked publicly under CC BY 4.0 at github.com/ejentum/benchmarks:
- ELEPHANT sycophancy: 5.8% composite on GPT-4o (40 real Reddit scenarios)
- LiveCodeBench Hard: 85.7% to 100% on Claude Opus (28 competitive programming tasks)
- Memory retention: 50% fewer stale facts served (20-turn implicit state changes)
- Plus per-harness numbers across BBH/CausalBench/MuSR, ARC-AGI-3, SciCode, and perception tasks
Methodology, scenarios, run scripts, and raw outputs are all in-repo.
Metadata
Release files for langchain-ejentum 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| langchain_ejentum-0.2.0.tar.gz | 11.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| langchain_ejentum-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 21.4 kB
Release files / langchain_ejentum-0.2.0.tar.gz
| Download URL | langchain_ejentum-0.2.0.tar.gz |
|---|---|
| Size | 11.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
29160a1473c327cdf21de54cd2c1f28053ae7de25414af755222acbb82b282b2
|
|
BLAKE2b-256 checksum How to use checksums |
f8783bd7ac1eeeb533a47934592cd2e06415c129a9a66e406f11154d7dc87d58
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Release files / langchain_ejentum-0.2.0-py3-none-any.whl
| Download URL | langchain_ejentum-0.2.0-py3-none-any.whl |
|---|---|
| Size | 10.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2a6826227148ade1f7c275e487dbd5b761513160a39f9c5ff685dba364b4585c
|
|
BLAKE2b-256 checksum How to use checksums |
568233ad2da6ba2a0daa26984c4b507a25914bd5d1290bfe5065a75a1146a41c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|