Authensor provides official adapters for LangChain, OpenAI Agents SDK, and CrewAI. If you use a different framework, you can build your own adapter. This guide explains the adapter architecture and walks through building one.
An adapter has one job: intercept tool calls in a specific framework and route them through Authensor's guard function before execution. The adapter translates between the framework's tool interface and Authensor's evaluation API.
Framework Tool Call → Adapter → guard(toolName, args) → Framework Tool Execution
Every adapter implements the same pattern:
guard(toolName, args)Here is how to build an adapter for a hypothetical framework called "AgentKit":
Find where AgentKit executes tool calls:
// AgentKit's tool execution
class AgentKitRunner {
async executeTool(tool: Tool, args: unknown): Promise<unknown> {
return await tool.execute(args);
}
}
import { createGuard, type Guard } from '@authensor/sdk';
export function withAuthensor(
runner: AgentKitRunner,
options: AuthensorOptions
): AgentKitRunner {
const guard = createGuard(options);
const originalExecute = runner.executeTool.bind(runner);
runner.executeTool = async (tool: Tool, args: unknown) => {
// Step 3: Evaluate
const decision = guard(tool.name, args);
// Step 4: Handle
if (decision.action === 'block') {
return { error: `Blocked: ${decision.reason}` };
}
if (decision.action === 'escalate') {
if (options.onEscalate) {
const approved = await options.onEscalate(decision);
if (!approved) {
return { error: `Denied: ${decision.reason}` };
}
} else {
return { error: `Escalated: ${decision.reason}` };
}
}
// Allowed: execute the tool
return await originalExecute(tool, args);
};
return runner;
}
Pass framework-specific metadata to the guard for richer receipts:
runner.executeTool = async (tool: Tool, args: unknown) => {
const decision = guard(tool.name, args, {
framework: 'agentkit',
toolDescription: tool.description,
runId: runner.currentRunId,
});
// ...
};
Test that the adapter correctly intercepts, evaluates, and handles each decision type:
test('blocks unauthorized tool calls', async () => {
const runner = withAuthensor(new AgentKitRunner(), {
policy: { rules: [{ tool: '*', action: 'block' }] },
});
const result = await runner.executeTool(searchTool, { query: 'test' });
expect(result.error).toContain('Blocked');
});
test('allows authorized tool calls', async () => {
const runner = withAuthensor(new AgentKitRunner(), {
policy: { rules: [{ tool: 'search', action: 'allow' }] },
});
const result = await runner.executeTool(searchTool, { query: 'test' });
expect(result.error).toBeUndefined();
});
If you build an adapter for a framework that does not have one, consider contributing it to the Authensor repository or publishing it as a community package. Adapters are small (typically under 200 lines) and benefit the entire community.
Explore more guides on AI agent safety, prompt injection, and building secure systems.
View All Guides