Files
breakpilot-compliance/admin-compliance/components/sdk/advisor/ClarifyView.tsx
T
Benjamin Admin f9b7ba2424 feat(advisor): v3 Clarity Gate — Case model + clarify/answer contract, [n] citations
Builds the FE against the SDK<->FE Clarity-Gate contract (board 2026-07-01 /
advisor-clarity-gate-contract). The advisor is now a CASE, not a chat:
- Request {question, context?}; response {mode: clarify|answer, clarity, general_answer,
  answer, evidence, citations, visual_evidence, footnotes}.
- clarify mode: short L1 general answer (marked "allgemeine Definition, ohne Rechtsquelle")
  + domain context chips; picking a chip re-runs the case scoped (-> answer).
- answer mode: markdown answer with clickable [n] citation markers coupled to evidence
  cards (highlight + scroll), evidence grouped by document family, visual_evidence
  (visual_type), footnotes, honest summary counts (no trust score).
- FE never parses the answer for structure — only the deliberate [n] markers, mapped via
  citations[]. New: contract.ts, useAdvisorCase, useCitationHighlight, ClarifyView,
  EvidenceUnitCard, VisualEvidencePane, CaseView. Removed the v2 stream/chat components.

NOT deployed: FE shape-switch (JSON modes) must deploy TOGETHER with the SDK endpoint
delivering the contract (board deploy-coupling). Proxy/route.ts unchanged (SDK-owned).
tsc clean, 16 vitest (incl. clarify+answer fixtures), check-loc 0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-01 11:31:28 +02:00

53 lines
1.7 KiB
TypeScript

'use client'
import { Info } from 'lucide-react'
import type { AdvisorResponse } from '@/lib/sdk/advisor/contract'
import { Markdown } from './Markdown'
/**
* Clarify mode: a short general (L1) definition — explicitly marked as general, no legal source —
* plus domain context chips. Picking a chip re-runs the case scoped to that domain (-> L2).
*/
export function ClarifyView({
response,
onSelectContext,
busy,
}: {
response: AdvisorResponse
onSelectContext: (id: string) => void
busy: boolean
}) {
const chips = response.clarity.suggested_contexts ?? []
return (
<div className="space-y-3">
<div className="rounded-lg border border-amber-200 bg-amber-50 px-3 py-2">
<div className="mb-1 flex items-center gap-1 text-[11px] font-semibold text-amber-700">
<Info className="h-3.5 w-3.5" />
Allgemeine Definition (ohne Rechtsquelle)
</div>
<Markdown content={response.general_answer || ''} />
</div>
{chips.length > 0 && (
<div>
<div className="mb-1.5 text-xs font-medium text-gray-700">
Meintest du einen bestimmten Kontext?
</div>
<div className="flex flex-wrap gap-1.5">
{chips.map((c) => (
<button
key={c.id}
type="button"
disabled={busy}
onClick={() => onSelectContext(c.id)}
className="rounded-full border border-indigo-200 bg-white px-3 py-1 text-xs font-medium text-indigo-700 transition-colors hover:bg-indigo-50 disabled:opacity-50"
>
{c.label}
</button>
))}
</div>
</div>
)}
</div>
)
}