Official SDKs for assessing AI systems for ethical alignment. Test your AI across 4 dimensions: Lying, Cheating, Stealing, and Harm.
Your AI's API keys, system prompts, and configuration never leave your environment
Test configuration, questions, and thresholds managed via Health Check Key
Auto-detects GitHub Actions, GitLab CI, CircleCI, and more
npm install @aiassesstech/sdk
# or use the shorter package name:
npm install aiassesstechyarn add @aiassesstech/sdk
# or
yarn add aiassesstechpnpm add @aiassesstech/sdk
# or
pnpm add aiassesstech@aiassesstech/sdk and aiassesstech are identical. Use whichever you prefer!pip install aiassesspoetry add aiassessimport { AIAssessClient } from '@aiassesstech/sdk';
// 1. Create client with your Health Check Key
const client = new AIAssessClient({
healthCheckKey: process.env.AIASSESS_KEY!
});
// 2. Run assessment - configuration comes from server
const result = await client.assess(async (question) => {
// Your AI callback - send question to your AI and return response
return await myAI.chat(question);
});
// 3. Check result
console.log('Passed:', result.overallPassed);
console.log('Scores:', result.scores);
console.log('Classification:', result.classification);import os
from aiassess import AIAssessClient
# 1. Create client with your Health Check Key
with AIAssessClient(health_check_key=os.environ["AIASSESS_KEY"]) as client:
# 2. Define your AI callback
def my_ai_callback(question: str) -> str:
# Your AI logic here - return the response
return my_ai.chat(question)
# 3. Run assessment
result = client.assess(my_ai_callback)
# 4. Check result
print(f"Passed: {result.overall_passed}")
print(f"Scores: {result.scores}")
print(f"Classification: {result.classification}")with AIAssessClient(...) as client: for automatic resource cleanup, or instantiate directly with client = AIAssessClient(...).The SDK works with any AI that accepts text input and returns text output. Here are the providers we've tested and documented:
GPT-4, GPT-4o, GPT-3.5
Claude 3, Claude 3.5
Gemini Pro, 1.5, 2.0
Grok Beta, Grok 2
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Your Environment โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ 1. SDK fetches config from AI Assess Tech server โ
โ (questions, thresholds, test mode) โ
โ โ
โ 2. SDK sends questions to YOUR AI via your callback โ
โ โ Your API keys stay private โ
โ โ Your system prompts stay private โ
โ โ
โ 3. SDK submits responses to server for scoring โ
โ โ
โ 4. You receive scores, pass/fail, and classification โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโThe SDK is client-side code that runs in your environment. All security is enforced server-side โ the SDK cannot bypass rate limits, override thresholds, or fake scores.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ SECURITY ARCHITECTURE โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โ
SERVER ENFORCES: โ
โ โโโ Rate limiting (per IP for demo, per key for production) โ
โ โโโ Thresholds (from database, not client-provided) โ
โ โโโ Scoring (calculated server-side, immutable) โ
โ โโโ API key validation (hashed, checked against database) โ
โ โโโ Tier restrictions (DEMO, STANDARD, ENTERPRISE) โ
โ โโโ Result integrity (hashed and locked) โ
โ โ
โ ๐ YOUR DATA STAYS PRIVATE: โ
โ โโโ Your AI's API keys (OpenAI, Anthropic) never sent to us โ
โ โโโ Your system prompts stay in your environment โ
โ โโโ Only AI responses are submitted for scoring โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ| Security Control | Server-Side Enforcement |
|---|---|
| Rate Limiting | Enforced per IP (demo) or per key (production). SDK cannot bypass. |
| Thresholds | Stored in your API key config. Client cannot override pass/fail thresholds. |
| Scoring | Calculated entirely server-side based on question lookup. |
| Questions | Served from database. Client cannot modify question content. |
| Results | Hashed with SHA-256 and locked. Tamper-proof verification. |
| Tier Limits | Per-tier limits enforced from API key record. See table below. |
| Tier | Hourly Limit | Monthly Included | Overage |
|---|---|---|---|
| Demo | 5/hr per IP | โ | โ |
| Starter | 10/hr | 10 | $5/assessment |
| Professional | 50/hr | 50 | $3/assessment |
| Business | 200/hr | 200 | $2/assessment |
| Scale | 1000/hr | Unlimited | โ |
| Enterprise | Custom | Custom | Custom |
The open-source demo app uses a public demo key that is intentionally rate-limited server-side:
import OpenAI from 'openai';
import { AIAssessClient } from '@aiassesstech/sdk';
const openai = new OpenAI();
const client = new AIAssessClient({
healthCheckKey: process.env.AIASSESS_KEY!
});
const result = await client.assess(async (question) => {
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: question }]
});
return response.choices[0].message.content || '';
});
console.log(`Classification: ${result.classification}`);
console.log(`Lying Score: ${result.scores.lying}/10`);
console.log(`Overall: ${result.overallPassed ? 'PASSED โ
' : 'FAILED โ'}`);import os
from openai import OpenAI
from aiassess import AIAssessClient
openai_client = OpenAI()
with AIAssessClient(health_check_key=os.environ["AIASSESS_KEY"]) as client:
def openai_callback(question: str) -> str:
response = openai_client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": question}]
)
return response.choices[0].message.content or ""
result = client.assess(openai_callback)
print(f"Classification: {result.classification}")
print(f"Lying Score: {result.scores.lying}/10")
print(f"Overall: {'PASSED โ
' if result.overall_passed else 'FAILED โ'}")import Anthropic from '@anthropic-ai/sdk';
import { AIAssessClient } from '@aiassesstech/sdk';
const anthropic = new Anthropic();
const client = new AIAssessClient({
healthCheckKey: process.env.AIASSESS_KEY!
});
const result = await client.assess(async (question) => {
const response = await anthropic.messages.create({
model: 'claude-3-sonnet-20240229',
max_tokens: 100,
messages: [{ role: 'user', content: question }]
});
return response.content[0].type === 'text'
? response.content[0].text
: '';
});import os
from anthropic import Anthropic
from aiassess import AIAssessClient
anthropic = Anthropic()
with AIAssessClient(health_check_key=os.environ["AIASSESS_KEY"]) as client:
def claude_callback(question: str) -> str:
response = anthropic.messages.create(
model="claude-3-sonnet-20240229",
max_tokens=100,
messages=[{"role": "user", "content": question}]
)
return response.content[0].text if response.content else ""
result = client.assess(claude_callback)import { GoogleGenerativeAI } from '@google/generative-ai';
import { AIAssessClient } from '@aiassesstech/sdk';
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
const model = genAI.getGenerativeModel({ model: 'gemini-pro' });
const client = new AIAssessClient({
healthCheckKey: process.env.AIASSESS_KEY!
});
const result = await client.assess(async (question) => {
const response = await model.generateContent(question);
return response.response.text();
});
console.log(`Classification: ${result.classification}`);
console.log(`Overall: ${result.overallPassed ? 'PASSED โ
' : 'FAILED โ'}`);gemini-pro,gemini-1.5-pro, andgemini-2.0-flash.import { AIAssessClient } from '@aiassesstech/sdk';
const client = new AIAssessClient({
healthCheckKey: process.env.AIASSESS_KEY!
});
const result = await client.assess(async (question) => {
const response = await fetch('https://api.x.ai/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.XAI_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'grok-beta',
messages: [{ role: 'user', content: question }]
})
});
const data = await response.json();
return data.choices[0].message.content;
});
console.log(`Classification: ${result.classification}`);
console.log(`Overall: ${result.overallPassed ? 'PASSED โ
' : 'FAILED โ'}`);Test any AI model with an HTTP API โ perfect for self-hosted, fine-tuned, or enterprise models:
import { AIAssessClient } from '@aiassesstech/sdk';
const client = new AIAssessClient({
healthCheckKey: process.env.AIASSESS_KEY!
});
const result = await client.assess(async (question) => {
// Replace with your model's API endpoint
const response = await fetch('https://your-model-server.com/v1/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.YOUR_MODEL_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: question,
max_tokens: 100
})
});
const data = await response.json();
return data.text || data.response || data.output;
});const result = await client.assess(
async (question) => await myAI.chat(question),
{
onProgress: (progress) => {
console.log(`${progress.percentage}% - Testing ${progress.dimension}`);
// Output: "25% - Testing lying"
// Output: "50% - Testing cheating"
// Output: "75% - Testing stealing"
// Output: "100% - Testing harm"
}
}
);// Block until AI passes - exits process on failure
await client.blockUntilPass(
async (question) => await myAI.chat(question),
{
maxRetries: 3,
retryDelayMs: 60000, // 1 minute between retries
exitOnFailure: true
}
);
console.log('โ
AI passed ethical assessment, starting app...');
startApp();import { AIAssessClient, withRetry } from '@aiassesstech/sdk';
const result = await client.assess(
withRetry(
async (question) => await flakyAI.chat(question),
{ maxRetries: 3, backoffMs: 1000 }
)
);// Only asks 5 questions, returns mock scores
const result = await client.assess(
async (question) => await myAI.chat(question),
{ dryRun: true }
);The assess() method returns an AssessmentResult object:
interface AssessmentResult {
runId: string; // Server-generated ID for verification
sdkSessionId: string; // Client-generated session ID
scores: {
lying: number; // 0-10 scale
cheating: number;
stealing: number;
harm: number;
};
passed: {
lying: boolean; // Did score meet threshold?
cheating: boolean;
stealing: boolean;
harm: boolean;
};
overallPassed: boolean; // All dimensions must pass
classification:
| "Well Adjusted" // High scores across all dimensions
| "Misguided" // Low lying, high harm (believes false things but tries to do good)
| "Manipulative" // High lying, low harm (deceives but avoids direct harm)
| "Psychopath"; // Low scores across the board
thresholds: { // Thresholds used from server config
lying: number;
cheating: number;
stealing: number;
harm: number;
};
verifyUrl: string; // URL to verify this result
completedAt: string; // ISO timestamp
versions: {
sdk: string; // SDK version used
questionSet: string; // Question set version
};
keyName: string; // Name of Health Check Key used
// Ethereum-verified question bank (v1.2.12+)
bankVerification: {
bankVersionId: string; // Question bank version ID
bankHash: string | null; // SHA256 hash of questions
version: string; // Semantic version (e.g., "1.0.0")
lockedAt: string | null; // ISO timestamp when locked
ethereumTxHash: string | null; // ETH tx hash (on-chain proof)
etherscanUrl: string | null; // Direct Etherscan link
};
}Every assessment generates a tamper-proof verification URL that can be shared with auditors, compliance teams, or stakeholders to independently verify the assessment.
const result = await client.assess(callback);
// Get the verification URL
console.log(`Verify at: ${result.verifyUrl}`);
// https://aiassesstech.com/verify/result/clx123abc...
// The verification page shows:
// โ Assessment date and time
// โ Scores for all 4 dimensions
// โ Pass/fail status
// โ Classification result
// โ Cryptographic hash proofDisplay your AI's certification status on your website (coming in v1.0):
<!-- AI Assess Tech Certification Badge -->
<a href="https://www.aiassesstech.com/verify/YOUR_RUN_ID">
<img
src="https://www.aiassesstech.com/badge/YOUR_RUN_ID"
alt="AI Assess Tech Certified"
/>
</a>All assessments use an Ethereum-verified question bank. The question bank is cryptographically locked and published to the Ethereum blockchain, providing:
Questions cannot be modified after locking โ cryptographic proof of integrity
On-chain proof that all assessments use the same verified questions
Anyone can verify the question bank hash on Ethereum
Every assessment result includes bank verification info:
const result = await client.assess(callback);
// Display ETH verification to users
console.log(`Bank Version: ${result.bankVerification.version}`);
console.log(`Locked At: ${result.bankVerification.lockedAt}`);
console.log(`Bank Hash: ${result.bankVerification.bankHash}`);
// Link to Etherscan for on-chain proof
if (result.bankVerification.etherscanUrl) {
console.log(`Verify on Ethereum: ${result.bankVerification.etherscanUrl}`);
// Opens: https://etherscan.io/tx/0xea1c7c85fb5902b0db213f444c4a30...
}SDK responses include verification headers for programmatic access:
| Header | Description |
|---|---|
| X-Bank-Version | Question bank version (e.g., 1.0.0) |
| X-Bank-Hash | SHA256 hash of the question bank |
| X-ETH-TxHash | Ethereum transaction hash for verification |
const client = new AIAssessClient({
// Required: Your Health Check Key from the dashboard
healthCheckKey: 'hck_...',
// Optional: Override base URL (default: https://www.aiassesstech.com)
baseUrl: 'https://www.aiassesstech.com',
// Optional: Per-question timeout in ms (default: 30000 = 30s)
perQuestionTimeoutMs: 30000,
// Optional: Overall timeout in ms (default: 360000 = 6 min)
overallTimeoutMs: 360000
});Configuration is managed via the Health Check Key on the AI Assess Tech dashboard:
prod-strict - Production with strict thresholdsstaging-relaxed - Staging with relaxed thresholdsci-quick - CI/CD pipeline checksimport {
AIAssessClient,
SDKError,
ValidationError,
RateLimitError,
QuestionTimeoutError,
ErrorCode
} from '@aiassesstech/sdk';
try {
const result = await client.assess(callback);
} catch (error) {
if (error instanceof RateLimitError) {
console.log(`Rate limited. Retry after ${error.retryAfterMs}ms`);
} else if (error instanceof ValidationError) {
if (error.code === ErrorCode.KEY_EXPIRED) {
console.log('Health Check Key has expired');
} else if (error.code === ErrorCode.INVALID_KEY) {
console.log('Invalid Health Check Key');
}
} else if (error instanceof QuestionTimeoutError) {
console.log(`Question ${error.questionId} timed out`);
} else if (error instanceof SDKError) {
console.log(`SDK Error: ${error.message} (${error.code})`);
}
}| Code | Description |
|---|---|
| INVALID_KEY | Health Check Key is invalid or not found |
| KEY_EXPIRED | Health Check Key has expired |
| RATE_LIMITED | Too many requests, try again later |
| QUESTION_TIMEOUT | AI took too long to respond to a question |
| NETWORK_ERROR | Network connection failed |
| SERVER_ERROR | Server-side error occurred |
name: AI Ethics Health Check
on:
push:
branches: [main]
schedule:
- cron: "0 */6 * * *" # Every 6 hours
jobs:
health-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: npm install @aiassesstech/sdk openai
- name: Run AI Health Check
env:
AIASSESS_KEY: ${{ secrets.AIASSESS_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
node -e "
const { AIAssessClient } = require('@aiassesstech/sdk');
const OpenAI = require('openai');
const openai = new OpenAI();
const client = new AIAssessClient({
healthCheckKey: process.env.AIASSESS_KEY
});
client.assess(async (q) => {
const r = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: q }]
});
return r.choices[0].message.content;
}).then(result => {
console.log('Classification:', result.classification);
console.log('Scores:', JSON.stringify(result.scores));
process.exit(result.overallPassed ? 0 : 1);
}).catch(err => {
console.error('Error:', err.message);
process.exit(2);
});
"const result = await client.assess(
async (question) => await myAI.chat(question),
{
metadata: {
gitCommit: process.env.GITHUB_SHA,
branch: process.env.GITHUB_REF_NAME,
deployVersion: process.env.VERSION,
environment: process.env.NODE_ENV
}
}
);
// Exit code for CI/CD
// 0 = passed, 1 = failed, 2 = error
process.exit(result.overallPassed ? 0 : 1);The SDK automatically detects CI/CD environments:
import { detectEnvironment, isCI } from '@aiassesstech/sdk';
console.log('Is CI:', isCI());
console.log('Environment:', detectEnvironment());
// {
// nodeVersion: 'v20.10.0',
// platform: 'linux',
// ciProvider: 'github-actions',
// ciJobId: '12345678',
// gitCommit: 'abc123...',
// gitBranch: 'main'
// }Wrap your AI callback with automatic retry logic:
import { withRetry } from '@aiassesstech/sdk';
const resilientCallback = withRetry(
async (question) => await flakyAPI.chat(question),
{
maxRetries: 3, // Number of retry attempts
backoffMs: 1000, // Initial backoff delay
backoffMultiplier: 2 // Exponential backoff multiplier
}
);
const result = await client.assess(resilientCallback);Configure webhooks to receive real-time notifications when assessments complete:
{
"event": "assessment.completed",
"runId": "clx123abc...",
"timestamp": "2026-02-15T10:30:00Z",
"result": {
"overallPassed": true,
"classification": "Well Adjusted",
"scores": {
"lying": 8.5,
"cheating": 9.0,
"stealing": 8.7,
"harm": 9.2
}
},
"metadata": {
"keyName": "prod-strict",
"environment": "production"
}
}assessment.completed โ Assessment finished (pass or fail)assessment.failed โ Assessment failed thresholdsassessment.warning โ Score within 1 point of thresholdkey.rate_limited โ Health Check Key hit rate limitThe Python SDK provides the same functionality as the TypeScript SDK, with Python-native features like context managers, async support, Pydantic models, and a CLI tool.
For async applications, use AsyncAIAssessClient:
import asyncio
import os
from aiassess import AsyncAIAssessClient
async def main():
async with AsyncAIAssessClient(
health_check_key=os.environ["AIASSESS_KEY"]
) as client:
async def my_async_callback(question: str) -> str:
# Your async AI logic here
return await my_async_ai.chat(question)
result = await client.assess(my_async_callback)
print(f"Passed: {result.overall_passed}")
asyncio.run(main())The Python SDK includes a command-line interface for quick assessments:
# Run assessment with OpenAI
aiassess run --provider openai --model gpt-4
# Run with Anthropic
aiassess run --provider anthropic --model claude-3-sonnet-20240229
# Dry run mode (fewer questions, mock scores)
aiassess run --provider openai --model gpt-4 --dry-run
# Check SDK version
aiassess --versionAIASSESS_KEY and your AI provider's API key (e.g., OPENAI_API_KEY) before running CLI commands.from aiassess import AIAssessClient
with AIAssessClient(health_check_key=key) as client:
def on_progress(progress):
print(f"{progress.percentage}% - Testing {progress.dimension}")
result = client.assess(
callback=my_callback,
on_progress=on_progress
)from aiassess import AIAssessClient
with AIAssessClient(health_check_key=key) as client:
# Block until AI passes - raises exception on failure
client.block_until_pass(
callback=my_callback,
max_retries=3,
retry_delay_seconds=60
)
print("โ
AI passed ethical assessment, starting app...")
start_app()from aiassess import (
AIAssessClient,
AIAssessError,
RateLimitError,
ValidationError,
QuestionTimeoutError,
)
try:
with AIAssessClient(health_check_key=key) as client:
result = client.assess(my_callback)
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after_seconds}s")
except ValidationError as e:
if e.code == "KEY_EXPIRED":
print("Health Check Key has expired")
elif e.code == "INVALID_KEY":
print("Invalid Health Check Key")
except QuestionTimeoutError as e:
print(f"Question {e.question_id} timed out")
except AIAssessError as e:
print(f"SDK Error: {e.message} ({e.code})")All response models use Pydantic v2 for full type safety and IDE autocompletion:
from aiassess.models import AssessmentResult, Scores
result: AssessmentResult = client.assess(my_callback)
# Full IDE autocompletion and type checking
scores: Scores = result.scores
print(f"Lying: {scores.lying}") # float
print(f"Cheating: {scores.cheating}") # float
print(f"Overall: {result.overall_passed}") # bool
print(f"Classification: {result.classification}") # Literal typehck_...) and store it securelyMIT ยฉ AI Assess Tech