npm package: @glidepaths/sdk
Description: TypeScript / JavaScript SDK for the Glidepaths AI governance API — log decisions, enforce policy guardrails, and query compliance posture.
Latest version: 0.1.0

# @glidepaths/sdk

TypeScript / JavaScript SDK for the [Glidepaths](https://glidepaths.com) AI governance API.

Log agent decisions, enforce policy guardrails before actions, query compliance posture, and generate audit packages — from any Node.js or browser environment.

**Zero runtime dependencies.** Uses the native `fetch` API (Node 18+, all modern browsers). Works as ESM and CommonJS.

## Installation

```bash
npm install @glidepaths/sdk
# or
pnpm add @glidepaths/sdk
# or
yarn add @glidepaths/sdk
```

Get your API key from [Settings → API Keys](https://glidepaths.com/api-keys) in the Glidepaths dashboard.

---

## Quick start

```ts
import { GlidepathsClient } from "@glidepaths/sdk";

const client = new GlidepathsClient({
  apiKey: process.env.GLIDEPATHS_API_KEY!,
});

// 1. Pre-action governance check
const result = await client.evaluate({
  action_type: "approve_insurance_claim",
  action_payload: { claim_id: "CLM-9821", amount: 125_000 },
  context: { delegation_tier: 2 },
  agent_id: "claims-agent-v3",
});

if (result.canProceed) {
  await approveClaim();
} else if (result.requiresEscalation) {
  await notifyHumanReviewer(result.escalation_path, result.reason);
} else if (result.isBlocked) {
  throw new Error(`Blocked by governance policy: ${result.reason}`);
}

// 2. Post-action audit log
await client.log({
  agent_name: "claims-agent-v3",
  decision_type: "claim_approval",
  decision_summary: "Approved claim #CLM-9821. Risk score 0.34.",
  risk_level: "medium",
  compliance_tags: ["NAIC_AA", "EU_AI_ACT_ART_13"],
  metadata: { model: "claude-opus-4-6", confidence: 0.91 },
});
```

---

## API reference

### `new GlidepathsClient(options)`

```ts
const client = new GlidepathsClient({
  apiKey: "glide_xxx",          // Required. From Glidepaths Settings → API Keys.
  baseUrl: "https://glidepaths.com", // Optional. Override for staging / self-hosted.
  timeoutMs: 10_000,            // Optional. Request timeout. Default: 10 000 ms.
});
```

---

### `client.evaluate(payload)` → `Promise<EvaluateResponse>`

Pre-action governance check. Call **before** an agent acts.

```ts
const result = await client.evaluate({
  action_type: "send_payment",       // Required
  action_payload: { amount: 50_000, recipient: "vendor-123" },
  context: { delegation_tier: 2, jurisdiction: "US-CA" },
  agent_id: "payment-agent",
});
```

**`EvaluateResponse` fields:**

| Field | Type | Description |
|---|---|---|
| `decision` | `"proceed" \| "escalate" \| "block"` | The governance decision |
| `reason` | `string` | Human-readable explanation |
| `policy_id` | `string \| null` | Policy that triggered the decision |
| `latency_ms` | `number` | Server-side evaluation time |
| `escalation_path` | `string \| undefined` | Where to route escalations |
| `canProceed` | `boolean` | `decision === "proceed"` |
| `requiresEscalation` | `boolean` | `decision === "escalate"` |
| `isBlocked` | `boolean` | `decision === "block"` |

---

### `client.log(payload)` → `Promise<LogResponse>`

Write an immutable decision to the 14-field audit trail. Call **after** acting.

```ts
await client.log({
  agent_name: "underwriting-agent-v2",    // Required
  decision_type: "policy_approval",        // Required
  decision_summary: "Approved homeowners policy for applicant A-8821. Risk 34/100.", // Required
  risk_level: "medium",                    // "low" | "medium" | "high" | "critical"
  delegation_tier: 2,
  model_version: "claude-opus-4-6",
  compliance_tags: ["NAIC", "EU_AI_ACT_ART_9"],
  input_hash: "sha256:abc123...",          // Enables safe idempotent retries
  metadata: { applicant_state: "CO", coverage_amount: 450_000 },
});
```

**Idempotent retries:** pass `input_hash` to make `log()` safely retryable. Duplicate hashes return `duplicates: 1` without creating a new record.

```ts
import { createHash } from "node:crypto";

const hash = "sha256:" + createHash("sha256")
  .update(JSON.stringify({ claim_id: "CLM-9821", amount: 125_000 }))
  .digest("hex");

await client.log({ agent_name: "...", decision_type: "...", decision_summary: "...", input_hash: hash });
```

**Batch logging:**

```ts
await client.logBatch([
  { agent_name: "agent-a", decision_type: "lookup", decision_summary: "...", risk_level: "low" },
  { agent_name: "agent-b", decision_type: "approval", decision_summary: "...", risk_level: "high" },
]);
```

Up to 100 events per call.

---

### `client.getComplianceMatrix(framework)` → `Promise<MatrixResponse>`

Fetch the current compliance posture, control by control.

```ts
const matrix = await client.getComplianceMatrix("EU_AI_ACT");
// or "NAIC" | "ISO_42001" | "NIST_AI_RMF"

const gaps = matrix.controls.filter(c => c.status === "gap");
console.log(`${gaps.length} gaps found in ${matrix.framework}`);

for (const control of matrix.controls) {
  console.log(`${control.control_id} — ${control.status} (${control.evidence_count} evidence items)`);
  if (control.gap_description) console.log("  Gap:", control.gap_description);
}
```

**`MatrixResponse` fields:**

```ts
{
  framework: "EU_AI_ACT",
  assessed_at: "2025-03-15T10:00:00Z",
  org_id: "org_xxx",
  controls: [
    {
      control_id: "EU-AIA-9",
      control_name: "Risk Management System",
      article: "Article 9",
      status: "compliant",       // "compliant" | "partial" | "gap"
      evidence_count: 12,
      last_evidence_date: "2025-03-10T09:00:00Z",
      gap_description: null,     // non-null only when status === "gap"
    },
    // ...
  ],
}
```

---

### `client.generateEvidencePackage(payload)` → `Promise<EvidenceResponse>`

Generate an audit-ready evidence bundle for a date range.

```ts
const pkg = await client.generateEvidencePackage({
  framework: "EU_AI_ACT",
  date_from: "2025-01-01",
  date_to: "2025-03-31",
});

console.log(`Package ${pkg.package_id}: ${pkg.decision_count} decisions, ${pkg.violation_count} violations`);
```

---

## Error handling

```ts
import {
  GlidepathsError,
  AuthError,
  RateLimitError,
  ValidationError,
  PolicyViolationError,
} from "@glidepaths/sdk";

try {
  await client.log({ ... });
} catch (e) {
  if (e instanceof AuthError) {
    console.error("Invalid or expired API key");
  } else if (e instanceof RateLimitError) {
    console.error(`Rate limited. Retry after ${e.retryAfter}s`);
    await sleep(e.retryAfter * 1000);
  } else if (e instanceof PolicyViolationError) {
    console.error("All events blocked:", e.blockedDetails);
  } else if (e instanceof ValidationError) {
    console.error("Bad request:", e.message);
  } else if (e instanceof GlidepathsError) {
    console.error(`API error ${e.statusCode}:`, e.message);
  } else {
    throw e;
  }
}
```

---

## LangChain integration

Install the callback handler from the `integrations/langchain` sub-path. No changes to your agent code needed — drop it into any chain or executor.

```bash
npm install @glidepaths/sdk langchain @langchain/core
```

```ts
import { GlidepathsClient } from "@glidepaths/sdk";
import { GlidepathsCallbackHandler } from "@glidepaths/sdk/integrations/langchain";
import { AgentExecutor, createReactAgent } from "langchain/agents";
import { ChatOpenAI } from "@langchain/openai";
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";

const glidepaths = new GlidepathsClient({ apiKey: process.env.GLIDEPATHS_API_KEY! });

const handler = new GlidepathsCallbackHandler(glidepaths, {
  agentName: "research-agent-v1",
  riskLevel: "medium",
  complianceTags: ["EU_AI_ACT_ART_13"],
  // Set to true to call evaluate() before each tool use
  evaluateBeforeToolUse: true,
  // Optional: custom handler when a tool is blocked
  onBlocked: (toolName, reason) => {
    throw new Error(`Tool "${toolName}" was blocked: ${reason}`);
  },
});

const llm = new ChatOpenAI({ model: "gpt-4o" });
const tools = [new TavilySearchResults()];
const agent = await createReactAgent({ llm, tools });

const executor = AgentExecutor.fromAgentAndTools({
  agent,
  tools,
  callbacks: [handler],   // ← Glidepaths governance added here
});

const result = await executor.invoke({ input: "What is the current EU AI Act enforcement status?" });
```

**What gets logged automatically:**

| LangChain event | Glidepaths action |
|---|---|
| `handleAgentAction` | `evaluate()` (when `evaluateBeforeToolUse: true`) |
| `handleToolEnd` | `log()` with `decision_type: "tool_execution"` |
| `handleAgentEnd` | `log()` with `decision_type: "agent_finish"` |
| `handleLLMEnd` | `log()` with `decision_type: "llm_generation"` |
| `handleToolError` | `log()` with `decision_type: "tool_error"`, `risk_level: "high"` |

---

## OpenAI Assistants integration

Wraps the OpenAI Assistants run loop to evaluate every tool call against governance policies before execution.

```bash
npm install @glidepaths/sdk openai
```

```ts
import OpenAI from "openai";
import { GlidepathsClient } from "@glidepaths/sdk";
import { GlidepathsAssistantWrapper } from "@glidepaths/sdk/integrations/openai";

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const glidepaths = new GlidepathsClient({ apiKey: process.env.GLIDEPATHS_API_KEY! });

const wrapper = new GlidepathsAssistantWrapper(openai, glidepaths, {
  assistantId: "asst_abc123",
  agentName: "claims-assistant",
  riskLevel: "high",
  complianceTags: ["NAIC_AA", "EU_AI_ACT_ART_14"],

  // Your tool implementations
  tools: {
    lookup_claim: async ({ claim_id }) => {
      const claim = await db.claims.findById(String(claim_id));
      return JSON.stringify(claim);
    },
    approve_claim: async ({ claim_id, amount }) => {
      await payments.approve(String(claim_id), Number(amount));
      return `Claim ${claim_id} approved for $${amount}`;
    },
  },

  // Called when governance blocks a tool call
  onBlocked: (toolName, reason) =>
    `This action was blocked by your organisation's governance policy: ${reason}. Please suggest an alternative approach.`,
});

