LangChain.js integration
The @inpolicy/langchain package integrates InPolicy into any LangChain.js chain or agent. Two flavors:
withInPolicy: wrap an LLM call with a single function. Simplest.InPolicyCallbackHandler: a callback handler you attach to an existing chain.
Install
Section titled “Install”npm install @inpolicy/langchain @inpolicy/sdk @langchain/corewithInPolicy: wrap a single LLM call
Section titled “withInPolicy: wrap a single LLM call”import { ChatOpenAI } from '@langchain/openai';import { InPolicyClient } from '@inpolicy/sdk';import { withInPolicy } from '@inpolicy/langchain';
const ip = new InPolicyClient({ apiKey: process.env.INPOLICY_API_KEY! });const llm = new ChatOpenAI({ modelName: 'gpt-4o' });
const guarded = withInPolicy( async ({ system, user }) => { const res = await llm.invoke([ { role: 'system', content: system }, { role: 'user', content: user }, ]); return typeof res.content === 'string' ? res.content : JSON.stringify(res.content); }, { client: ip, sessionId: 'sess_abc', systemPrompt: 'You are a helpful customer support agent.', checkOutput: true, // optional; requires post_inference_checking on the key },);
const result = await guarded.invoke({ input: "I'm 16 — can I buy this?" });
console.log(result.output); // the LLM's responseconsole.log(result.preInferencePolicies); // e.g. ['Policy 4.2', 'Policy 7.1']console.log(result.postInferenceViolations); // non-empty only when checkOutput=true and unsafeWhat it does on every invocation:
record_turn({ role: 'user', content: input })→ get active policies.- Build
system = systemPrompt + '\n\n' + injectionBlock. - Call the wrapped LLM function with
{ system, user }. record_turn({ role: 'assistant', content: output, checkOutput }).- Return output + policy metadata.
Failures in InPolicy calls are non-blocking. They log and pass through. This keeps governance from breaking your chain if InPolicy is briefly unreachable.
InPolicyCallbackHandler: drop into an existing chain
Section titled “InPolicyCallbackHandler: drop into an existing chain”If you have a complex chain or agent already wired up, use the callback handler instead:
import { ChatOpenAI } from '@langchain/openai';import { InPolicyClient } from '@inpolicy/sdk';import { InPolicyCallbackHandler } from '@inpolicy/langchain';
const ip = new InPolicyClient({ apiKey: process.env.INPOLICY_API_KEY! });
const inpolicyHandler = new InPolicyCallbackHandler({ client: ip, sessionId: 'sess_abc', recentContextWindow: 3, checkOutput: true, onViolations: (violations) => { console.warn('[InPolicy]', violations.length, 'violations in assistant output'); },});
const llm = new ChatOpenAI({ modelName: 'gpt-4o', callbacks: [inpolicyHandler],});
// Use `llm` anywhere; the handler fires on every LLM call in the chain.const result = await llm.invoke('Draft a reply to the Acme account exec.');
// After invocation, read the latest stateconst latest = inpolicyHandler.getLatest();console.log(latest?.activePolicies);The handler hooks handleChatModelStart and handleLLMEnd to record turns around every LLM invocation. Attach to any Runnable, chain, or agent; it travels through.
Caveat: the callback handler can call record_turn but it can’t modify the system prompt that’s being sent to the LLM. If you want the injection block to actually reach the model, either use withInPolicy (recommended) or have your chain’s prompt template read the injection block from inpolicyHandler.getInjectionBlock() (called after a warm-up turn).
With an agent + tools
Section titled “With an agent + tools”For an agent that calls tools, combine the callback handler with explicit checkToolCall calls in your tool definitions:
import { DynamicStructuredTool } from '@langchain/core/tools';import { z } from 'zod';
const sendEmailTool = new DynamicStructuredTool({ name: 'send_email', description: 'Send an email to a recipient', schema: z.object({ to: z.string(), subject: z.string(), body: z.string(), }), func: async (args) => { // Gate the action const check = await ip.checkToolCall({ sessionId: 'sess_abc', // same session the handler uses toolName: 'send_email', arguments: args, }); if (!check.allow) { return `Blocked by policy: ${check.violations[0].explanation}`; } // Execute return await actuallySendEmail(args); },});Python LangChain
Section titled “Python LangChain”Not yet available. Use the REST API directly via requests or httpx; shape is documented in the API reference.