Package Exports
- @cohesionauth/sdk
- @cohesionauth/sdk/package.json
Readme
@cohesionauth/sdk
Save humanity by keeping judgment alive in the age of AI.
Official TypeScript SDK for the COHESION Judgment Independence Score API. Measure and certify human oversight of AI-assisted decisions in real time, per EU AI Act Article 14, Colorado SB 205, and NYC Local Law 144.
- npm:
@cohesionauth/sdk - License: Apache-2.0
- Requires: Node.js 20 or later
- Base URL:
https://api.cohesionauth.com(human-readable docs athttps://cohesionauth.com/api)
Install
npm install @cohesionauth/sdkQuickstart
import { Cohesion } from "@cohesionauth/sdk";
const client = new Cohesion({ apiKey: process.env.COHESION_API_KEY! });
const result = await client.score({
session_id: "sess_2026_04_22_001",
operator_id: "analyst-42",
domain: "financial",
interaction: {
ai_recommendation_presented: true,
time_to_decision_ms: 3400,
decision: "modified",
modification_extent: 0.25,
ai_available: true,
scenario_type: "standard",
outcome_correct: null,
hover_events: 4,
scroll_depth: 0.9,
alternative_views_checked: 1,
},
});
console.log(`JIS ${result.jis} (${result.band})`);DRS gate — the Authorized Inference Gateway
cohesion.gate() wraps a regulated AI call with the Decision Risk Score engine. The contract is strict-gate, fail-closed: the SDK refuses to surface a final AI output unless DRS returned a clean routing_decision envelope.
import {
Cohesion,
gate,
CohesionPolicyBlockedError,
CohesionRequiresHumanReviewError,
CohesionMalformedDecisionError,
} from "@cohesionauth/sdk";
const client = new Cohesion({ apiKey: process.env.COHESION_API_KEY! });
// 1. Pre-AI pass: ask DRS whether the input is admissible at all.
const preDecision = await gate(client, request, null);
if (preDecision.routing_decision !== "auto") {
// must_review / async_review / forced_escalation — route to a human reviewer
// BEFORE calling the AI provider. preDecision.review_queue_id is the handle.
return routeToReviewer(preDecision);
}
// 2. Call the AI provider.
const aiOutput = await provider.complete(request);
// 3. Post-AI pass: ask DRS whether to surface the AI output.
try {
const postDecision = await gate(client, request, aiOutput);
// routing_decision === 'auto', no forced escalation — safe to surface.
return aiOutput;
} catch (e) {
if (e instanceof CohesionPolicyBlockedError) {
// Hard block: never surface this AI output. e.decision.drs_reason_codes
// and e.decision.policy_evaluation.hard_failures explain why.
return blockResponse(e);
}
if (e instanceof CohesionRequiresHumanReviewError) {
// Route to reviewer; e.decision.review_queue_id is the handle.
return routeToReviewer(e.decision);
}
if (e instanceof CohesionMalformedDecisionError) {
// Fail-closed sentinel: DRS returned 2xx but the envelope was malformed.
// Treat as a hard block. Contact support with e.requestId.
return blockResponse(e);
}
// Network / 5xx / retry-exhausted -> caller MUST treat as fail-closed.
// Do NOT surface the AI output. The plain `CohesionError`, `ServerError`,
// `NetworkError` types preserve `requestId` for incident tracing.
return blockResponse(e);
}The fail-closed contract on transport failure: if DRS does not return a 2xx envelope (network error, 5xx after retries, abort), gate() re-throws the underlying error unchanged. The caller MUST NOT surface the AI output. Treat any non-resolution as a hard block.
Error class taxonomy:
| Error | Thrown on | Carries |
|---|---|---|
CohesionPolicyBlockedError |
routing_decision === 'policy_blocked' on either pass |
decision.drs_reason_codes, decision.policy_evaluation.hard_failures, decision.ai_decision_log_id |
CohesionRequiresHumanReviewError |
Post-AI must_review / async_review / non-empty forced_escalation_rules_triggered |
decision.review_queue_id |
CohesionMalformedDecisionError |
2xx with missing or unrecognized envelope fields (fail-CLOSED) | observedKeys, missingFields |
ServerError / NetworkError |
retry-exhausted transport failure | requestId |
Pre-AI must_review / async_review / forced escalation return the envelope without throwing — that branch is the caller's signal to route to a reviewer before the AI call.
See examples/07-live-gate.ts for a runnable end-to-end demonstration.
Side-by-side
The same request in three forms.
cURL
curl https://api.cohesionauth.com/v1/score \
-H "X-API-Key: $COHESION_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d @payload.jsonPython
from cohesion import Client
client = Client(api_key=os.environ["COHESION_API_KEY"])
result = client.score(
session_id="sess_...",
operator_id="analyst-42",
domain="financial",
interaction={...},
)TypeScript
import { Cohesion } from "@cohesionauth/sdk";
const client = new Cohesion({ apiKey: process.env.COHESION_API_KEY! });
const result = await client.score({ /* ... */ });5-minute integrations (1.1.0)
Three drop-in patterns. Pick the one that fits your stack.
Express
import express from "express";
import { Cohesion, cohesionExpress } from "@cohesionauth/sdk";
const cohesion = new Cohesion({ apiKey: process.env.COHESION_API_KEY! });
const app = express();
app.use(
cohesionExpress({
client: cohesion,
domain: "financial",
operatorIdResolver: (req) => String(req.headers["x-user-id"] ?? "anon"),
}),
);Next.js (App Router route handler)
import { Cohesion, cohesionNextRoute } from "@cohesionauth/sdk";
const cohesion = new Cohesion({ apiKey: process.env.COHESION_API_KEY! });
export const POST = cohesionNextRoute(
async (req) => Response.json({ ok: true }),
{
client: cohesion,
domain: "general", // SOC alert-triage maps here per the v1.2 spec
operatorIdResolver: (req) => req.headers.get("x-user-id") ?? "anon",
},
);Decorator (any function — class method or HOF wrap)
import { measure } from "@cohesionauth/sdk";
const handle = measure({
client: cohesion,
domain: "financial",
operatorIdResolver: ([req]: [{ userId: string }]) => req.userId,
})(originalHandle);domain is one of healthcare | aviation | financial | legal | pharmaceutical | general. SOC use cases map to general per v1.2 §4 Option A.
For chat-completion patterns (OpenAI / Anthropic / LangChain / Vercel AI), see Provider integrations below or import the chat namespace:
import { chat } from "@cohesionauth/sdk";
const wrapped = chat.wrapOpenAI(openai, cohesion, ctx);Six full integration examples live under examples/.
Client options
new Cohesion({
apiKey: string, // required
baseUrl?: string, // default "https://api.cohesionauth.com"
timeout?: number, // default 30000 ms
maxRetries?: number, // default 3
logger?: Logger, // default createDefaultLogger()
enableTelemetry?: boolean, // default false (opt-in Sentry)
});Method reference
| Method | HTTP | Notes |
|---|---|---|
client.score(req) |
POST /v1/score |
Idempotency-Key auto-generated |
client.scoreBatch(req) |
POST /v1/score/batch |
up to 100 interactions |
client.operatorProfile(operatorId) |
GET /v1/operator/:id/profile |
includes JIS history |
client.organizationDashboard() |
GET /v1/organization/dashboard |
aggregate metrics |
client.maintenanceRecommend(req) |
POST /v1/maintenance/recommend |
judgment-maintenance exercises |
client.complianceReport() |
GET /v1/compliance/report |
EU AI Act Article 14 rollup |
client.adminKeyRotate() |
POST /v1/admin/key/rotate |
returns new key ONCE |
client.adminKeyRevoke() |
POST /v1/admin/key/revoke |
sets org inactive |
client.adminAuditLog(opts?) |
GET /v1/admin/audit-log |
own-org events only |
AI-provider wrappers
Instrument OpenAI, Anthropic, Azure OpenAI, Vercel AI SDK, or LangChain.
import OpenAI from "openai";
import { Cohesion, wrapOpenAI } from "@cohesionauth/sdk";
const cohesion = new Cohesion({ apiKey: process.env.COHESION_API_KEY! });
const openai = wrapOpenAI(new OpenAI(), cohesion, {
operatorId: "analyst-42",
sessionId: "sess_...",
domain: "financial",
});
const { response, recordDecision } = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: "Draft SAR narrative" }],
});
// Present `response` to the human. After they decide:
const score = await recordDecision({
decision: "modified",
modificationExtent: 0.3,
});Equivalent helpers: wrapAnthropic, wrapAzureOpenAI, vercelAIMiddleware, langChainHandler.
Errors
Every SDK error carries requestId and nextStep.
| Class | HTTP | Extra fields | nextStep example |
|---|---|---|---|
AuthenticationError |
401 | "Check the 8-character prefix of your key. New customers get a key at cohesionauth.com/signup; existing customers rotate at cohesionauth.com/dashboard/api-keys." | |
RateLimitError |
429 | retryAfter: number |
"Retry after 7 seconds." |
ValidationError |
400, 413, 422 | field, allowedValues |
"scenario_type must be one of: standard, independent, trap, split." |
ServerError |
5xx | populated only when actionable | |
NetworkError |
transport | cause |
"Check connectivity to api.cohesionauth.com and ensure TLS 1.3 egress is permitted from your environment." |
CohesionError |
base | hierarchy root |
import { RateLimitError } from "@cohesionauth/sdk";
try {
await client.score(req);
} catch (err) {
if (err instanceof RateLimitError) {
console.log(`Retry in ${err.retryAfter}s. Hint: ${err.nextStep}`);
} else {
throw err;
}
}CLI
npx cohesion score --operator-id analyst-42 --from-file payload.json
# or via stdin:
cat payload.json | npx cohesion score --operator-id analyst-42 --from-file -Retry and idempotency
- Exponential backoff with full jitter. Default max 3 retries.
- Retries only on 429 and 5xx. All 4xx (except 429) fail fast.
- Honors
Retry-Afterheader (integer seconds or HTTP-date). - Every POST auto-populates
Idempotency-Keywith a UUIDv4 so retries are safe to replay.
Environment variables
| Name | Purpose |
|---|---|
COHESION_API_KEY |
API key. Required for the CLI. |
COHESION_BASE_URL |
Override the base URL (staging, self-hosted). |
COHESION_LOG_FORMAT |
Set to json for structured logs. |
COHESION_LOG_LEVEL |
debug, info, warn, or error. |
COHESION_TEST_API_KEY |
Enables the live integration test. |
COHESION_SENTRY_DSN or SENTRY_DSN |
Opt-in telemetry, only when enableTelemetry: true. |
Logging and redaction
The default logger redacts API keys (ck_live_*) and operator_id values before emit. Set COHESION_LOG_FORMAT=json for structured output suitable for Datadog, Sentry, or Cloudflare Logpush.
License
Apache License 2.0. See LICENSE and NOTICE.
The COHESION Judgment Independence Score methodology, scoring engine, and intervention protocol are subject to the provisional patent filed 2026-04-13.