Extends the Compliance Advisor from a Q&A chatbot into a full drafting engine that can generate, validate, and refine compliance documents within Scope Engine constraints. Includes intent classifier, state projector, constraint enforcer, SOUL templates, Go backend endpoints, and React UI components. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
154 lines
5.7 KiB
TypeScript
154 lines
5.7 KiB
TypeScript
import { IntentClassifier } from '../intent-classifier'
|
|
|
|
describe('IntentClassifier', () => {
|
|
const classifier = new IntentClassifier()
|
|
|
|
describe('classify - Draft mode', () => {
|
|
it.each([
|
|
['Erstelle ein VVT fuer unseren Hauptprozess', 'draft'],
|
|
['Generiere eine TOM-Dokumentation', 'draft'],
|
|
['Schreibe eine Datenschutzerklaerung', 'draft'],
|
|
['Verfasse einen Entwurf fuer das Loeschkonzept', 'draft'],
|
|
['Create a DSFA document', 'draft'],
|
|
['Draft a privacy policy for us', 'draft'],
|
|
['Neues VVT anlegen', 'draft'],
|
|
])('"%s" should classify as %s', (input, expectedMode) => {
|
|
const result = classifier.classify(input)
|
|
expect(result.mode).toBe(expectedMode)
|
|
expect(result.confidence).toBeGreaterThan(0.7)
|
|
})
|
|
})
|
|
|
|
describe('classify - Validate mode', () => {
|
|
it.each([
|
|
['Pruefe die Konsistenz meiner Dokumente', 'validate'],
|
|
['Ist mein VVT korrekt?', 'validate'],
|
|
['Validiere die TOM gegen das VVT', 'validate'],
|
|
['Check die Vollstaendigkeit', 'validate'],
|
|
['Stimmt das mit der DSFA ueberein?', 'validate'],
|
|
['Cross-Check VVT und TOM', 'validate'],
|
|
])('"%s" should classify as %s', (input, expectedMode) => {
|
|
const result = classifier.classify(input)
|
|
expect(result.mode).toBe(expectedMode)
|
|
expect(result.confidence).toBeGreaterThan(0.7)
|
|
})
|
|
})
|
|
|
|
describe('classify - Ask mode', () => {
|
|
it.each([
|
|
['Was fehlt noch in meinem Profil?', 'ask'],
|
|
['Zeige mir die Luecken', 'ask'],
|
|
['Welche Dokumente fehlen noch?', 'ask'],
|
|
['Was ist der naechste Schritt?', 'ask'],
|
|
['Welche Informationen brauche ich noch?', 'ask'],
|
|
])('"%s" should classify as %s', (input, expectedMode) => {
|
|
const result = classifier.classify(input)
|
|
expect(result.mode).toBe(expectedMode)
|
|
expect(result.confidence).toBeGreaterThan(0.6)
|
|
})
|
|
})
|
|
|
|
describe('classify - Explain mode (fallback)', () => {
|
|
it.each([
|
|
['Was ist DSGVO?', 'explain'],
|
|
['Erklaere mir Art. 30', 'explain'],
|
|
['Hallo', 'explain'],
|
|
['Danke fuer die Hilfe', 'explain'],
|
|
])('"%s" should classify as %s (fallback)', (input, expectedMode) => {
|
|
const result = classifier.classify(input)
|
|
expect(result.mode).toBe(expectedMode)
|
|
})
|
|
})
|
|
|
|
describe('classify - confidence thresholds', () => {
|
|
it('should have high confidence for clear draft intents', () => {
|
|
const result = classifier.classify('Erstelle ein neues VVT')
|
|
expect(result.confidence).toBeGreaterThanOrEqual(0.85)
|
|
})
|
|
|
|
it('should have lower confidence for ambiguous inputs', () => {
|
|
const result = classifier.classify('Hallo')
|
|
expect(result.confidence).toBeLessThan(0.6)
|
|
})
|
|
|
|
it('should boost confidence with document type detection', () => {
|
|
const withDoc = classifier.classify('Erstelle VVT')
|
|
const withoutDoc = classifier.classify('Erstelle etwas')
|
|
expect(withDoc.confidence).toBeGreaterThanOrEqual(withoutDoc.confidence)
|
|
})
|
|
|
|
it('should boost confidence with multiple pattern matches', () => {
|
|
const single = classifier.classify('Erstelle Dokument')
|
|
const multi = classifier.classify('Erstelle und generiere ein neues Dokument')
|
|
expect(multi.confidence).toBeGreaterThanOrEqual(single.confidence)
|
|
})
|
|
})
|
|
|
|
describe('detectDocumentType', () => {
|
|
it.each([
|
|
['VVT erstellen', 'vvt'],
|
|
['Verarbeitungsverzeichnis', 'vvt'],
|
|
['Art. 30 Dokumentation', 'vvt'],
|
|
['TOM definieren', 'tom'],
|
|
['technisch organisatorische Massnahmen', 'tom'],
|
|
['Art. 32 Massnahmen', 'tom'],
|
|
['DSFA durchfuehren', 'dsfa'],
|
|
['Datenschutz-Folgenabschaetzung', 'dsfa'],
|
|
['Art. 35 Pruefung', 'dsfa'],
|
|
['DPIA erstellen', 'dsfa'],
|
|
['Datenschutzerklaerung', 'dsi'],
|
|
['Privacy Policy', 'dsi'],
|
|
['Art. 13 Information', 'dsi'],
|
|
['Loeschfristen definieren', 'lf'],
|
|
['Loeschkonzept erstellen', 'lf'],
|
|
['Retention Policy', 'lf'],
|
|
['Auftragsverarbeitung', 'av_vertrag'],
|
|
['AVV erstellen', 'av_vertrag'],
|
|
['Art. 28 Vertrag', 'av_vertrag'],
|
|
['Einwilligung einholen', 'einwilligung'],
|
|
['Consent Management', 'einwilligung'],
|
|
['Cookie Banner', 'einwilligung'],
|
|
])('"%s" should detect document type %s', (input, expectedType) => {
|
|
const result = classifier.detectDocumentType(input)
|
|
expect(result).toBe(expectedType)
|
|
})
|
|
|
|
it('should return undefined for unrecognized types', () => {
|
|
expect(classifier.detectDocumentType('Hallo Welt')).toBeUndefined()
|
|
expect(classifier.detectDocumentType('Was kostet das?')).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('classify - Umlaut handling', () => {
|
|
it('should handle German umlauts correctly', () => {
|
|
// With actual umlauts (ä, ö, ü)
|
|
const result1 = classifier.classify('Prüfe die Vollständigkeit')
|
|
expect(result1.mode).toBe('validate')
|
|
|
|
// With ae/oe/ue substitution
|
|
const result2 = classifier.classify('Pruefe die Vollstaendigkeit')
|
|
expect(result2.mode).toBe('validate')
|
|
})
|
|
|
|
it('should handle ß correctly', () => {
|
|
const result = classifier.classify('Schließe Lücken')
|
|
// Should still detect via normalized patterns
|
|
expect(result).toBeDefined()
|
|
})
|
|
})
|
|
|
|
describe('classify - combined mode + document type', () => {
|
|
it('should detect both mode and document type', () => {
|
|
const result = classifier.classify('Erstelle ein VVT fuer unsere Firma')
|
|
expect(result.mode).toBe('draft')
|
|
expect(result.detectedDocumentType).toBe('vvt')
|
|
})
|
|
|
|
it('should detect validate + document type', () => {
|
|
const result = classifier.classify('Pruefe mein TOM auf Konsistenz')
|
|
expect(result.mode).toBe('validate')
|
|
expect(result.detectedDocumentType).toBe('tom')
|
|
})
|
|
})
|
|
})
|