@governmyai/sdk-langchain
v0.1.1
Published
GovernMy.ai LangChain integration — callback handler that checks regulatory obligations during agent tool calls and chain invocations
Maintainers
Readme
@governmyai/sdk-langchain
GovernMy.ai LangChain integration. Provides a callback handler and a tool wrapper that check regulatory obligations during agent tool calls and chain invocations.
Companion package to @governmyai/sdk.
Install
npm install @langchain/core @governmyai/sdk @governmyai/sdk-langchainOption 1 — Callback handler (recommended)
Drop into any chain/agent/LLM callbacks array. Gates tool calls by name.
const { GovernMy } = require('@governmyai/sdk');
const { buildCallbackHandler } = require('@governmyai/sdk-langchain');
const governmy = new GovernMy({ apiKey: process.env.GOVERNMY_API_KEY });
const governMyHandler = buildCallbackHandler({
governmy,
context: {
riskTier: 'high',
role: 'provider',
annexIiiCategory: ['employment'],
lifecyclePhase: 'deployment',
systemId: 'hiring-agent-v1',
},
mode: 'warn',
gatedToolNames: ['submit_decision', 'send_offer', 'reject_candidate'],
onObligations: async ({ toolName, obligations, blocked }) => {
console.log(`[governmy] ${toolName}: ${obligations.length} obligations${blocked ? ' (blocked)' : ''}`);
},
});
// Use with any LangChain runnable
const result = await chain.invoke(input, { callbacks: [governMyHandler] });
// Or with an agent executor
const result = await agentExecutor.invoke({ input }, { callbacks: [governMyHandler] });Option 2 — Direct tool wrapping
If you can't modify the callback chain, wrap individual tools:
const { wrapTool } = require('@governmyai/sdk-langchain');
const gatedTool = wrapTool(submitDecisionTool, {
governmy,
context: { riskTier: 'high', role: 'provider', ... },
mode: 'block',
});
// Use gatedTool in place of submitDecisionTool — .call() / .invoke() will
// run the regulatory check first and throw HumanReviewRequired on failure.
const result = await gatedTool.invoke({ candidateId: '123' });Mode behavior
| Mode | cannotBeAutoSatisfied match | Any humanReview.required match | Other matches |
|---|---|---|---|
| warn (default) | throws HumanReviewRequired | proceeds; obligations surfaced via onObligations | proceeds |
| block | throws HumanReviewRequired | throws HumanReviewRequired | proceeds |
| log-only | throws HumanReviewRequired | proceeds; obligations surfaced via onObligations | proceeds |
cannotBeAutoSatisfied obligations (EU AI Act Art. 14 et al.) always throw — structural, not configurable.
Catching HumanReviewRequired
When the handler throws, LangChain's agent executor surfaces the error naturally. Wrap the outer invocation:
const { HumanReviewRequired } = require('@governmyai/sdk');
try {
await agentExecutor.invoke({ input }, { callbacks: [governMyHandler] });
} catch (err) {
if (err instanceof HumanReviewRequired) {
enqueueForReview({
obligations: err.obligations,
unoverridable: err.unoverridable,
context: err.context,
});
return;
}
throw err;
}Notes
- The handler is duck-typed to LangChain's
BaseCallbackHandlerinterface. Works without importing@langchain/core, though you'll need it for the rest of your LangChain setup. handleToolStartandhandleAgentActionare both implemented — the handler works with both standalone chains and agent executors.- Per-tool context layering: the handler appends the tool name to
context.useCasesfor each gated call, so rules matching can be tool-specific.
License
MIT
