lang_ai_agent
A LangGraph agent backend built around production patterns: a streaming HTTP API, durable state that survives restarts, a human-approval gate for side-effecting tools, deterministic tests that never call a real LLM, and built-in observability.
It ships as an Ops Copilot demo (multi-store retail: "what's about to stock out?" → "send the reorder email"), but the runtime is domain-agnostic — the tools are the only retail-specific part. Swap them (or plug in your own MCP servers) and keep everything else.
Status — v0.1.0 is released on PyPI and gated by
make check(ruff, pyright strict, pytest; 100% coverage on the graph core). Releases go through GitHub Actions Trusted Publishing with a maintainer approval step. Design docs live underdocs/.
How it works
The agent calls read-only tools freely. Any side-effecting tool stops the graph at a LangGraph interrupt() and waits for a human to approve or reject it over the API. The graph is checkpointed at that point, so the server can restart in between. A rejection with a comment goes back to the model, which revises its draft and asks again.
flowchart LR
C[Client / curl] -- "HTTP + SSE (Bearer)" --> A[FastAPI · api/app.py]
A --> agent
agent -- tool_calls --> route
route -- safe --> safe_tools --> agent
route -- effect --> approval
approval -. "interrupt() ⏸ human approves" .-> effect_tools --> agent
agent -- no tool_calls --> END
The only edge into effect_tools passes through approval. That is not a convention — a test walks the compiled graph and fails if any other path appears.
Install
Requires Python 3.12+.
pip install lang-ai-agent # or: uv add lang-ai-agent
uv tool install lang-ai-agent # or, as a standalone CLI on your PATH
To work from a checkout instead, install uv and run uv sync; every command below then takes a uv run prefix.
Quickstart
lang-ai-agent init # pick a provider, paste your API key → writes .env (mode 0600)
lang-ai-agent serve # http://127.0.0.1:8000 — fails fast if the key is missing
init supports Anthropic (default), OpenAI, xAI and Google; MODEL uses LangChain's provider:model form, so any other provider init_chat_model supports works as well. Your key is written only to the git-ignored .env.
Talk to it from another terminal (TOKEN is the APP_BEARER_TOKEN that init printed):
H=(-H "Authorization: Bearer $TOKEN" -H 'content-type: application/json')
TID=$(curl -s -X POST "${H[@]}" localhost:8000/threads | jq -r .thread_id)
curl -sN -X POST "${H[@]}" localhost:8000/threads/$TID/messages \
-d '{"content":"Which items at store main will stock out next week? Summarize as a table."}'
The response is a Server-Sent Events stream: tool_start/tool_end for check_stockout, token events carrying the table, then usage and done.
API
| Method · path | Body | What it does |
|---|---|---|
POST /threads |
— | Issue a thread_id |
POST /threads/{id}/messages |
{content} |
Run the graph; SSE stream |
GET /threads/{id}/state |
— | last_message, pending action, usage, awaiting_approval |
POST /threads/{id}/approve |
{approved, comment?} |
Resume from the interrupt; SSE stream |
DELETE /threads/{id} |
— | Delete the thread's history (every checkpoint) |
SSE events (Pydantic-typed, discriminated on type): token · tool_start · tool_end · interrupt (pending action + draft) · usage · done · error. A stream ends with either one interrupt or usage → done.
60-second demo
lang-ai-agent serve— one JSON log line, server up.- Ask what will stock out at store
main→ tool call, streamed table. - "Send the reorder email for the at-risk items" → suggestions are fetched, a draft is written, and the stream stops at
interruptshowing the recipient and draft. GET /state→awaiting_approval: true.POST /approve {"approved": true}→ the email tool runs (dry-run by default), the agent reports back,usage→done.
The full script with timings and a restart-resilience variant is in docs/DEMO.md.
Real-model smoke
lang-ai-agent init # once — your key goes to .env only
lang-ai-agent smoke # scenario 1 (query) + scenario 2 (draft → y/n approval in the console)
lang-ai-agent smoke --mcp # same, with the real MCP servers from mcp_servers.json
From a checkout, make smoke runs the same thing.
The smoke always runs dry-run, whatever .env says, and costs three to four model calls (cents on a Sonnet-class model). Everything else runs without a key: make check makes zero network calls.
Why it is built this way
- Approval as topology, not a flag. Side-effecting tools are reachable only through the
approvalnode, and a graph-structure test enforces it. Sending is double-gated: the interrupt andSEND_MODE=live. - One run per thread at a time.
/messages,/approveandDELETEon the same thread are serialized in-process, so a duplicated approval can never run the effect twice, and a message sent while the thread waits for approval gets a 409 instead of forking its history. - The model is a script in tests.
ScriptedChatModelreplays a fixed sequence ofAIMessages (tool calls included) and fails loudly if the script is exhausted or diverges. With the model scripted, the graph is a state machine and every path — approve, reject-and-revise, tool failure, restart mid-interrupt — is a deterministic test. Real models appear only in the smoke. - State stays small. State is serialized at every checkpoint, so it holds messages and minimal metadata; large tool results are summarized before they enter it.
- Static types as the cheapest feedback loop. pyright strict + Pydantic v2 at every boundary (requests, model output, MCP responses), no
Anyreturns, and every# type: ignorecarries a reason. - Fail at startup, not on the first request. A missing provider key or bearer token is a
ConfigErrorwith the fix in the message, raised before the server binds. - Provider-agnostic, MCP-native.
init_chat_modelfor the model;langchain-mcp-adaptersto mount MCP servers as tools, each mapped to safe/effect (unlisted tools default to effect).
Development
uv sync # dev dependencies included
make check # ruff check + pyright strict + pytest (core coverage gate ≥ 90%)
make dev # uvicorn with --reload
src/lang_ai_agent/
core/ state.py (AgentState, PendingAction, Usage) · graph.py (StateGraph) · tools_spec.py (safe/effect)
adapters/ llm.py (providers) · checkpoint.py (AsyncSqliteSaver) · mcp_loader.py · effects.py · observability.py
api/ app.py (FastAPI assembly) · sse.py (event schema + mapper) · auth.py
cli.py init · serve · smoke smoke.py real-model smoke logic
tests/ helpers (ScriptedChatModel, MockEffects, FixedClock) · unit · component · e2e (API-level scenarios)
CI runs make check on every push and pull request (.github/workflows/ci.yml). A v* tag runs publish.yml: build → TestPyPI → PyPI, the last step behind a required maintainer approval (docs/RELEASE.md). That approval is the maintainer's; installing and running the package never asks anyone for approval.
Docs
| Doc | Contents |
|---|---|
CLAUDE.md |
Agent steering: stack, commands, conventions, guardrails |
docs/SPEC.md |
Product spec: goals, non-goals, scenarios, roadmap |
docs/DESIGN.md |
Technical design: graph, state, API, tool classes, MCP, env, onboarding, packaging |
docs/TESTING.md |
Test strategy: scripted model, golden trajectories, edge-case checklist |
docs/TASKS.md |
Task backlog with machine-checkable completion criteria |
docs/WORKFLOW.md |
AI-native development rules for this repo |
docs/DEMO.md |
The 60-second demo script |
docs/RELEASE.md |
PyPI release runbook: Trusted Publishing setup, tag rules, procedure |
This repo is developed doc-first: spec and design are updated before code, implementation is done task-by-task by Claude Code, and make check is the shared gate.
Roadmap
- v0.1 — single-agent graph + approval gate + FastAPI SSE + deterministic tests + onboarding CLI + CI + PyPI release
- v0.2 — PostgresSaver, supervisor multi-agent, always-on MCP server connections
- v0.3 — evaluation harness (golden-trajectory regression + eval sets), cost reports, Docker template
License
MIT © 2026 Trapa-Eureka.
Metadata
Release files for lang-ai-agent 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| lang_ai_agent-0.1.1.tar.gz | 37.1 kB | With provenance | Details for lang_ai_agent-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| lang_ai_agent-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for lang_ai_agent-0.1.1-py3-none-any.whl |
Total release size: 84.5 kB
Release files / lang_ai_agent-0.1.1.tar.gz
| Download URL | lang_ai_agent-0.1.1.tar.gz |
|---|---|
| Size | 37.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9792a38f1a2af652126aba691cd5a890a7aeba2445652f3602775ab57dad8a93
|
|
BLAKE2b-256 checksum How to use checksums |
42665313d96657ffb8137591cf5905790af187150af628ba3b7676c0d9d1e1fc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.
Transparency logRelease files / lang_ai_agent-0.1.1-py3-none-any.whl
| Download URL | lang_ai_agent-0.1.1-py3-none-any.whl |
|---|---|
| Size | 47.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c832254b458364e0eefd1741623a98684a742c9fc1f4e310f14fede121de3a3f
|
|
BLAKE2b-256 checksum How to use checksums |
d2a4cb5694a92957b8aeef3ed47ad7282d35e1368a42846f1118aeadd0b5347b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.
Transparency logSecurity for lang-ai-agent 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for lang_ai_agent-0.1.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.