/v1/evaluate, its Permit is verified, and only then does the original function run. The wrappers have no dependency on LlamaIndex itself, so they work with any LlamaIndex version.
Install
Python
with_llamaindex_guard wraps a callable before you hand it to FunctionTool.from_defaults, QueryEngineTool, or any other LlamaIndex tool factory. The wrapped function keeps the original name, docstring, and signature.
AtlaSentDeniedError is raised before search() runs. For async tools, use async_with_llamaindex_guard with an AsyncAtlaSentClient.
TypeScript
withLlamaIndexGuard takes an array of tool definitions (LlamaIndex-style metadata plus an execute callback) and returns the same tools with execute replaced by an authorize-first version: evaluate, then verify the Permit, then execute.
agent, action, extraContext, and stateSnapshot also accept a resolver function (toolName, input) => value, so you can set them per call.
Denials
By default a denial throws (AtlaSentDeniedError). Set on_deny="tool-result" in Python, or onDeny: "tool-result" in TypeScript, to return a structured denial instead, so the LLM sees the reason and can adjust. In Python that’s a DenialResult object; in TypeScript it looks like:
_atlasent_permit_id and _atlasent_audit_hash; other results pass through unchanged.
Action class mapping
When you don’t pass an action, the wrappers evaluate the canonicalagent.tool.invoke action and always send the tool’s own name as context.tool, so policy can tell tools apart. That action class requires environment in context; the wrapper never invents one, so supply it through extra_context / extraContext. If you map tools to your own action classes instead, key them on stable action types rather than Python or TypeScript function names.
Related
- LangChain integration
- MCP server for host-side gating