Available in AOS Core 0.2.0-rc14 with the optional langgraph dependencies.
LangGraph runs the workflow; AOS authenticates and governs the external action.
Only public LangGraph documentation and existing AOS contracts are used.
Run the local checks
Download and verify the wheel using Getting started. From the directory containing that wheel, with Python 3.11–3.14:
python3 -m venv .aos-framework
.aos-framework/bin/python -m pip install --upgrade pip
.aos-framework/bin/python -m pip install './aos_core-0.2.0rc14-py3-none-any.whl[langgraph]'
.aos-framework/bin/aos-evaluate --cli --langgraph --output ./framework-run --port 0 --serve
Use a new output directory on each run. The command starts an isolated control plane, runtime worker and harmless HTTP service. It creates real LangGraph checkpoints, closes and reopens the SQLite checkpointer, and resumes the action. No cloud resources, model API or payment account is used. Local validation disables inherited LangSmith/LangChain tracing and restores the environment afterward. Normal application tracing remains the operator’s responsibility.
Expected results:
| Check | Expected behavior |
|---|---|
| Review pause | No external action until the workflow is resumed |
| Resume after reopening checkpoints | One successful action, with AOS receipt and runtime evidence |
| Replay with the same thread and identity | Original receipt; no second external effect |
| Policy changed during review | Denied before provider execution |
| Budget exhausted during review | Rejected before provider execution |
| Provider response lost | Unknown outcome; no blind retry |
| Capability revoked during review | Rejected before provider execution |
framework.json contains the framework checks and receipt references. evaluation.json also
includes the ordinary CLI allowed/denied/unknown checks. There are four total reference effects:
two in the ordinary checks and two in the framework checks. A reference effect only advances an
in-memory counter. HTTP-request latency is measured; tokens and cost are null because this test
does not measure model usage. These are local functional results, not production benchmarks.
Inspect through the console and CLI
- Open the console URL printed by the command. Choose Session, enter
free-evaluation, and selectframework-run/console-token.txt. The token stays in your local environment. - Open Capabilities to inspect the contract. The reference capability is revoked at the end of validation. Connect and approve a separate staging capability to perform new actions.
- Open Audit to review decisions. Under Platform > Runtime & Fleets, inspect unknown workloads and use Reconcile evidence. Reconciliation does not repeat the action.
- In another terminal, use the
AOS_URL,AOS_TENANT_IDandAOS_TOKEN_FILEvalues printed inWALKTHROUGH.txt, then run:
.aos-framework/bin/aos product capability list
.aos-framework/bin/aos product runtime workloads --status unknown
.aos-framework/bin/aos product execution pending
.aos-framework/bin/aos product audit
Both interfaces inspect the same records. LangGraph drives the workflow pause; Action Reviews
records the separate AOS approval. The evaluator uses a distinct reviewer identity. Its private
reviewer-token.txt is only for this isolated local validation. Stop the evaluator with Ctrl-C. Keep tokens, checkpoint
files and evidence private; remove the output directory when no longer needed.
Add to your application
After registering and approving a capability, use a service identity limited to the required tenant and operations. Configure this existing token through a private file, not graph state.
import os
from pathlib import Path
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.types import Command
from aos.integrations.langgraph import build_action_graph
from aos.product_client import ProductClient
client = ProductClient(os.environ['AOS_URL'], os.environ['AOS_TENANT_ID'],
Path(os.environ['AOS_TOKEN_FILE']).read_text().strip())
# Checkpoints contain action inputs. Use private local storage.
Path('./private-state').mkdir(mode=0o700, exist_ok=True)
Path('./private-state').chmod(0o700)
with SqliteSaver.from_conn_string('./private-state/workflow.sqlite') as saver:
graph = build_action_graph(client, checkpointer=saver)
config = {'configurable': {'thread_id': 'maintenance-request-001'}}
paused = graph.invoke({'action': {
'capability_id': os.environ['AOS_CAPABILITY_ID'],
'operation': 'restart', 'input': {'service': 'staging-service'},
}}, config)
# AOS creates a pending exact-request review before the graph pauses.
print('A different reviewer must approve:', paused['approval_id'])
input('After that reviewer approves through AOS, press Enter to resume: ')
# Application consent alone does not grant authority.
result = graph.invoke(Command(resume={
'approved': True,
'action_digest': paused['binding']['action_digest'],
}), config)
print(result['result'])
Persist the logical thread ID before starting. On a process restart, reopen the same checkpoint
database and use graph.get_state(config) to inspect pending state before sending Command.
Use a separate node ID for each distinct action boundary in a larger application. Do not rotate
the thread ID, node ID, AOS identity or idempotency key to retry an uncertain action. Scope and
protect checkpoint access per tenant and user; the checkpointer is trusted application state.
If the workflow is resumed before the AOS reviewer decides, it raises before sending an invocation.
After approval, reopen the same checkpoint and call graph.invoke(None, config) to continue that
pending node. Never replace an unknown action with a fresh thread just to retry it.
The review reply is consent, not an AOS authority token. AOS capability approvals, current policy, roles and usage budgets still apply. An AOS escalation remains blocked until resolved through AOS’s existing approval process. The adapter does not auto-resolve it or mint delegated authority. The evaluator validates separate requester and reviewer identities; cross-agent delegation remains a separate qualification step. See action approval for UI and CLI steps.
Only action.input, explicit action.context and action.constraints are forwarded. Other graph
state, model transcripts, credentials and private context are not automatically forwarded. Explicit
inputs are stored in the AOS review and checkpoints: callers must minimize them and control retention. Provider
output is not copied to graph results; the result contains status and evidence references.
Recovery and retention
The gateway retains the response for 24 hours, then removes its body and retains a payload-free
admission tombstone. A delayed replay gets IDEMPOTENCY_OUTCOME_REQUIRES_REVIEW (CLI exit 4).
Server errors and interrupted processing also retain the guard. These cases require inspection
of audit, runtime and provider records. The guard prevents re-admission with the same identity and
key; it does not establish exactly-once execution in arbitrary external systems.
Back up the idempotency table with the control-plane database. Do not prune its effect tombstones while workflows can still resume. Restoring an older database, changing identity or deliberately choosing a new key can remove duplicate protection. Guarded states require this server version; rollback must retain them and disable new writes until the compatible server is restored. Existing rc11 records are not retroactively protected once already expired or deleted.
Public references: LangGraph interrupts explain why pre-interrupt code can run again; persistence explains checkpointer durability. The implementation uses optional LangGraph 1.2.x and SQLite checkpointer 3.1.x dependencies. External model/IdP qualification, sustained operation and independent security review remain in the release gate.