mirror of
https://github.com/temetro/temetro.git
synced 2026-08-13 03:56:53 +00:00
feat(chat): replace model picker with situation modes (Chat/Analysis/Graph)
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>
This commit is contained in:
@@ -78,7 +78,23 @@ function inlineTextFiles(messages: UIMessage[]): UIMessage[] {
|
||||
});
|
||||
}
|
||||
|
||||
function systemPrompt(veilActive: boolean, providerLabel: string): string {
|
||||
// A short directive for the clinician's chosen "situation" mode, appended to the
|
||||
// base prompt. Chat mode adds nothing.
|
||||
function modeDirective(mode: string | undefined): string {
|
||||
if (mode === "analysis") {
|
||||
return "Mode — Analysis: the clinician wants interpretation, not just retrieval. After fetching a patient's data, surface patterns and correlations across their problems, labs and visits (e.g. recurring complaints, trends, likely links) and call out anything notable. Stay grounded in the tool results.";
|
||||
}
|
||||
if (mode === "graph") {
|
||||
return "Mode — Graph: the clinician wants to see how a patient's problems and visits connect. When they reference a patient, call getPatient (its record graph renders automatically) and briefly describe the key relationships between illnesses and encounters.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function systemPrompt(
|
||||
veilActive: boolean,
|
||||
providerLabel: string,
|
||||
mode?: string,
|
||||
): string {
|
||||
return [
|
||||
"You are temetro, a clinical assistant that helps clinicians retrieve,",
|
||||
"organize, and add patient information. You operate over a real patient",
|
||||
@@ -130,6 +146,7 @@ function systemPrompt(veilActive: boolean, providerLabel: string): string {
|
||||
veilActive
|
||||
? `Privacy: this conversation runs on an external provider (${providerLabel}). Patient identifiers are de-identified as tokens like [PATIENT_1] / [MRN_1]; refer to patients generically ("this patient") rather than repeating tokens.`
|
||||
: "",
|
||||
modeDirective(mode),
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
@@ -137,10 +154,11 @@ function systemPrompt(veilActive: boolean, providerLabel: string): string {
|
||||
|
||||
chatRouter.post("/", async (req, res, next) => {
|
||||
try {
|
||||
const { messages, model: requestedModel } = req.body as {
|
||||
const { messages, model: requestedModel, mode } = req.body as {
|
||||
messages: UIMessage[];
|
||||
model?: string;
|
||||
effort?: string;
|
||||
mode?: string;
|
||||
};
|
||||
if (!Array.isArray(messages)) {
|
||||
res.status(400).json({ error: "messages must be an array." });
|
||||
@@ -171,7 +189,7 @@ chatRouter.post("/", async (req, res, next) => {
|
||||
};
|
||||
|
||||
const modelMessages = await convertToModelMessages(inlineTextFiles(messages));
|
||||
const system = systemPrompt(veil.active, resolved.providerLabel);
|
||||
const system = systemPrompt(veil.active, resolved.providerLabel, mode);
|
||||
|
||||
const stream = createUIMessageStream({
|
||||
execute: async ({ writer }) => {
|
||||
|
||||
Reference in New Issue
Block a user