Files
Khalid Abdi fa2e499440 feat: live AI chat (thinking + inline Veil) and display/add actions
Make the chat feel alive and let the agent act on the clinic — safely.

UX (frontend):
- Stream `data-step` parts from each tool into an inline Chain-of-Thought
  trace, plus a "Thinking…" shimmer while a request is in flight (works even
  on the non-streamed external+Veil path).
- Replace the modal Veil consent Dialog with an inline, once-per-session
  "Veil" confirmation above the input (with a "Use local model" option).
- Render new list + action-preview cards; chat-input now uses COSS tokens.

Agent (backend):
- Add display tools (listAppointments / listTasks / listPrescriptions) and
  propose tools (proposeAppointment / proposeTask / proposePrescription) that
  validate as a dry run and stream an approval card — nothing is written until
  the clinician approves, via the existing RBAC-gated create endpoints.
- previewImport now also covers single-patient add + migration.
- System prompt: display + add only, never edit/delete or alter the schema;
  stronger migration guidance. ToolContext carries the viewer for task scoping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 23:49:18 +03:00

53 lines
1.7 KiB
TypeScript

"use client";
import { ShieldCheck } from "lucide-react";
import { useTranslation } from "react-i18next";
import { Button } from "@/components/ui/button";
// Inline "Veil" gate. Shown above the prompt input the first time a message
// would leave the clinic for an external provider — replaces the old modal so
// the chat flow is never interrupted. Veil de-identifies PHI before the send.
export function VeilConfirmation({
provider,
onConfirm,
onUseLocal,
onCancel,
}: {
provider: string;
onConfirm: () => void;
onUseLocal: () => void;
onCancel: () => void;
}) {
const { t } = useTranslation();
return (
<div
className="flex w-full flex-col gap-3 rounded-2xl border border-border bg-card/40 px-4 py-3"
role="alertdialog"
>
<div className="flex items-start gap-2.5">
<span className="mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary">
<ShieldCheck className="size-4" />
</span>
<div className="space-y-0.5">
<p className="font-medium text-sm">{t("chat.veil.title")}</p>
<p className="text-muted-foreground text-sm">
{t("chat.veil.body", { provider })}
</p>
</div>
</div>
<div className="flex flex-wrap items-center justify-end gap-2">
<Button onClick={onCancel} size="sm" variant="ghost">
{t("chat.veil.cancel")}
</Button>
<Button onClick={onUseLocal} size="sm" variant="outline">
{t("chat.veil.useLocal")}
</Button>
<Button onClick={onConfirm} size="sm">
{t("chat.veil.confirm")}
</Button>
</div>
</div>
);
}