UNPKG

@ethicalzen/sdk

Version:

Official EthicalZen SDK for Node.js - AI safety guardrails made simple

296 lines (295 loc) 10.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EthicalZenClient = void 0; const axios_1 = __importDefault(require("axios")); /** * EthicalZen Client * * Core client for interacting with the EthicalZen API. * Supports two modes: * - **Explicit** (default): Uses custom headers (X-Certificate-ID, X-Tenant-ID, X-Target-Endpoint) * - **Transparent**: Acts as transparent proxy (certificate in path, no custom headers) * * @example Explicit Mode (Default) * ```typescript * const client = new EthicalZenClient({ * apiKey: process.env.ETHICALZEN_API_KEY, * tenantId: 'demo', * mode: 'explicit' * }); * * const result = await client.enforce({ * contractId: 'my-service/general/us/v1.0', * payload: { output: 'AI response here' } * }); * ``` * * @example Transparent Mode (Zero Custom Code) * ```typescript * const client = new EthicalZenClient({ * apiKey: process.env.ETHICALZEN_API_KEY, * certificateId: 'hipaa-compliant-llm-v1', * baseURL: 'http://gateway:8080', * mode: 'transparent' * }); * * // Get transparent proxy URL for OpenAI * const proxyURL = client.getTransparentProxyURL('https://api.openai.com/v1'); * * // Use with standard OpenAI SDK * const openai = new OpenAI({ * apiKey: process.env.OPENAI_API_KEY, * baseURL: proxyURL * }); * ``` */ class EthicalZenClient { constructor(config) { if (!config.apiKey) { throw new Error('EthicalZen API key is required'); } // Validate mode-specific requirements this.mode = config.mode || 'explicit'; if (this.mode === 'explicit') { if (!config.tenantId) { throw new Error('Tenant ID is required for explicit mode'); } this.tenantId = config.tenantId; } else if (this.mode === 'transparent') { if (!config.certificateId) { throw new Error('Certificate ID is required for transparent mode'); } this.certificateId = config.certificateId; } this.apiKey = config.apiKey; this.gatewayURL = config.baseURL || 'http://localhost:8080'; // Setup axios client based on mode if (this.mode === 'explicit') { this.client = axios_1.default.create({ baseURL: this.gatewayURL, timeout: config.timeout || 30000, headers: { 'X-API-Key': config.apiKey, 'X-Tenant-ID': config.tenantId, 'Content-Type': 'application/json', 'User-Agent': '@ethicalzen/sdk/0.1.0' } }); } else { // Transparent mode - minimal headers this.client = axios_1.default.create({ baseURL: this.gatewayURL, timeout: config.timeout || 30000, headers: { 'Content-Type': 'application/json', 'User-Agent': '@ethicalzen/sdk/0.1.0' } }); } } /** * Get transparent proxy URL for a target service * Only works in transparent mode * * @param targetURL - Target service URL (e.g., https://api.openai.com/v1) * @returns Transparent proxy URL in format: {gateway}/proxy/{cert}/{target} * * @example * ```typescript * const client = new EthicalZenClient({ * apiKey: 'sk-...', * certificateId: 'hipaa-compliant-llm-v1', * baseURL: 'http://gateway:8080', * mode: 'transparent' * }); * * // Get proxy URL * const proxyURL = client.getTransparentProxyURL('https://api.openai.com/v1'); * // Returns: http://gateway:8080/proxy/hipaa-compliant-llm-v1/https://api.openai.com/v1 * * // Use with OpenAI SDK * const openai = new OpenAI({ apiKey: '...', baseURL: proxyURL }); * ``` */ getTransparentProxyURL(targetURL) { if (this.mode !== 'transparent') { throw new Error('getTransparentProxyURL() only works in transparent mode'); } if (!this.certificateId) { throw new Error('Certificate ID is required for transparent proxy'); } // Build transparent proxy URL: {gateway}/proxy/{cert}/{target} return `${this.gatewayURL}/proxy/${this.certificateId}/${targetURL}`; } /** * Get current mode * @returns Current SDK mode ('explicit' or 'transparent') */ getMode() { return this.mode; } /** * Get certificate ID (transparent mode only) * @returns Certificate ID or undefined */ getCertificateId() { return this.certificateId; } /** * Get tenant ID (explicit mode only) * @returns Tenant ID or undefined */ getTenantId() { return this.tenantId; } /** * Enforce contract guardrails on AI input/output * Works in both explicit and transparent modes * * @param request - Enforcement request with contractId and payload * @returns Enforcement result with violations (if any) * * @example Explicit Mode * ```typescript * const result = await client.enforce({ * contractId: 'chatbot/general/us/v1.0', * payload: { * output: 'Your AI response here' * } * }); * ``` * * @example Transparent Mode * ```typescript * // Transparent mode typically doesn't use enforce() directly * // Instead, use getTransparentProxyURL() with standard SDKs * ``` */ async enforce(request) { try { // Go ACVPS Gateway API: POST /api/validate const response = await this.client.post('/api/validate', { contract_id: request.contractId, payload: request.payload }); // Map Go gateway response to SDK format const violations = (response.data.violations || []).map((v) => ({ policyId: v.feature || 'unknown', guardrail: v.feature || 'unknown', message: `Envelope violation: ${v.feature} = ${v.value} (allowed: ${v.min}-${v.max})`, severity: 'high', details: { feature: v.feature, value: v.value, min: v.min, max: v.max } })); return { success: true, passed: response.data.valid === true, contractId: request.contractId, tenantId: this.tenantId || 'transparent', violations: violations, features: response.data.features, extractionTimeMs: response.data.extraction_time_ms, validationTimeMs: response.data.validation_time_ms, detectionMethod: response.data.detection_method, timestamp: new Date().toISOString(), latencyMs: (response.data.extraction_time_ms || 0) + (response.data.validation_time_ms || 0) }; } catch (error) { // If enforcement fails, return safe default (fail-open vs fail-closed configurable) return { success: false, passed: false, contractId: request.contractId, tenantId: this.tenantId || 'transparent', violations: [{ policyId: 'enforcement_error', guardrail: 'system', message: error.response?.data?.error || error.message || 'Enforcement failed', severity: 'critical', details: { error: error.toString(), status: error.response?.status, data: error.response?.data } }], timestamp: new Date().toISOString() }; } } /** * Register a new AI service for safety certification * * @param service - Service details * @returns Registration response with evaluation ID * * @example * ```typescript * const result = await client.registerService({ * name: 'customer-support-bot', * description: 'AI chatbot for customer support', * domain: 'general', * region: 'us' * }); * * console.log('Evaluation ID:', result.evaluationId); * ``` */ async registerService(service) { try { const response = await this.client.post('/services/register', service); return { success: true, evaluationId: response.data.evaluation_id || response.data.evaluationId, message: response.data.message || 'Service registered successfully' }; } catch (error) { throw new Error(`Failed to register service: ${error.message}`); } } /** * Get evaluation results for a registered service * * @param evaluationId - Evaluation ID from registration * @returns Evaluation results */ async getEvaluationResults(evaluationId) { try { const response = await this.client.get(`/api/simulation-results/${evaluationId}`); return response.data; } catch (error) { throw new Error(`Failed to get evaluation results: ${error.message}`); } } /** * Approve a certificate after reviewing evaluation results * * @param evaluationId - Evaluation ID to approve * @param notes - Optional approval notes * @returns Approval response with contract ID */ async approveCertificate(evaluationId, notes) { try { const response = await this.client.post('/api/evaluation/approve', { evaluationId, notes }); return response.data; } catch (error) { throw new Error(`Failed to approve certificate: ${error.message}`); } } } exports.EthicalZenClient = EthicalZenClient;