mirror of
https://github.com/temetro/temetro.git
synced 2026-07-26 11:58:14 +00:00
fa2e499440
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>
53 lines
1.7 KiB
TypeScript
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>
|
|
);
|
|
}
|