LangChain / LangGraph
Vectadyne is an MCP server, so LangChain reaches it either through an MCP tool adapter or through the Python SDK directly. Prefer the SDK for the governed path, and here is why that is not just taste.
Do not make the verdict a tool call
Section titled “Do not make the verdict a tool call”The tempting design is to expose preflight.action as a tool and let the model decide when to call
it. That fails in a specific way: the model can choose not to. A model under instruction pressure
— from a user, or from injected text in a document it is reading — will skip the safety check
precisely when the check mattered.
Put the verdict in the graph, as a node the model does not control:
Retrieval is fine as a tool — a model choosing to look something up is normal. The verdict is not.
The governed node
Section titled “The governed node”import osfrom vectadyne import Vectadyne, interpret_verdict
vd = Vectadyne( mcp_url=os.environ["VECTADYNE_MCP_URL"], token=os.environ["VECTADYNE_TOKEN"],)
def assemble_node(state): assembled = vd.assemble( action_type=state["action_type"], summary=state["summary"], changed_files=state.get("changed_files", []), scope_key=state["scope"], purpose=state.get("purpose", "feature"), ) d = interpret_verdict(assembled.verdict) return {**state, "assembled": assembled, "guidance": d}
def route(state): return "escalate" if not state["guidance"].proceed else "act"Note not ... .proceed. Python’s polarity is the inverse of Go’s and TypeScript’s — see
Interpret a verdict.
Put advisories in front of the model
Section titled “Put advisories in front of the model”A warn proceeds, and its advisories are the whole value:
def act_node(state): notes = "\n".join(f"- {w}" for w in state["guidance"].warnings) messages = state["messages"] if notes: messages = messages + [SystemMessage( content=f"Governed memory notes for this action:\n{notes}" )] return {**state, "messages": messages}Dropping them turns a warn into a silent allow and wastes the one thing the corpus knew that your
agent did not.
Close the loop
Section titled “Close the loop”def ingest_node(state): vd.client.call_tool("evidence.ingest", evidence_args( agent=state["agent"], items=[{ "source_type": "run", "summary": state["outcome"], "scope_key": state["scope"], }], )) return stateRecord failures too — a corpus of only successes cannot warn anyone about anything.
AsyncVectadyne mirrors the sync facade method for method, with the same parameter names and the
same typed returns:
from vectadyne.aio import AsyncVectadyne # NOT vectadyne.AsyncVectadyneNeither AsyncVectadyne nor Secret is re-exported at the top level, and the obvious guess fails.
Multi-agent graphs
Section titled “Multi-agent graphs”One credential per member, and identity must survive a handoff — LangGraph state carries the conversation, and the credential is easy to drop on the hop. See Multi-agent crews.