LangChain
Add governance to LangChain.js tools with a single function call. Every tool invocation is evaluated against your policies before execution.
LangChain Integration
The SidClaw SDK provides governTool and governTools wrappers for LangChain.js. These wrap the invoke method of any LangChain-compatible tool with governance checks -- policy evaluation before execution, outcome recording after.
Installation
npm install @sidclaw/sdk @langchain/coreQuick start
import { AgentIdentityClient } from '@sidclaw/sdk';
import { governTools } from '@sidclaw/sdk/langchain';
import { TavilySearchResults } from '@langchain/community/tools/tavily_search';
import { Calculator } from '@langchain/community/tools/calculator';
const client = new AgentIdentityClient({
apiKey: process.env.SIDCLAW_API_KEY!,
apiUrl: 'https://api.sidclaw.com',
agentId: 'your-agent-id',
});
const tools = [
new TavilySearchResults(),
new Calculator(),
];
// Wrap all tools with governance in one call
const governedTools = governTools(tools, { client });API reference
governTool(tool, config)
Wraps a single LangChain tool with governance. Returns a new tool with the same name, description, and schema -- only the invoke method is wrapped.
import { governTool } from '@sidclaw/sdk/langchain';
const governedSearch = governTool(searchTool, {
client,
target_integration: 'tavily',
resource_scope: 'web_search',
data_classification: 'public',
});Parameters:
| Parameter | Type | Description |
|---|---|---|
tool | LangChainToolLike | Any object with name, description, and invoke method. |
config | GovernedToolConfig | Governance configuration (see below). |
Returns: A new tool of the same type, with invoke wrapped.
governTools(tools, config)
Wraps all tools in an array with governance. Each tool's name is automatically used as the target_integration.
import { governTools } from '@sidclaw/sdk/langchain';
const governedTools = governTools(myTools, {
client,
data_classification: 'internal',
});Parameters:
| Parameter | Type | Description |
|---|---|---|
tools | LangChainToolLike[] | Array of LangChain-compatible tools. |
config | GovernedToolConfig (without target_integration) | Shared governance configuration. |
Returns: A new array of governed tools.
GovernedToolConfig
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
client | AgentIdentityClient | Yes | -- | Configured SDK client instance. |
target_integration | string | No | Tool's name | Integration identifier for policy matching. |
resource_scope | string | No | '*' | Resource scope for policy matching. |
data_classification | DataClassification | No | 'internal' | Data sensitivity level: public, internal, confidential, restricted. |
Example: LangChain agent with governed tools
import { AgentIdentityClient } from '@sidclaw/sdk';
import { governTools } from '@sidclaw/sdk/langchain';
import { ChatOpenAI } from '@langchain/openai';
import { AgentExecutor, createOpenAIFunctionsAgent } from 'langchain/agents';
import { pull } from 'langchain/hub';
const client = new AgentIdentityClient({
apiKey: process.env.SIDCLAW_API_KEY!,
apiUrl: 'https://api.sidclaw.com',
agentId: 'customer-support-agent',
});
// Your tools
const tools = [searchTool, emailTool, databaseTool];
// Govern all tools
const governedTools = governTools(tools, {
client,
data_classification: 'confidential',
});
// Use governed tools in your agent
const model = new ChatOpenAI({ modelName: 'gpt-4' });
const prompt = await pull('hwchase17/openai-functions-agent');
const agent = await createOpenAIFunctionsAgent({ llm: model, tools: governedTools, prompt });
const executor = new AgentExecutor({ agent, tools: governedTools });
const result = await executor.invoke({
input: 'Look up the customer record for [email protected]',
});Error handling
When a policy denies a tool call or requires approval, governTool throws an ActionDeniedError. You can catch this and handle it in your agent logic.
import { ActionDeniedError } from '@sidclaw/sdk';
try {
const result = await governedTool.invoke(input);
} catch (error) {
if (error instanceof ActionDeniedError) {
console.log('Policy denied this action:', error.reason);
console.log('Trace ID:', error.traceId);
// The agent can try a different approach
}
throw error;
}How it works
When invoke is called on a governed tool:
- The SDK calls
POST /api/v1/evaluatewith the tool's name as the operation, the configuredtarget_integration,resource_scope, anddata_classification, plus the tool input as context. - If the policy engine returns
allow, the originalinvokeis called. After execution, the outcome (success or error) is recorded to the trace. - If the policy engine returns
denyorapproval_required, anActionDeniedErroris thrown before the tool executes.
Python
Installation
pip install sidclaw[langchain]Quick start
from sidclaw import SidClaw
from sidclaw.middleware.langchain import govern_tools
client = SidClaw(api_key="ai_...", agent_id="your-agent-id")
# Wrap all your LangChain tools with governance
governed = govern_tools(my_tools, client=client, data_classification="confidential")
# Use governed tools in your agent
agent = create_tool_calling_agent(llm=llm, tools=governed, prompt=prompt)Single tool
from sidclaw.middleware.langchain import govern_tool
governed_search = govern_tool(
search_tool,
client=client,
target_integration="search_service",
data_classification="internal",
)Example: LangChain agent with governed tools
from sidclaw import SidClaw
from sidclaw.middleware.langchain import govern_tools
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate
client = SidClaw(api_key="ai_...", agent_id="customer-support-agent")
# Govern all tools
governed_tools = govern_tools(
[search_tool, email_tool, database_tool],
client=client,
data_classification="confidential",
)
# Use governed tools in your agent
llm = ChatOpenAI(model="gpt-4")
prompt = ChatPromptTemplate.from_messages([...])
agent = create_tool_calling_agent(llm=llm, tools=governed_tools, prompt=prompt)
executor = AgentExecutor(agent=agent, tools=governed_tools)
result = executor.invoke({"input": "Look up the customer record for [email protected]"})Error handling
from sidclaw import ActionDeniedError
try:
result = governed_tool.invoke(input)
except ActionDeniedError as e:
print(f"Policy denied this action: {e.reason}")
print(f"Trace ID: {e.trace_id}")