TypeScript SDK
The official TypeScript SDK for the InPolicy governance API. Adds type safety, automatic retries on 5xx/network errors, and a clean ergonomic surface.
Install
Section titled “Install”npm install @inpolicy/sdkCreate a client
Section titled “Create a client”import { InPolicyClient } from '@inpolicy/sdk';
const ip = new InPolicyClient({ apiKey: process.env.INPOLICY_API_KEY!, // all optional: baseUrl: 'https://api.inpolicy.ai', timeoutMs: 30_000, maxRetries: 2, userAgent: 'my-support-agent/1.4.0',});One client per API key; safe to reuse across requests.
Record a turn
Section titled “Record a turn”const result = await ip.recordTurn({ sessionId: 'sess_abc', turn: { role: 'user', content: "I'm 16 — can I buy this?" },});
console.log(result.activePolicies); // what's active nowconsole.log(result.injectionBlock); // paste into your system promptconsole.log(result.diff.newlyApplicable); // what just became activeThe full RecordTurnInput shape:
{ sessionId: string; turn: { role: 'user' | 'assistant' | 'tool'; content: string }; recentContext?: string[]; // last 2-3 prior turns, for disambiguation priorHistory?: string[]; // bootstrap on first call only endUserContext?: { ephemeralId?: string; attributes?: Record<string, unknown>; // { role: 'support_agent', region: 'EU' } }; policyAreaIds?: string[]; // scope to specific areas tokenBudget?: number; // injection_block size, default 600 idempotencyKey?: string; // retries within 5 min return cached checkOutput?: boolean; // only when role='assistant' ttlSeconds?: number; // override 4h default}Check an output
Section titled “Check an output”// Requires post_inference_checking: 'allowed' on the API keyconst check = await ip.postInference({ output: draft, sessionId: 'sess_abc',});
if (!check.safe) { if (check.suggestedRedaction) { return check.suggestedRedaction; // use the remediated text } // Otherwise regenerate with stronger prompting}Gate a tool call
Section titled “Gate a tool call”// Requires tool_call_governance: 'allowed' on the API keyconst ok = await ip.checkToolCall({ sessionId: 'sess_abc', toolName: 'send_email', arguments: { to: 'customer@...', subject: '...', body: '...' },});
if (!ok.allow) { return `I can't send that email — ${ok.violations[0].explanation}`;}await actuallySendEmail();Read / end conversation
Section titled “Read / end conversation”const snapshot = await ip.getConversationState('sess_abc');// { turnCount, activePolicies, injectionBlock, bindingLog, updatedAt }
await ip.endConversation('sess_abc'); // purge Redis state, idempotentError handling
Section titled “Error handling”import { InPolicyApiError } from '@inpolicy/sdk';
try { await ip.recordTurn({ ... });} catch (err) { if (err instanceof InPolicyApiError) { if (err.status === 403) { // Feature gate disabled on the API key (e.g. tried checkOutput without the setting) } else if (err.status === 429) { // Rate limited. The SDK retries 5xx automatically but not 429. } else if (err.status >= 500) { // SDK already retried `maxRetries` times (default 2) } } // network / timeout errors also reach here, not wrapped in InPolicyApiError}Retry behavior
Section titled “Retry behavior”The SDK retries:
- ✅ 5xx responses
- ✅ Network errors (DNS, connection refused, TCP reset)
- ✅ Timeouts
- ❌ 4xx responses (your code is wrong, retrying won’t help)
- ❌ 429 (backing off is your responsibility; we don’t want to make the rate-limit situation worse)
Exponential backoff with jitter: 100ms, 200ms, 400ms, … capped at 2000ms. Tune with maxRetries (default 2, giving 3 total attempts).
Pattern — minimal chat loop
Section titled “Pattern — minimal chat loop”import { InPolicyClient } from '@inpolicy/sdk';import OpenAI from 'openai';
const ip = new InPolicyClient({ apiKey: process.env.INPOLICY_API_KEY! });const openai = new OpenAI();
class Conversation { constructor(public sessionId = crypto.randomUUID()) {}
async say(userMessage: string): Promise<string> { const pre = await ip.recordTurn({ sessionId: this.sessionId, turn: { role: 'user', content: userMessage }, });
const res = await openai.chat.completions.create({ model: 'gpt-4o', messages: [ { role: 'system', content: `You are a support agent.\n\n${pre.injectionBlock}` }, { role: 'user', content: userMessage }, ], }); const output = res.choices[0].message.content ?? '';
await ip.recordTurn({ sessionId: this.sessionId, turn: { role: 'assistant', content: output }, }); return output; }
async end() { await ip.endConversation(this.sessionId); }}
const chat = new Conversation();console.log(await chat.say("I'm 16 — can I buy this?"));console.log(await chat.say("Okay, can I at least see the product page?"));await chat.end();Python SDK
Section titled “Python SDK”Python support is on the roadmap. In the meantime, call the REST API directly. The shape is the same as documented in the API reference, and Python requests/httpx work fine.