mirror of
https://github.com/temetro/temetro.git
synced 2026-07-26 11:58:14 +00:00
d30c310336
The composer's SELECT is now a clinician-facing mode picker instead of a list of LLM vendors (the model still comes from Settings → AI and continues to drive the Veil consent gate). The mode travels with each send: - backend appends an Analysis/Graph directive to the agent's system prompt - Graph mode renders an Obsidian-style RecordGraph for the /patient fast-path (new data-recordGraph message part reusing the shared graph component) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
78 lines
2.1 KiB
TypeScript
78 lines
2.1 KiB
TypeScript
"use client";
|
|
|
|
import { ChevronDown } from "lucide-react";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import {
|
|
Menu,
|
|
MenuPopup,
|
|
MenuRadioGroup,
|
|
MenuRadioItem,
|
|
MenuTrigger,
|
|
} from "@/components/ui/menu";
|
|
import { type ChatMode, CHAT_MODES, getMode } from "@/lib/chat-modes";
|
|
|
|
type ModePickerProps = {
|
|
mode: ChatMode;
|
|
onModeChange: (mode: ChatMode) => void;
|
|
triggerClassName: string;
|
|
};
|
|
|
|
/**
|
|
* The situation-mode control in the chat composer (Chat / Analysis / Graph).
|
|
* Replaces the old model picker — clinicians pick what they want the assistant
|
|
* to do, not which LLM runs (that's configured once in Settings → AI).
|
|
*/
|
|
export function ModePicker({
|
|
mode,
|
|
onModeChange,
|
|
triggerClassName,
|
|
}: ModePickerProps) {
|
|
const { t } = useTranslation();
|
|
const selected = getMode(mode);
|
|
const SelectedIcon = selected.icon;
|
|
|
|
return (
|
|
<Menu>
|
|
<MenuTrigger
|
|
render={
|
|
<button
|
|
aria-label={t("chat.input.mode")}
|
|
className={triggerClassName}
|
|
type="button"
|
|
/>
|
|
}
|
|
>
|
|
<SelectedIcon className="size-4 opacity-80" />
|
|
<span className="truncate font-medium text-foreground">
|
|
{t(selected.labelKey)}
|
|
</span>
|
|
<ChevronDown className="size-4 opacity-70" />
|
|
</MenuTrigger>
|
|
<MenuPopup align="end" className="min-w-64">
|
|
<MenuRadioGroup
|
|
onValueChange={(value) => onModeChange(value as ChatMode)}
|
|
value={mode}
|
|
>
|
|
{CHAT_MODES.map((m) => {
|
|
const Icon = m.icon;
|
|
return (
|
|
<MenuRadioItem key={m.id} value={m.id}>
|
|
<span className="flex items-center gap-2">
|
|
<Icon className="size-4 opacity-80" />
|
|
<span className="flex flex-col">
|
|
<span className="text-foreground">{t(m.labelKey)}</span>
|
|
<span className="text-muted-foreground text-xs">
|
|
{t(m.descriptionKey)}
|
|
</span>
|
|
</span>
|
|
</span>
|
|
</MenuRadioItem>
|
|
);
|
|
})}
|
|
</MenuRadioGroup>
|
|
</MenuPopup>
|
|
</Menu>
|
|
);
|
|
}
|