@euconform/core 1.0.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.
Files changed (89) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/LICENSE +21 -0
  3. package/dist/fairness-metrics.d.ts +65 -0
  4. package/dist/fairness-metrics.d.ts.map +1 -0
  5. package/dist/fairness-metrics.js +394 -0
  6. package/dist/index.d.ts +14 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +17 -0
  9. package/dist/inference/browser-inference.d.ts +60 -0
  10. package/dist/inference/browser-inference.d.ts.map +1 -0
  11. package/dist/inference/browser-inference.js +221 -0
  12. package/dist/inference/capability-detection.d.ts +183 -0
  13. package/dist/inference/capability-detection.d.ts.map +1 -0
  14. package/dist/inference/capability-detection.js +552 -0
  15. package/dist/inference/index.d.ts +43 -0
  16. package/dist/inference/index.d.ts.map +1 -0
  17. package/dist/inference/index.js +97 -0
  18. package/dist/inference/inference-factory.d.ts +73 -0
  19. package/dist/inference/inference-factory.d.ts.map +1 -0
  20. package/dist/inference/inference-factory.js +175 -0
  21. package/dist/inference/ollama-client.d.ts +114 -0
  22. package/dist/inference/ollama-client.d.ts.map +1 -0
  23. package/dist/inference/ollama-client.js +386 -0
  24. package/dist/legal-checks/annex-iv-report.d.ts +131 -0
  25. package/dist/legal-checks/annex-iv-report.d.ts.map +1 -0
  26. package/dist/legal-checks/annex-iv-report.js +62 -0
  27. package/dist/legal-checks/bias-metrics.d.ts +162 -0
  28. package/dist/legal-checks/bias-metrics.d.ts.map +1 -0
  29. package/dist/legal-checks/bias-metrics.js +408 -0
  30. package/dist/legal-checks/data-governance.d.ts +30 -0
  31. package/dist/legal-checks/data-governance.d.ts.map +1 -0
  32. package/dist/legal-checks/data-governance.js +99 -0
  33. package/dist/legal-checks/human-oversight-logging.d.ts +27 -0
  34. package/dist/legal-checks/human-oversight-logging.d.ts.map +1 -0
  35. package/dist/legal-checks/human-oversight-logging.js +106 -0
  36. package/dist/legal-checks/index.d.ts +13 -0
  37. package/dist/legal-checks/index.d.ts.map +1 -0
  38. package/dist/legal-checks/index.js +6 -0
  39. package/dist/legal-checks/risk-classifier.d.ts +35 -0
  40. package/dist/legal-checks/risk-classifier.d.ts.map +1 -0
  41. package/dist/legal-checks/risk-classifier.js +234 -0
  42. package/dist/legal-checks/robustness-transparency.d.ts +45 -0
  43. package/dist/legal-checks/robustness-transparency.d.ts.map +1 -0
  44. package/dist/legal-checks/robustness-transparency.js +111 -0
  45. package/dist/metrics/crows-pairs-bias.d.ts +41 -0
  46. package/dist/metrics/crows-pairs-bias.d.ts.map +1 -0
  47. package/dist/metrics/crows-pairs-bias.js +172 -0
  48. package/dist/metrics/index.d.ts +6 -0
  49. package/dist/metrics/index.d.ts.map +1 -0
  50. package/dist/metrics/index.js +5 -0
  51. package/dist/metrics/stereotype-bias.d.ts +89 -0
  52. package/dist/metrics/stereotype-bias.d.ts.map +1 -0
  53. package/dist/metrics/stereotype-bias.js +157 -0
  54. package/dist/risk-engine.d.ts +23 -0
  55. package/dist/risk-engine.d.ts.map +1 -0
  56. package/dist/risk-engine.js +451 -0
  57. package/dist/types.d.ts +131 -0
  58. package/dist/types.d.ts.map +1 -0
  59. package/dist/types.js +5 -0
  60. package/package.json +28 -0
  61. package/src/fairness-metrics.ts +498 -0
  62. package/src/index.ts +150 -0
  63. package/src/inference/browser-inference.ts +258 -0
  64. package/src/inference/capability-detection.ts +714 -0
  65. package/src/inference/index.ts +156 -0
  66. package/src/inference/inference-factory.ts +222 -0
  67. package/src/inference/ollama-client.ts +514 -0
  68. package/src/inference/transformers.d.ts +62 -0
  69. package/src/legal-checks/annex-iv-report.ts +157 -0
  70. package/src/legal-checks/bias-metrics.ts +590 -0
  71. package/src/legal-checks/data-governance.ts +148 -0
  72. package/src/legal-checks/human-oversight-logging.ts +135 -0
  73. package/src/legal-checks/index.ts +55 -0
  74. package/src/legal-checks/risk-classifier.ts +285 -0
  75. package/src/legal-checks/robustness-transparency.ts +162 -0
  76. package/src/metrics/crows-pairs-bias.ts +245 -0
  77. package/src/metrics/index.ts +22 -0
  78. package/src/metrics/stereotype-bias.ts +267 -0
  79. package/src/risk-engine.ts +525 -0
  80. package/src/types.ts +154 -0
  81. package/tests/annex-iv-report.test.ts +323 -0
  82. package/tests/crows-pairs-bias.test.ts +342 -0
  83. package/tests/fairness-metrics.test.ts +187 -0
  84. package/tests/integration/bias-calculation.integration.test.ts +688 -0
  85. package/tests/legal-checks.test.ts +53 -0
  86. package/tests/ollama-client.test.ts +427 -0
  87. package/tests/risk-engine.test.ts +149 -0
  88. package/tsconfig.json +11 -0
  89. package/vitest.config.ts +17 -0
