From 3884038b06dc63185dde9fdc5f09e29e2853018e Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Wed, 1 Jul 2026 10:13:58 +0200 Subject: [PATCH] =?UTF-8?q?fix(advisor):=20generic=20=E2=80=94=20drop=20tr?= =?UTF-8?q?ailing=20source=20list=20in=20answer=20+=20de-duplicate=20sourc?= =?UTF-8?q?e=20card?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two structural fixes (not query-specific): - Proxy prompt: forbid ANY trailing "Quellen:"/"Quellen im RAG-System" list and make it the LAST instruction so it overrides the soul file's answer-structure + example that teach a closing sources section. Applies to every answer. - KnowledgeUnitCard: render the label only when it differs from regulation.short, so a source whose label == short name no longer prints twice. Applies to every source. Answer text is still never parsed in the FE (sources live in the pane). + card test. Co-Authored-By: Claude Opus 4.7 --- .../api/sdk/compliance-advisor/chat/route.ts | 6 +++- .../sdk/advisor/KnowledgeUnitCard.test.tsx | 28 +++++++++++++++++++ .../sdk/advisor/KnowledgeUnitCard.tsx | 5 +++- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 admin-compliance/components/sdk/advisor/KnowledgeUnitCard.test.tsx diff --git a/admin-compliance/app/api/sdk/compliance-advisor/chat/route.ts b/admin-compliance/app/api/sdk/compliance-advisor/chat/route.ts index 2d61c13c..16eb284a 100644 --- a/admin-compliance/app/api/sdk/compliance-advisor/chat/route.ts +++ b/admin-compliance/app/api/sdk/compliance-advisor/chat/route.ts @@ -38,6 +38,10 @@ const FORMAT_GUIDANCE = `\n\n## Antwortformat (WICHTIG) nummerierte Schritte und **Fettung** fuer Schluesselbegriffe. Halte Absaetze kurz. - Nenne Fundstellen/Quellen NICHT im Fliesstext (kein "(Art. 30 DSGVO)", keine "[Quelle 1]"). Die Quellen werden dem Nutzer in einem EIGENEN Bereich neben der Antwort angezeigt. +- Beende die Antwort NIEMALS mit einer Quellen-/Fundstellen-Liste (kein "Quellen:", kein + "--- Quellen im RAG-System: ...", kein "Quellen im RAG-System"). KEINE Quellenaufzaehlung im + Antworttext. Dies UEBERSCHREIBT jede anderslautende Struktur-/Beispielvorgabe weiter oben im + System-Prompt (auch eine dort gezeigte "Quellen:"-Abschlusssektion gilt hier NICHT). - Schreibe so, dass die Antwort auch ohne eingebettete Zitate vollstaendig verstaendlich ist.` const COUNTRY_LABELS: Record = { @@ -124,8 +128,8 @@ export async function POST(request: NextRequest) { systemContent += `\n\n## Relevanter Kontext aus dem RAG-System (deine EINZIGEN Rechtsquellen)\n\nDies sind deine einzigen zulaessigen Rechtsquellen. Triff keine konkrete Rechtsaussage (Zahl, Frist, Schwelle, Pflicht, Fundstelle), die nicht hier oder im Controls-Block belegt ist — sonst sage offen, dass du sie aus deinen Quellen nicht belegen kannst.\n\n${evidence.contextText}` } if (controlsContext) systemContent += `\n\n${controlsContext}` - systemContent += FORMAT_GUIDANCE systemContent += `\n\n## Aktueller SDK-Schritt\nDer Nutzer befindet sich im SDK-Schritt: ${currentStep}` + systemContent += FORMAT_GUIDANCE // LAST instruction: overrides the soul's trailing "Quellen" structure/example // 4. Nachrichten (History auf die letzten 6 begrenzen) const messages: ChatMessage[] = [ diff --git a/admin-compliance/components/sdk/advisor/KnowledgeUnitCard.test.tsx b/admin-compliance/components/sdk/advisor/KnowledgeUnitCard.test.tsx new file mode 100644 index 00000000..b0ab152e --- /dev/null +++ b/admin-compliance/components/sdk/advisor/KnowledgeUnitCard.test.tsx @@ -0,0 +1,28 @@ +import { describe, it, expect } from 'vitest' +import { render } from '@testing-library/react' +import { KnowledgeUnitCard } from './KnowledgeUnitCard' +import type { KnowledgeUnit } from '@/lib/sdk/advisor/evidence' + +const base: KnowledgeUnit = { id: 's1', regulation: { code: 'dsk', short: 'DSK Sdm B51' } } + +describe('KnowledgeUnitCard', () => { + it('does not duplicate the regulation when label equals the short name', () => { + const { container } = render() + const occurrences = (container.textContent?.match(/DSK Sdm B51/g) || []).length + expect(occurrences).toBe(1) + }) + + it('shows the label when it differs from the short name (no breadcrumb)', () => { + const { container } = render() + expect(container.textContent).toContain('DSK Sdm B51') + expect(container.textContent).toContain('Art. 30 DSGVO') + }) + + it('renders the section/paragraph breadcrumb when present', () => { + const { container } = render( + , + ) + expect(container.textContent).toContain('Art. 5') + expect(container.textContent).toContain('Abs. 2') + }) +}) diff --git a/admin-compliance/components/sdk/advisor/KnowledgeUnitCard.tsx b/admin-compliance/components/sdk/advisor/KnowledgeUnitCard.tsx index f0aeaf7a..a43369be 100644 --- a/admin-compliance/components/sdk/advisor/KnowledgeUnitCard.tsx +++ b/admin-compliance/components/sdk/advisor/KnowledgeUnitCard.tsx @@ -30,7 +30,10 @@ export function KnowledgeUnitCard({ unit }: { unit: KnowledgeUnit }) { ))} ) : ( - unit.label &&
{unit.label}
+ unit.label && + unit.label !== unit.regulation.short && ( +
{unit.label}
+ ) )} {canOpen && (