@vorionsys/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts ADDED
@@ -0,0 +1,559 @@
1
+ /**
2
+ * @vorionsys/sdk - Vorion SDK
3
+ *
4
+ * Simple, developer-friendly interface for AI agent governance.
5
+ * Supports both local mode (in-memory) and remote mode (cognigate-api).
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
10
+ import * as crypto from 'node:crypto';
11
+
12
+ // Re-export runtime types for convenience
13
+ export type {
14
+ TrustTier,
15
+ DecisionTier,
16
+ AgentCredentials,
17
+ Action,
18
+ TrustSignal,
19
+ } from '@vorionsys/runtime';
20
+
21
+ /**
22
+ * SDK Configuration
23
+ */
24
+ export interface VorionConfig {
25
+ /** API endpoint for hosted Cognigate */
26
+ apiEndpoint?: string;
27
+ /** API key for authentication */
28
+ apiKey?: string;
29
+ /** Default observation tier for agents */
30
+ defaultObservationTier?: 'BLACK_BOX' | 'GRAY_BOX' | 'WHITE_BOX';
31
+ /** Enable local mode (no API calls). If false and apiEndpoint is provided, uses remote mode. */
32
+ localMode?: boolean;
33
+ /** Request timeout in ms (default: 30000) */
34
+ timeout?: number;
35
+ }
36
+
37
+ /**
38
+ * Agent registration options
39
+ */
40
+ export interface AgentOptions {
41
+ /** Unique agent identifier */
42
+ agentId: string;
43
+ /** Human-readable name */
44
+ name: string;
45
+ /** Agent capabilities/permissions */
46
+ capabilities?: string[];
47
+ /** Observation tier */
48
+ observationTier?: 'BLACK_BOX' | 'GRAY_BOX' | 'WHITE_BOX';
49
+ /** Additional metadata */
50
+ metadata?: Record<string, unknown>;
51
+ }
52
+
53
+ /**
54
+ * Result of an action request
55
+ */
56
+ export interface ActionResult {
57
+ /** Whether the action was allowed */
58
+ allowed: boolean;
59
+ /** Decision tier (GREEN/YELLOW/RED) */
60
+ tier: 'GREEN' | 'YELLOW' | 'RED';
61
+ /** Human-readable reason */
62
+ reason: string;
63
+ /** Proof commitment ID for audit */
64
+ proofId: string;
65
+ /** Any constraints applied */
66
+ constraints?: string[];
67
+ /** Processing time in ms (remote mode only) */
68
+ processingTimeMs?: number;
69
+ }
70
+
71
+ /**
72
+ * Trust score information
73
+ */
74
+ export interface TrustInfo {
75
+ /** Current trust score (0-1000) */
76
+ score: number;
77
+ /** Trust tier name */
78
+ tierName: string;
79
+ /** Trust tier number (0-7) */
80
+ tierNumber: number;
81
+ /** Observation tier */
82
+ observationTier: string;
83
+ }
84
+
85
+ /**
86
+ * API Client for cognigate-api
87
+ */
88
+ class ApiClient {
89
+ private baseUrl: string;
90
+ private apiKey: string;
91
+ private timeout: number;
92
+
93
+ constructor(baseUrl: string, apiKey: string, timeout: number = 30000) {
94
+ this.baseUrl = baseUrl.replace(/\/$/, ''); // Remove trailing slash
95
+ this.apiKey = apiKey;
96
+ this.timeout = timeout;
97
+ }
98
+
99
+ async request<T>(method: string, path: string, body?: unknown): Promise<T> {
100
+ const controller = new AbortController();
101
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
102
+
103
+ try {
104
+ const response = await fetch(`${this.baseUrl}${path}`, {
105
+ method,
106
+ headers: {
107
+ 'Content-Type': 'application/json',
108
+ 'Authorization': `Bearer ${this.apiKey}`,
109
+ },
110
+ body: body ? JSON.stringify(body) : undefined,
111
+ signal: controller.signal,
112
+ });
113
+
114
+ if (!response.ok) {
115
+ const errorData = await response.json().catch(() => ({ error: 'Unknown error' })) as { error?: string; message?: string };
116
+ throw new Error(`API error ${response.status}: ${errorData.error || errorData.message || 'Unknown'}`);
117
+ }
118
+
119
+ return await response.json() as T;
120
+ } finally {
121
+ clearTimeout(timeoutId);
122
+ }
123
+ }
124
+
125
+ // Intent endpoints
126
+ async submitIntent(payload: {
127
+ agentId: string;
128
+ agentName?: string;
129
+ capabilities?: string[];
130
+ observationTier?: string;
131
+ action: { type: string; resource: string; parameters?: Record<string, unknown> };
132
+ }) {
133
+ return this.request<{
134
+ intentId: string;
135
+ allowed: boolean;
136
+ tier: string;
137
+ reason: string;
138
+ proofId: string;
139
+ constraints?: string[];
140
+ processingTimeMs: number;
141
+ }>('POST', '/api/v1/intents', payload);
142
+ }
143
+
144
+ async checkIntent(payload: {
145
+ agentId: string;
146
+ agentName?: string;
147
+ capabilities?: string[];
148
+ observationTier?: string;
149
+ action: { type: string; resource: string };
150
+ }) {
151
+ return this.request<{
152
+ wouldAllow: boolean;
153
+ tier: string;
154
+ reason: string;
155
+ }>('POST', '/api/v1/intents/check', payload);
156
+ }
157
+
158
+ // Trust endpoints
159
+ async admitAgent(payload: {
160
+ agentId: string;
161
+ name: string;
162
+ capabilities: string[];
163
+ observationTier: string;
164
+ }) {
165
+ return this.request<{
166
+ admitted: boolean;
167
+ initialTier: number;
168
+ initialScore: number;
169
+ observationCeiling: number;
170
+ capabilities: string[];
171
+ expiresAt: string;
172
+ reason?: string;
173
+ }>('POST', '/api/v1/trust/admit', payload);
174
+ }
175
+
176
+ async getTrustInfo(agentId: string) {
177
+ return this.request<{
178
+ agentId: string;
179
+ score: number | null;
180
+ tier: number | null;
181
+ tierName: string | null;
182
+ observationCeiling?: number;
183
+ message?: string;
184
+ }>('GET', `/api/v1/trust/${agentId}`);
185
+ }
186
+
187
+ async recordSignal(agentId: string, payload: {
188
+ type: 'success' | 'failure' | 'violation' | 'neutral';
189
+ source: string;
190
+ weight?: number;
191
+ context?: Record<string, unknown>;
192
+ }) {
193
+ return this.request<{
194
+ accepted: boolean;
195
+ scoreBefore: number;
196
+ scoreAfter: number;
197
+ change: number;
198
+ newTier: number | null;
199
+ newTierName: string | null;
200
+ }>('POST', `/api/v1/trust/${agentId}/signal`, payload);
201
+ }
202
+
203
+ // Health check
204
+ async health() {
205
+ return this.request<{ status: string; version: string }>('GET', '/api/v1/health');
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Vorion SDK Client
211
+ *
212
+ * Simple interface for agent governance.
213
+ *
214
+ * @example
215
+ * ```typescript
216
+ * // Local mode (in-memory, for testing)
217
+ * const vorion = new Vorion({ localMode: true });
218
+ *
219
+ * // Remote mode (cognigate-api)
220
+ * const vorion = new Vorion({
221
+ * apiEndpoint: 'http://localhost:3000',
222
+ * apiKey: 'vorion-dev-key-12345',
223
+ * });
224
+ *
225
+ * const agent = vorion.registerAgent({
226
+ * agentId: 'my-agent',
227
+ * name: 'My AI Agent',
228
+ * capabilities: ['read:*', 'write:*'],
229
+ * });
230
+ *
231
+ * const result = await agent.requestAction({
232
+ * type: 'read',
233
+ * resource: 'documents/report.pdf',
234
+ * });
235
+ *
236
+ * if (result.allowed) {
237
+ * // Perform the action
238
+ * await agent.reportSuccess('read');
239
+ * } else {
240
+ * console.log('Denied:', result.reason);
241
+ * }
242
+ * ```
243
+ */
244
+ export class Vorion {
245
+ private config: VorionConfig;
246
+ private agents: Map<string, Agent> = new Map();
247
+ private apiClient: ApiClient | null = null;
248
+
249
+ constructor(config: VorionConfig = {}) {
250
+ this.config = {
251
+ localMode: !config.apiEndpoint,
252
+ defaultObservationTier: 'GRAY_BOX',
253
+ timeout: 30000,
254
+ ...config,
255
+ };
256
+
257
+ // Initialize API client for remote mode
258
+ if (!this.config.localMode && this.config.apiEndpoint) {
259
+ if (!this.config.apiKey) {
260
+ throw new Error('apiKey is required for remote mode');
261
+ }
262
+ this.apiClient = new ApiClient(
263
+ this.config.apiEndpoint,
264
+ this.config.apiKey,
265
+ this.config.timeout
266
+ );
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Register an agent with the governance system
272
+ */
273
+ async registerAgent(options: AgentOptions): Promise<Agent> {
274
+ const agent = new Agent(this, options);
275
+
276
+ // In remote mode, admit the agent via API
277
+ if (this.apiClient) {
278
+ await this.apiClient.admitAgent({
279
+ agentId: options.agentId,
280
+ name: options.name,
281
+ capabilities: options.capabilities ?? [],
282
+ observationTier: options.observationTier ?? this.config.defaultObservationTier ?? 'GRAY_BOX',
283
+ });
284
+ }
285
+
286
+ this.agents.set(options.agentId, agent);
287
+ return agent;
288
+ }
289
+
290
+ /**
291
+ * Get a registered agent by ID
292
+ */
293
+ getAgent(agentId: string): Agent | undefined {
294
+ return this.agents.get(agentId);
295
+ }
296
+
297
+ /**
298
+ * Get all registered agents
299
+ */
300
+ getAllAgents(): Agent[] {
301
+ return Array.from(this.agents.values());
302
+ }
303
+
304
+ /**
305
+ * Get SDK configuration
306
+ */
307
+ getConfig(): VorionConfig {
308
+ return { ...this.config };
309
+ }
310
+
311
+ /**
312
+ * Get the API client (for advanced use)
313
+ */
314
+ getApiClient(): ApiClient | null {
315
+ return this.apiClient;
316
+ }
317
+
318
+ /**
319
+ * Check if running in local mode
320
+ */
321
+ isLocalMode(): boolean {
322
+ return this.config.localMode ?? true;
323
+ }
324
+
325
+ /**
326
+ * Health check (remote mode only)
327
+ */
328
+ async healthCheck(): Promise<{ status: string; version: string }> {
329
+ if (!this.apiClient) {
330
+ return { status: 'healthy', version: 'local' };
331
+ }
332
+ return this.apiClient.health();
333
+ }
334
+ }
335
+
336
+ /**
337
+ * Agent wrapper for simplified governance interactions
338
+ */
339
+ export class Agent {
340
+ private sdk: Vorion;
341
+ private options: AgentOptions;
342
+ private localTrustScore = 500; // Start at T3 (Monitored) for local mode
343
+ private actionHistory: Array<{ action: string; allowed: boolean; timestamp: number }> = [];
344
+
345
+ constructor(sdk: Vorion, options: AgentOptions) {
346
+ this.sdk = sdk;
347
+ this.options = {
348
+ observationTier: sdk.getConfig().defaultObservationTier,
349
+ capabilities: [],
350
+ ...options,
351
+ };
352
+ }
353
+
354
+ /**
355
+ * Request permission to perform an action
356
+ */
357
+ async requestAction(action: {
358
+ type: string;
359
+ resource: string;
360
+ parameters?: Record<string, unknown>;
361
+ }): Promise<ActionResult> {
362
+ const apiClient = this.sdk.getApiClient();
363
+
364
+ // Remote mode: call cognigate-api
365
+ if (apiClient) {
366
+ const result = await apiClient.submitIntent({
367
+ agentId: this.options.agentId,
368
+ agentName: this.options.name,
369
+ capabilities: this.options.capabilities,
370
+ observationTier: this.options.observationTier,
371
+ action,
372
+ });
373
+
374
+ this.actionHistory.push({
375
+ action: action.type,
376
+ allowed: result.allowed,
377
+ timestamp: Date.now(),
378
+ });
379
+
380
+ return {
381
+ allowed: result.allowed,
382
+ tier: result.tier as 'GREEN' | 'YELLOW' | 'RED',
383
+ reason: result.reason,
384
+ proofId: result.proofId,
385
+ constraints: result.constraints,
386
+ processingTimeMs: result.processingTimeMs,
387
+ };
388
+ }
389
+
390
+ // Local mode: simple capability check
391
+ const proofId = crypto.randomUUID();
392
+ const hasCapability = this.options.capabilities?.some(cap =>
393
+ cap === '*' ||
394
+ cap === action.type || // Simple capability (e.g., 'read')
395
+ cap === `${action.type}:*` ||
396
+ cap === `${action.type}:${action.resource.split('/')[0]}`
397
+ ) ?? false;
398
+ const allowed = hasCapability && this.localTrustScore >= 200;
399
+
400
+ if (allowed) {
401
+ this.localTrustScore = Math.min(1000, this.localTrustScore + 1);
402
+ }
403
+
404
+ this.actionHistory.push({
405
+ action: action.type,
406
+ allowed,
407
+ timestamp: Date.now(),
408
+ });
409
+
410
+ return {
411
+ allowed,
412
+ tier: allowed ? 'GREEN' : 'RED',
413
+ reason: allowed
414
+ ? 'Action permitted'
415
+ : hasCapability
416
+ ? 'Trust score too low'
417
+ : `Missing capability: ${action.type}:${action.resource.split('/')[0]}`,
418
+ proofId,
419
+ constraints: allowed ? this.getConstraintsForTier() : undefined,
420
+ };
421
+ }
422
+
423
+ /**
424
+ * Report action completion (positive signal)
425
+ */
426
+ async reportSuccess(actionType: string): Promise<void> {
427
+ const apiClient = this.sdk.getApiClient();
428
+
429
+ if (apiClient) {
430
+ await apiClient.recordSignal(this.options.agentId, {
431
+ type: 'success',
432
+ source: 'sdk',
433
+ weight: 0.1,
434
+ context: { actionType },
435
+ });
436
+ } else {
437
+ this.localTrustScore = Math.min(1000, this.localTrustScore + 2);
438
+ }
439
+ }
440
+
441
+ /**
442
+ * Report action failure (negative signal)
443
+ */
444
+ async reportFailure(actionType: string, reason?: string): Promise<void> {
445
+ const apiClient = this.sdk.getApiClient();
446
+
447
+ if (apiClient) {
448
+ await apiClient.recordSignal(this.options.agentId, {
449
+ type: 'failure',
450
+ source: 'sdk',
451
+ weight: 0.5,
452
+ context: { actionType, reason },
453
+ });
454
+ } else {
455
+ this.localTrustScore = Math.max(0, this.localTrustScore - 20);
456
+ }
457
+ }
458
+
459
+ /**
460
+ * Get current trust information
461
+ */
462
+ async getTrustInfo(): Promise<TrustInfo> {
463
+ const apiClient = this.sdk.getApiClient();
464
+
465
+ if (apiClient) {
466
+ const info = await apiClient.getTrustInfo(this.options.agentId);
467
+ return {
468
+ score: info.score ?? 0,
469
+ tierName: info.tierName ?? 'Unknown',
470
+ tierNumber: info.tier ?? 0,
471
+ observationTier: this.options.observationTier ?? 'GRAY_BOX',
472
+ };
473
+ }
474
+
475
+ return {
476
+ score: this.localTrustScore,
477
+ tierName: this.getTierName(),
478
+ tierNumber: this.getTierNumber(),
479
+ observationTier: this.options.observationTier ?? 'GRAY_BOX',
480
+ };
481
+ }
482
+
483
+ /**
484
+ * Get agent ID
485
+ */
486
+ getId(): string {
487
+ return this.options.agentId;
488
+ }
489
+
490
+ /**
491
+ * Get agent name
492
+ */
493
+ getName(): string {
494
+ return this.options.name;
495
+ }
496
+
497
+ /**
498
+ * Get agent capabilities
499
+ */
500
+ getCapabilities(): string[] {
501
+ return [...(this.options.capabilities ?? [])];
502
+ }
503
+
504
+ /**
505
+ * Get action history
506
+ */
507
+ getActionHistory(): Array<{ action: string; allowed: boolean; timestamp: number }> {
508
+ return [...this.actionHistory];
509
+ }
510
+
511
+ private getTierNumber(): number {
512
+ if (this.localTrustScore < 200) return 0;
513
+ if (this.localTrustScore < 350) return 1;
514
+ if (this.localTrustScore < 500) return 2;
515
+ if (this.localTrustScore < 650) return 3;
516
+ if (this.localTrustScore < 800) return 4;
517
+ if (this.localTrustScore < 876) return 5;
518
+ if (this.localTrustScore < 951) return 6;
519
+ return 7;
520
+ }
521
+
522
+ private getTierName(): string {
523
+ const names = [
524
+ 'Sandbox', // T0
525
+ 'Observed', // T1
526
+ 'Provisional', // T2
527
+ 'Monitored', // T3
528
+ 'Standard', // T4
529
+ 'Trusted', // T5
530
+ 'Certified', // T6
531
+ 'Autonomous', // T7
532
+ ];
533
+ return names[this.getTierNumber()] ?? 'Unknown';
534
+ }
535
+
536
+ private getConstraintsForTier(): string[] {
537
+ const tier = this.getTierNumber();
538
+ if (tier <= 1) {
539
+ return ['rate_limit:10/min', 'audit:full', 'sandbox:true'];
540
+ }
541
+ if (tier <= 3) {
542
+ return ['rate_limit:100/min', 'audit:standard'];
543
+ }
544
+ if (tier <= 5) {
545
+ return ['rate_limit:1000/min', 'audit:light'];
546
+ }
547
+ return []; // T6-T7: minimal constraints
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Create a new Vorion SDK instance
553
+ */
554
+ export function createVorion(config?: VorionConfig): Vorion {
555
+ return new Vorion(config);
556
+ }
557
+
558
+ // Default export
559
+ export default Vorion;