@@ -0,0 +1,525 @@
1
+ /**
2
+ * EU AI Act Risk Engine
3
+ * Implements risk classification according to Article 6 + Annex III
4
+ */
5
+
6
+ import type { HighRiskCategory, QuizAnswer, QuizQuestion, RiskAssessment, RiskFlag } from "./types";
7
+
8
+ /** Risk classification questions based on EU AI Act criteria */
9
+ export const RISK_QUIZ_QUESTIONS_EN: QuizQuestion[] = [
10
+ {
11
+ id: "purpose",
12
+ question: "What is the primary purpose of your AI system?",
13
+ description: "Select the category that best describes your system's main function",
14
+ options: [
15
+ {
16
+ value: "biometric",
17
+ label: "Biometric identification/categorization",
18
+ riskIndicator: "high",
19
+ },
20
+ {
21
+ value: "critical-infra",
22
+ label: "Critical infrastructure management",
23
+ riskIndicator: "high",
24
+ },
25
+ { value: "education", label: "Education or vocational training", riskIndicator: "high" },
26
+ {
27
+ value: "employment",
28
+ label: "Employment, worker management, recruitment",
29
+ riskIndicator: "high",
30
+ },
31
+ {
32
+ value: "essential-services",
33
+ label: "Access to essential services (credit, insurance)",
34
+ riskIndicator: "high",
35
+ },
36
+ { value: "law-enforcement", label: "Law enforcement", riskIndicator: "high" },
37
+ { value: "migration", label: "Migration, asylum, border control", riskIndicator: "high" },
38
+ { value: "justice", label: "Administration of justice", riskIndicator: "high" },
39
+ { value: "chatbot", label: "Chatbot or conversational AI", riskIndicator: "limited" },
40
+ {
41
+ value: "content-generation",
42
+ label: "Content generation (text, images)",
43
+ riskIndicator: "limited",
44
+ },
45
+ { value: "other", label: "Other / General purpose", riskIndicator: "minimal" },
46
+ ],
47
+ },
48
+ {
49
+ id: "subliminal",
50
+ question: "Does your system use subliminal techniques to manipulate behavior?",
51
+ description: "Techniques beyond a person's consciousness that could cause harm",
52
+ options: [
53
+ { value: "yes", label: "Yes", riskIndicator: "unacceptable" },
54
+ { value: "no", label: "No", riskIndicator: "minimal" },
55
+ { value: "unsure", label: "Not sure", riskIndicator: "limited" },
56
+ ],
57
+ },
58
+ {
59
+ id: "vulnerability",
60
+ question: "Does your system target vulnerable groups in ways that could exploit them?",
61
+ description: "Children, elderly, disabled, or economically/socially disadvantaged groups",
62
+ options: [
63
+ { value: "yes", label: "Yes, it targets vulnerable groups", riskIndicator: "unacceptable" },
64
+ {
65
+ value: "no",
66
+ label: "No, it does not specifically target vulnerable groups",
67
+ riskIndicator: "minimal",
68
+ },
69
+ {
70
+ value: "includes",
71
+ label: "It may include but doesn't specifically target them",
72
+ riskIndicator: "limited",
73
+ },
74
+ ],
75
+ },
76
+ {
77
+ id: "social-scoring",
78
+ question: "Does your system perform social scoring?",
79
+ description:
80
+ "Evaluating trustworthiness based on social behavior by public authorities leading to detrimental treatment",
81
+ options: [
82
+ { value: "yes", label: "Yes, by public authorities", riskIndicator: "unacceptable" },
83
+ { value: "no", label: "No", riskIndicator: "minimal" },
84
+ {
85
+ value: "partial",
86
+ label: "It scores behavior but not for social purposes by public authorities",
87
+ riskIndicator: "limited",
88
+ },
89
+ ],
90
+ },
91
+ {
92
+ id: "biometric-realtime",
93
+ question: "Does your system use real-time remote biometric identification in public spaces?",
94
+ description: "For law enforcement purposes without judicial authorization",
95
+ options: [
96
+ { value: "yes", label: "Yes", riskIndicator: "unacceptable" },
97
+ { value: "no", label: "No", riskIndicator: "minimal" },
98
+ {
99
+ value: "authorized",
100
+ label: "Yes, but with proper judicial authorization",
101
+ riskIndicator: "high",
102
+ },
103
+ ],
104
+ },
105
+ {
106
+ id: "human-oversight",
107
+ question: "What level of human oversight exists for your AI system's decisions?",
108
+ description: "Consider who reviews and can override AI decisions",
109
+ options: [
110
+ { value: "none", label: "Fully autonomous, no human oversight", riskIndicator: "high" },
111
+ {
112
+ value: "limited",
113
+ label: "Human review possible but not required",
114
+ riskIndicator: "limited",
115
+ },
116
+ {
117
+ value: "full",
118
+ label: "Human oversight and approval required for decisions",
119
+ riskIndicator: "minimal",
120
+ },
121
+ ],
122
+ },
123
+ ];
124
+
125
+ export const RISK_QUIZ_QUESTIONS_DE: QuizQuestion[] = [
126
+ {
127
+ id: "purpose",
128
+ question: "Was ist der Hauptzweck Ihres KI-Systems?",
129
+ description:
130
+ "Wählen Sie die Kategorie, die die Hauptfunktion Ihres Systems am besten beschreibt",
131
+ options: [
132
+ {
133
+ value: "biometric",
134
+ label: "Biometrische Identifizierung/Kategorisierung",
135
+ riskIndicator: "high",
136
+ },
137
+ {
138
+ value: "critical-infra",
139
+ label: "Management kritischer Infrastrukturen",
140
+ riskIndicator: "high",
141
+ },
142
+ { value: "education", label: "Allgemeine und berufliche Bildung", riskIndicator: "high" },
143
+ {
144
+ value: "employment",
145
+ label: "Beschäftigung, Personalmanagement, Rekrutierung",
146
+ riskIndicator: "high",
147
+ },
148
+ {
149
+ value: "essential-services",
150
+ label: "Zugang zu wesentlichen Dienstleistungen (Kredit, Versicherung)",
151
+ riskIndicator: "high",
152
+ },
153
+ { value: "law-enforcement", label: "Strafverfolgung", riskIndicator: "high" },
154
+ { value: "migration", label: "Migration, Asyl, Grenzkontrolle", riskIndicator: "high" },
155
+ { value: "justice", label: "Justizverwaltung", riskIndicator: "high" },
156
+ { value: "chatbot", label: "Chatbot oder konversationelle KI", riskIndicator: "limited" },
157
+ {
158
+ value: "content-generation",
159
+ label: "Inhaltsgenerierung (Text, Bilder)",
160
+ riskIndicator: "limited",
161
+ },
162
+ { value: "other", label: "Andere / Allzweck", riskIndicator: "minimal" },
163
+ ],
164
+ },
165
+ {
166
+ id: "subliminal",
167
+ question: "Verwendet Ihr System unterschwellige Techniken, um Verhalten zu manipulieren?",
168
+ description:
169
+ "Techniken jenseits des menschlichen Bewusstseins, die Schaden verursachen könnten",
170
+ options: [
171
+ { value: "yes", label: "Ja", riskIndicator: "unacceptable" },
172
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
173
+ { value: "unsure", label: "Nicht sicher", riskIndicator: "limited" },
174
+ ],
175
+ },
176
+ {
177
+ id: "vulnerability",
178
+ question:
179
+ "Zielt Ihr System auf schutzbedürftige Gruppen in einer Weise ab, die sie ausnutzen könnte?",
180
+ description:
181
+ "Kinder, ältere Menschen, Behinderte oder wirtschaftlich/sozial benachteiligte Gruppen",
182
+ options: [
183
+ {
184
+ value: "yes",
185
+ label: "Ja, es zielt auf schutzbedürftige Gruppen ab",
186
+ riskIndicator: "unacceptable",
187
+ },
188
+ {
189
+ value: "no",
190
+ label: "Nein, es zielt nicht speziell auf schutzbedürftige Gruppen ab",
191
+ riskIndicator: "minimal",
192
+ },
193
+ {
194
+ value: "includes",
195
+ label: "Es kann sie einschließen, zielt aber nicht speziell auf sie ab",
196
+ riskIndicator: "limited",
197
+ },
198
+ ],
199
+ },
200
+ {
201
+ id: "social-scoring",
202
+ question: "Führt Ihr System Social Scoring durch?",
203
+ description:
204
+ "Bewertung der Vertrauenswürdigkeit aufgrund sozialen Verhaltens durch öffentliche Behörden, das zu nachteiliger Behandlung führt",
205
+ options: [
206
+ { value: "yes", label: "Ja, durch öffentliche Behörden", riskIndicator: "unacceptable" },
207
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
208
+ {
209
+ value: "partial",
210
+ label: "Es bewertet Verhalten, aber nicht für soziale Zwecke durch öffentliche Behörden",
211
+ riskIndicator: "limited",
212
+ },
213
+ ],
214
+ },
215
+ {
216
+ id: "biometric-realtime",
217
+ question:
218
+ "Verwendet Ihr System biometrische Fernidentifizierung in Echtzeit im öffentlichen Raum?",
219
+ description: "Für Strafverfolgungszwecke ohne richterliche Genehmigung",
220
+ options: [
221
+ { value: "yes", label: "Ja", riskIndicator: "unacceptable" },
222
+ { value: "no", label: "Nein", riskIndicator: "minimal" },
223
+ {
224
+ value: "authorized",
225
+ label: "Ja, aber mit ordnungsgemäßer richterlicher Genehmigung",
226
+ riskIndicator: "high",
227
+ },
228
+ ],
229
+ },
230
+ {
231
+ id: "human-oversight",
232
+ question:
233
+ "Welches Maß an menschlicher Aufsicht gibt es für die Entscheidungen Ihres KI-Systems?",
234
+ description: "Berücksichtigen Sie, wer die KI-Entscheidungen überprüft und aufheben kann",
235
+ options: [
236
+ {
237
+ value: "none",
238
+ label: "Vollständig autonom, keine menschliche Aufsicht",
239
+ riskIndicator: "high",
240
+ },
241
+ {
242
+ value: "limited",
243
+ label: "Menschliche Überprüfung möglich, aber nicht erforderlich",
244
+ riskIndicator: "limited",
245
+ },
246
+ {
247
+ value: "full",
248
+ label: "Menschliche Aufsicht und Genehmigung für Entscheidungen erforderlich",
249
+ riskIndicator: "minimal",
250
+ },
251
+ ],
252
+ },
253
+ ];
254
+
255
+ export const RISK_QUIZ_QUESTIONS = RISK_QUIZ_QUESTIONS_DE;
256
+
257
+ /** Map purpose values to high-risk categories */
258
+ const PURPOSE_TO_CATEGORY: Record<string, HighRiskCategory> = {
259
+ biometric: "biometric-identification",
260
+ "critical-infra": "critical-infrastructure",
261
+ education: "education-training",
262
+ employment: "employment-workers",
263
+ "essential-services": "essential-services",
264
+ "law-enforcement": "law-enforcement",
265
+ migration: "migration-asylum",
266
+ justice: "justice-democracy",
267
+ };
268
+
269
+ /**
270
+ * Classify AI system risk level based on quiz answers
271
+ * Implements EU AI Act Article 5 (prohibited) and Article 6 + Annex III (high-risk)
272
+ */
273
+ export function classifyRisk(answers: QuizAnswer[]): RiskAssessment {
274
+ const flags: RiskFlag[] = [];
275
+ const recommendations: string[] = [];
276
+ const legalBasis: string[] = [];
277
+
278
+ // Check for unacceptable (prohibited) practices - Article 5
279
+ const prohibitedPractices = checkProhibitedPractices(answers);
280
+ if (prohibitedPractices.length > 0) {
281
+ return {
282
+ level: "unacceptable",
283
+ score: 100,
284
+ flags: prohibitedPractices,
285
+ recommendations: [
286
+ "This AI system appears to fall under prohibited practices (Article 5)",
287
+ "Deploy this system is not permitted under the EU AI Act",
288
+ "Consult legal counsel immediately",
289
+ ],
290
+ legalBasis: ["Article 5 - Prohibited AI Practices"],
291
+ };
292
+ }
293
+
294
+ // Check for high-risk systems - Article 6 + Annex III
295
+ const purposeAnswer = answers.find((a) => a.questionId === "purpose");
296
+ const category = purposeAnswer?.value ? PURPOSE_TO_CATEGORY[purposeAnswer.value] : undefined;
297
+
298
+ if (category) {
299
+ flags.push({
300
+ type: "warning",
301
+ message: `System falls under high-risk category: ${formatCategory(category)}`,
302
+ articleReference: "Annex III",
303
+ });
304
+ legalBasis.push(
305
+ "Article 6 - Classification of High-Risk AI Systems",
306
+ "Annex III - High-Risk Categories"
307
+ );
308
+ recommendations.push(
309
+ "Implement conformity assessment procedures",
310
+ "Establish risk management system",
311
+ "Ensure data governance and documentation",
312
+ "Enable human oversight mechanisms",
313
+ "Maintain technical documentation per Annex IV"
314
+ );
315
+
316
+ const humanOversight = answers.find((a) => a.questionId === "human-oversight");
317
+ if (humanOversight?.value === "none") {
318
+ flags.push({
319
+ type: "warning",
320
+ message: "High-risk systems require meaningful human oversight (Article 14)",
321
+ articleReference: "Article 14",
322
+ });
323
+ recommendations.push(
324
+ "Implement meaningful human oversight measures as required for high-risk systems"
325
+ );
326
+ }
327
+
328
+ return {
329
+ level: "high",
330
+ category,
331
+ score: calculateRiskScore(answers),
332
+ flags,
333
+ recommendations,
334
+ legalBasis,
335
+ };
336
+ }
337
+
338
+ // Check for limited-risk systems (transparency obligations)
339
+ const limitedRiskIndicators = ["chatbot", "content-generation"];
340
+ if (purposeAnswer?.value && limitedRiskIndicators.includes(purposeAnswer.value)) {
341
+ flags.push({
342
+ type: "info",
343
+ message: "System requires transparency obligations",
344
+ articleReference: "Article 50",
345
+ });
346
+ legalBasis.push("Article 50 - Transparency Obligations");
347
+ recommendations.push(
348
+ "Clearly inform users they are interacting with an AI system",
349
+ "Label AI-generated content appropriately",
350
+ "Document the AI nature of outputs"
351
+ );
352
+
353
+ return {
354
+ level: "limited",
355
+ score: calculateRiskScore(answers),
356
+ flags,
357
+ recommendations,
358
+ legalBasis,
359
+ };
360
+ }
361
+
362
+ // Minimal risk - no specific obligations
363
+ return {
364
+ level: "minimal",
365
+ score: calculateRiskScore(answers),
366
+ flags: [
367
+ {
368
+ type: "info",
369
+ message: "System classified as minimal risk - voluntary codes of conduct apply",
370
+ },
371
+ ],
372
+ recommendations: [
373
+ "Consider adopting voluntary codes of conduct",
374
+ "Monitor for regulatory updates",
375
+ "Maintain good AI practices",
376
+ ],
377
+ legalBasis: ["No mandatory requirements - minimal risk system"],
378
+ };
379
+ }
380
+
381
+ /**
382
+ * Check for prohibited AI practices under Article 5
383
+ */
384
+ function checkProhibitedPractices(answers: QuizAnswer[]): RiskFlag[] {
385
+ const flags: RiskFlag[] = [];
386
+
387
+ const subliminal = answers.find((a) => a.questionId === "subliminal");
388
+ if (subliminal?.value === "yes") {
389
+ flags.push({
390
+ type: "critical",
391
+ message: "PROHIBITED: Use of subliminal techniques to manipulate behavior",
392
+ articleReference: "Article 5(1)(a)",
393
+ });
394
+ }
395
+
396
+ const vulnerability = answers.find((a) => a.questionId === "vulnerability");
397
+ if (vulnerability?.value === "yes") {
398
+ flags.push({
399
+ type: "critical",
400
+ message: "PROHIBITED: Exploitation of vulnerabilities of specific groups",
401
+ articleReference: "Article 5(1)(b)",
402
+ });
403
+ }
404
+
405
+ const socialScoring = answers.find((a) => a.questionId === "social-scoring");
406
+ if (socialScoring?.value === "yes") {
407
+ flags.push({
408
+ type: "critical",
409
+ message: "PROHIBITED: Social scoring by public authorities leading to detrimental treatment",
410
+ articleReference: "Article 5(1)(c)",
411
+ });
412
+ }
413
+
414
+ const biometricRealtime = answers.find((a) => a.questionId === "biometric-realtime");
415
+ if (biometricRealtime?.value === "yes") {
416
+ flags.push({
417
+ type: "critical",
418
+ message:
419
+ "PROHIBITED: Real-time remote biometric identification in public spaces without judicial authorization",
420
+ articleReference: "Article 5(1)(d)",
421
+ });
422
+ }
423
+
424
+ return flags;
425
+ }
426
+
427
+ /**
428
+ * Calculate risk score (0-100) based on answer patterns
429
+ */
430
+ function calculateRiskScore(answers: QuizAnswer[]): number {
431
+ let score = 0;
432
+ const questions = RISK_QUIZ_QUESTIONS;
433
+
434
+ for (const answer of answers) {
435
+ const question = questions.find((q) => q.id === answer.questionId);
436
+ const option = question?.options.find((o) => o.value === answer.value);
437
+
438
+ if (option?.riskIndicator) {
439
+ switch (option.riskIndicator) {
440
+ case "unacceptable":
441
+ score += 30;
442
+ break;
443
+ case "high":
444
+ score += 20;
445
+ break;
446
+ case "limited":
447
+ score += 10;
448
+ break;
449
+ case "minimal":
450
+ score += 0;
451
+ break;
452
+ }
453
+ }
454
+ }
455
+
456
+ return Math.min(100, score);
457
+ }
458
+
459
+ /**
460
+ * Format high-risk category for display
461
+ */
462
+ function formatCategory(category: HighRiskCategory): string {
463
+ const labels: Record<HighRiskCategory, string> = {
464
+ "biometric-identification": "Biometric Identification & Categorization",
465
+ "critical-infrastructure": "Critical Infrastructure",
466
+ "education-training": "Education & Vocational Training",
467
+ "employment-workers": "Employment & Worker Management",
468
+ "essential-services": "Essential Private/Public Services",
469
+ "law-enforcement": "Law Enforcement",
470
+ "migration-asylum": "Migration, Asylum & Border Control",
471
+ "justice-democracy": "Administration of Justice & Democracy",
472
+ };
473
+ return labels[category] || category;
474
+ }
475
+
476
+ /**
477
+ * Get all quiz questions for the risk assessment
478
+ */
479
+ export function getQuizQuestions(): QuizQuestion[] {
480
+ return RISK_QUIZ_QUESTIONS;
481
+ }
482
+
483
+ /**
484
+ * Get detailed recommendations based on risk level
485
+ */
486
+ export function getComplianceGuidance(assessment: RiskAssessment): string[] {
487
+ const guidance: string[] = [];
488
+
489
+ switch (assessment.level) {
490
+ case "unacceptable":
491
+ guidance.push(
492
+ "⛔ This system is PROHIBITED under EU AI Act Article 5",
493
+ "Do not deploy or make available in the EU market",
494
+ "Consult legal counsel for alternatives"
495
+ );
496
+ break;
497
+ case "high":
498
+ guidance.push(
499
+ "📋 Register in EU database before market placement",
500
+ "🔍 Conduct conformity assessment",
501
+ "📝 Prepare technical documentation (Annex IV)",
502
+ "⚠️ Implement risk management system",
503
+ "🧪 Test for accuracy, robustness, cybersecurity",
504
+ "👤 Enable human oversight measures",
505
+ "📊 Maintain logs for at least 6 months"
506
+ );
507
+ break;
508
+ case "limited":
509
+ guidance.push(
510
+ "💬 Inform users about AI interaction",
511
+ "🏷️ Label AI-generated content",
512
+ "📚 Consider voluntary codes of conduct"
513
+ );
514
+ break;
515
+ case "minimal":
516
+ guidance.push(
517
+ "✅ No mandatory requirements",
518
+ "📖 Voluntary codes of conduct encouraged",
519
+ "🔄 Monitor regulatory updates"
520
+ );
521
+ break;
522
+ }
523
+
524
+ return guidance;
525
+ }
package/src/types.ts ADDED
@@ -0,0 +1,154 @@
1
+ /**
2
+ * EU AI Act Type Definitions
3
+ * Based on Regulation (EU) 2024/1689
4
+ */
5
+
6
+ /** Risk classification levels according to EU AI Act Article 6 + Annex III */
7
+ export type RiskLevel = "unacceptable" | "high" | "limited" | "minimal";
8
+
9
+ /** Categories of high-risk AI systems from Annex III */
10
+ export type HighRiskCategory =
11
+ | "biometric-identification"
12
+ | "critical-infrastructure"
13
+ | "education-training"
14
+ | "employment-workers"
15
+ | "essential-services"
16
+ | "law-enforcement"
17
+ | "migration-asylum"
18
+ | "justice-democracy";
19
+
20
+ /** Quiz question for risk assessment */
21
+ export interface QuizQuestion {
22
+ id: string;
23
+ question: string;
24
+ description?: string;
25
+ options: QuizOption[];
26
+ }
27
+
28
+ export interface QuizOption {
29
+ value: string;
30
+ label: string;
31
+ riskIndicator?: RiskLevel;
32
+ }
33
+
34
+ /** User's answer to a quiz question */
35
+ export interface QuizAnswer {
36
+ questionId: string;
37
+ value: string;
38
+ }
39
+
40
+ /** Result of risk classification */
41
+ export interface RiskAssessment {
42
+ level: RiskLevel;
43
+ category?: HighRiskCategory;
44
+ score: number;
45
+ flags: RiskFlag[];
46
+ recommendations: string[];
47
+ legalBasis: string[];
48
+ }
49
+
50
+ export interface RiskFlag {
51
+ type: "warning" | "critical" | "info";
52
+ message: string;
53
+ articleReference?: string;
54
+ }
55
+
56
+ /** Fairness metrics types */
57
+ export interface FairnessMetric {
58
+ name: string;
59
+ value: number;
60
+ threshold: number;
61
+ passed: boolean;
62
+ description: string;
63
+ }
64
+
65
+ export interface BiasTestResult {
66
+ modelId: string;
67
+ timestamp: string;
68
+ method: BiasCalculationMethod;
69
+ engine: "browser" | "ollama";
70
+ protectedAttribute?: string;
71
+ crowsPairsResult?: CrowsPairsBiasResult;
72
+ metrics?: FairnessMetric[];
73
+ overallPassed: boolean;
74
+ samplesAnalyzed: number;
75
+ }
76
+
77
+ /** Prediction data for fairness analysis */
78
+ export interface PredictionData {
79
+ prediction: number | boolean;
80
+ label?: number | boolean;
81
+ protectedGroup: string;
82
+ }
83
+
84
+ /** CrowS-Pairs dataset entry */
85
+ export interface CrowsPairsEntry {
86
+ id: number;
87
+ sent_more: string;
88
+ sent_less: string;
89
+ bias_type: string;
90
+ }
91
+
92
+ /** Bias calculation method types */
93
+ export type BiasCalculationMethod = "logprobs_exact" | "logprobs_fallback_latency";
94
+
95
+ /** Model capability cache for log-probability support */
96
+ export interface ModelCapabilityCache {
97
+ model: string;
98
+ supportsLogProbs: boolean;
99
+ testedAt: string;
100
+ ollamaVersion?: string;
101
+ }
102
+
103
+ /** CrowS-Pairs bias calculation result */
104
+ export interface CrowsPairsBiasResult {
105
+ score: number;
106
+ method: BiasCalculationMethod;
107
+ pairsAnalyzed: number;
108
+ stereotypicalPreference: number; // percentage
109
+ metadata: {
110
+ engine: "browser" | "ollama";
111
+ model: string;
112
+ timestamp: string;
113
+ };
114
+ }
115
+
116
+ /** Configuration for bias test execution */
117
+ export interface BiasTestConfig {
118
+ dataset: CrowsPairsEntry[];
119
+ model: string;
120
+ engine: "browser" | "ollama";
121
+ }
122
+
123
+ /** Annex IV Technical Documentation Report */
124
+ export interface AnnexIVReport {
125
+ version: string;
126
+ generatedAt: string;
127
+ provider: {
128
+ name: string;
129
+ address?: string;
130
+ contact?: string;
131
+ };
132
+ system: {
133
+ name: string;
134
+ intendedPurpose: string;
135
+ riskLevel: RiskLevel;
136
+ category?: HighRiskCategory;
137
+ };
138
+ technicalSpecs: {
139
+ architecture?: string;
140
+ trainingData?: string;
141
+ inputFormat?: string;
142
+ outputFormat?: string;
143
+ };
144
+ riskAssessment: RiskAssessment;
145
+ biasTests?: BiasTestResult[];
146
+ biasMethodology?: {
147
+ method: BiasCalculationMethod;
148
+ engine: "browser" | "ollama";
149
+ dataset: string;
150
+ citation: string;
151
+ description: string;
152
+ };
153
+ complianceStatus: "compliant" | "non-compliant" | "pending";
154
+ }