// Single-turn
const result = await wrapper.run("Approve the insurance claim for claimant C-4821.");
console.log(result.output);
console.log(`Tools executed: ${result.toolCallsExecuted}, blocked: ${result.toolCallsBlocked}`);

// Multi-turn (maintain conversation state)
const { threadId } = await wrapper.run("Look up claim CLM-9821.");
await wrapper.runOnThread(threadId, "Now approve it if the risk score is below 0.5.");
```

**Governance flow per tool call:**

1. `evaluate({ action_type: toolName, action_payload: toolArgs })` is called
2. If `isBlocked` → `onBlocked()` output is submitted to the assistant instead
3. If `requiresEscalation` → warning logged, tool executes (override in your `onBlocked`)
4. If `canProceed` → tool function executes
5. `log()` records the outcome with the full tool name, args, and output

---

## CommonJS usage

```js
const { GlidepathsClient } = require("@glidepaths/sdk");
const { GlidepathsCallbackHandler } = require("@glidepaths/sdk/integrations/langchain");

const client = new GlidepathsClient({ apiKey: process.env.GLIDEPATHS_API_KEY });
```

---

## Full `log()` payload reference

| Field | Type | Default | Description |
|---|---|---|---|
| `agent_name` | `string` | required | Agent identifier |
| `decision_type` | `string` | required | Category of decision |
| `decision_summary` | `string` | required | Human-readable description |
| `risk_level` | `RiskLevel` | `"low"` | `"low" \| "medium" \| "high" \| "critical"` |
| `delegation_tier` | `number` | `1` | Authority level (1–5) |
| `agent_id` | `string` | — | UUID of registered agent |
| `input_hash` | `string` | — | Hash for idempotent retries |
| `model_version` | `string` | — | Model identifier |
| `authority_scope` | `string[]` | — | What the agent was authorised to do |
| `override_triggered` | `boolean` | `false` | Whether a human override occurred |
| `override_rationale` | `string` | — | Explanation of override |
| `human_review_status` | `string` | `"not_required"` | Review state |
| `escalation_triggered` | `boolean` | `false` | Whether escalation occurred |
| `escalation_path` | `string` | — | Where it was escalated |
| `data_lineage` | `string` | — | Source of input data |
| `compliance_tags` | `string[]` | — | Regulatory framework tags |
| `metadata` | `object` | — | Arbitrary additional fields |
| `source_system` | `string` | — | Calling system identifier |
| `session_id` | `string` | — | Session grouping key |
| `decision_timestamp` | `string` | server now | ISO 8601 override |