diff --git a/public/index.html b/public/index.html
index 8f8dd24..8d58a52 100644
--- a/public/index.html
+++ b/public/index.html
@@ -485,7 +485,7 @@
-
+
diff --git a/public/js/peGuide.js b/public/js/peGuide.js
index 66b3a37..73369e6 100644
--- a/public/js/peGuide.js
+++ b/public/js/peGuide.js
@@ -15,8 +15,6 @@
// step array and produces a Technique + Findings narrative.
// ============================================================
-(function () {
-
// ────────────────────────────────────────────────────────────
// GRADING SCALES — universal reference shown at top of each system
// ────────────────────────────────────────────────────────────
@@ -1710,5 +1708,3 @@
if (s == null) return '';
return String(s).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
}
-
-})();
diff --git a/src/routes/clinicalAssistant.js b/src/routes/clinicalAssistant.js
index 230fabc..10e3ab6 100644
--- a/src/routes/clinicalAssistant.js
+++ b/src/routes/clinicalAssistant.js
@@ -44,73 +44,6 @@ var GREETING_RE = /^(hi|hello|hey|yo|good\s+(morning|afternoon|evening)|thanks|t
var MAX_SAVED_CHATS_PER_USER = 100;
var MAX_SAVED_CHAT_PAYLOAD = 250000;
var MAX_SAVED_CHAT_TITLE = 160;
-var EXAMPLE_CANDIDATES = [
- { label: 'Status asthma escalation', prompt: 'In a 4-year-old with acute wheeze, when should magnesium sulfate be considered and what dose is recommended?' },
- { label: 'Febrile neonate', prompt: 'What initial workup and empiric antibiotics are recommended for a well-appearing febrile neonate?' },
- { label: 'Sepsis vasoactives', prompt: 'In pediatric septic shock, when should fluid boluses be limited and vasoactives started?' },
- { label: 'Toxic ingestion', prompt: 'How should an unknown pediatric ingestion be initially assessed and when is activated charcoal appropriate?' },
- { label: 'Meningitis antibiotics', prompt: 'What empiric antibiotics are recommended for suspected bacterial meningitis by pediatric age group?' },
- { label: 'Sickle fever', prompt: 'How should fever in a child with sickle cell disease be evaluated and treated?' },
- { label: 'Head injury CT', prompt: 'Which pediatric head injury features should prompt CT imaging or ED observation?' },
- { label: 'Anaphylaxis IM epi', prompt: 'What is the recommended IM epinephrine dose for pediatric anaphylaxis and when should it be repeated?' },
- { label: 'Dehydration fluids', prompt: 'How should dehydration severity guide oral rehydration versus IV fluids in children?' },
- { label: 'Neonatal jaundice', prompt: 'Which neonatal jaundice risk factors change phototherapy thresholds or urgency?' },
- { label: 'UTI imaging', prompt: 'When should children with febrile UTI receive renal ultrasound or further imaging?' },
- { label: 'Kawasaki workup', prompt: 'What clinical and laboratory features support incomplete Kawasaki disease evaluation?' },
- { label: 'Intussusception', prompt: 'What are the red flags, diagnostic steps, and reduction approach for suspected intussusception?' },
- { label: 'NAT red flags', prompt: 'What injury patterns and history features should raise concern for non-accidental trauma?' },
- { label: 'Status epilepticus', prompt: 'Outline first- and second-line treatment for pediatric status epilepticus with typical dosing.' },
- { label: 'Croup escalation', prompt: 'When should a child with croup receive nebulized epinephrine, and how long should they be observed?' },
- { label: 'Bilious vomiting', prompt: 'What are the red flags for bilious vomiting in neonates, and what immediate workup is recommended?' },
- { label: 'Bronchiolitis oxygen', prompt: 'What supportive care and oxygen/admission criteria are recommended for infant bronchiolitis?' },
- { label: 'DKA cerebral edema', prompt: 'What warning signs suggest cerebral edema during pediatric DKA treatment, and what immediate treatment is recommended?' },
- { label: 'Neonatal resuscitation', prompt: 'Summarize the first minute steps in neonatal resuscitation and when positive pressure ventilation is indicated.' }
-];
-var TOPIC_SUGGESTIONS = {
- asthma: [
- 'How should acute pediatric asthma exacerbation severity guide SABA frequency, ipratropium, steroids, magnesium sulfate, and disposition?',
- 'When should magnesium sulfate, continuous albuterol, noninvasive ventilation, ICU transfer, or intubation be considered in status asthmaticus?',
- 'How can bronchiolitis, viral-induced wheeze, and early asthma be distinguished in infants and preschool children?',
- 'What discharge criteria, observation period, relapse risks, and follow-up are recommended after an ED asthma exacerbation?',
- 'When should controller therapy be started or stepped up after an ED asthma visit?'
- ],
- bronchiolitis: [
- 'What supportive care, suctioning, hydration, oxygen targets, and feeding guidance are recommended for infant bronchiolitis?',
- 'When is a bronchodilator trial reasonable in bronchiolitis, and when should it be stopped?',
- 'What apnea risk, work of breathing, oxygen saturation, hydration, and social factors support admission for bronchiolitis?',
- 'How can bronchiolitis be distinguished from early asthma, pneumonia, cardiac disease, or foreign body aspiration?',
- 'When should high-flow nasal cannula, CPAP, ICU transfer, or escalation be considered in bronchiolitis?'
- ],
- fever: [
- 'How should fever without source be evaluated by age group in neonates, young infants, and older children?',
- 'What cultures, inflammatory markers, LP decisions, empiric antibiotics, and disposition are recommended for febrile neonates?',
- 'Which clinical and laboratory features stratify risk for serious bacterial infection in febrile infants?',
- 'When is lumbar puncture indicated or avoidable in febrile infants by age and risk category?',
- 'How should fever be approached in immunocompromised children, central lines, or incomplete immunization?'
- ],
- seizure: [
- 'What is the timed pediatric status epilepticus algorithm including benzodiazepine dosing and second-line choices?',
- 'How should simple versus complex febrile seizures be evaluated, treated, and explained to caregivers?',
- 'When should levetiracetam, fosphenytoin, phenobarbital, valproate, anesthetic infusion, or ICU transfer be used?',
- 'Which seizure presentations require neuroimaging, labs, toxicology, LP, EEG, or admission?',
- 'What common seizure mimics in children should be considered and how are they distinguished?'
- ],
- croup: [
- 'How should croup severity guide dexamethasone, nebulized epinephrine, observation, and disposition?',
- 'When is nebulized epinephrine indicated for croup and how long should the child be observed afterward?',
- 'What dexamethasone dose and route are recommended for mild, moderate, and severe croup?',
- 'What discharge, admission, ICU, and airway escalation criteria apply after croup treatment?',
- 'What alternative diagnoses should be considered in a child with stridor or atypical croup?'
- ],
- dehydration: [
- 'Which clinical signs best estimate mild, moderate, and severe dehydration in children?',
- 'What oral rehydration protocol, volumes, antiemetic use, and reassessment are recommended for gastroenteritis?',
- 'When are IV boluses, maintenance fluids, deficit replacement, glucose, or electrolyte checks indicated?',
- 'How should hypernatremic dehydration be recognized and corrected safely?',
- 'What discharge, admission, and follow-up criteria apply after pediatric gastroenteritis or dehydration?'
- ]
-};
-
var promptPool = createClinicalPromptPool({
redisCache: redisCache,
callAI: callAI,
@@ -118,9 +51,7 @@ var promptPool = createClinicalPromptPool({
semanticSearch: semanticSearch,
dedupeSources: dedupeSources,
normalizeMcpSearchResponse: normalizeMcpSearchResponse,
- getIndexedTopicExamples: getIndexedTopicExamples,
- exampleCandidates: EXAMPLE_CANDIDATES,
- topicSuggestions: TOPIC_SUGGESTIONS
+ getIndexedTopicExamples: getIndexedTopicExamples
});
function positiveInt(value, fallback) {
@@ -386,18 +317,6 @@ async function prepareAssistantChat(body) {
}
var history = Array.isArray(body.history) ? body.history.slice(-8) : [];
- var contextualHistory = priorClinicalHistory(history, message);
- var suggestions = getTopicSuggestions(message);
- if (!contextualHistory.length && suggestions.length > 0 && message.split(/\s+/).length < 4) {
- return { direct: {
- success: true,
- answer: buildSuggestionAnswer(message, suggestions),
- suggestions: suggestions,
- sources: [],
- model: null,
- search: { skipped: true, reason: 'topic_suggestions' }
- } };
- }
var searchQuery = await rewriteSearchQuery(message, history, chatModel).catch(function(e) {
console.warn('[clinical-assistant] query rewrite skipped:', e.message);
@@ -503,13 +422,6 @@ function needsContextualRewrite(message) {
return words.length <= 8 || /\b(it|this|that|they|them|he|she|dose|dosing|how much|what about|next|admit|discharge|criteria|side effects?|contraindications?|monitor|monitoring)\b/i.test(text);
}
-function priorClinicalHistory(history, message) {
- var latest = String(message || '').trim();
- return (Array.isArray(history) ? history : []).filter(function(m) {
- return m && (m.role === 'user' || m.role === 'assistant') && m.content && String(m.content).trim() !== latest;
- });
-}
-
function deterministicFollowupQuery(message, history) {
var text = String(message || '').trim().toLowerCase();
if (!/^(dose|dosing|what dose|dose\?|how much|med dose|medication dose)$/i.test(text)) return '';
@@ -716,22 +628,4 @@ function assistantErrorMessage(e) {
return msg || 'Assistant request failed';
}
-function getTopicSuggestions(message) {
- var normalized = String(message || '').toLowerCase().replace(/[^a-z0-9\s-]/g, ' ').replace(/\s+/g, ' ').trim();
- if (!normalized) return [];
- var direct = TOPIC_SUGGESTIONS[normalized];
- if (direct) return direct;
- var keys = Object.keys(TOPIC_SUGGESTIONS);
- for (var i = 0; i < keys.length; i++) {
- if (normalized.indexOf(keys[i]) !== -1) return TOPIC_SUGGESTIONS[keys[i]];
- }
- return [];
-}
-
-function buildSuggestionAnswer(topic, suggestions) {
- return 'I can look up **' + topic + '**. Pick a specific clinical question so I retrieve the right cited pages instead of giving a broad summary:\n\n' +
- suggestions.map(function(s) { return '- ' + s; }).join('\n') +
- '\n\nOr type your own specific question, for example: "management of acute asthma exacerbation in a 6-year-old".';
-}
-
module.exports = router;
diff --git a/src/utils/clinicalPromptPool.js b/src/utils/clinicalPromptPool.js
index 0a6a694..9d0c6b9 100644
--- a/src/utils/clinicalPromptPool.js
+++ b/src/utils/clinicalPromptPool.js
@@ -41,10 +41,7 @@ function createClinicalPromptPool(opts) {
refreshIfNeeded(false).catch(function() {});
- var examples = [];
- rotateExamples(opts.exampleCandidates || [], now).slice(0, 9).forEach(function(item) {
- examples.push({ label: item.label, prompt: item.prompt });
- });
+ var examples = await fallbackIndexedExamples();
memoryCache = { expiresAt: now + cacheMs, examples: examples };
return examples;
diff --git a/test/clinical-assistant-prompt-pool.test.js b/test/clinical-assistant-prompt-pool.test.js
new file mode 100644
index 0000000..cb6278b
--- /dev/null
+++ b/test/clinical-assistant-prompt-pool.test.js
@@ -0,0 +1,20 @@
+const { test } = require('node:test');
+const assert = require('node:assert/strict');
+const fs = require('node:fs');
+const path = require('node:path');
+
+const root = path.join(__dirname, '..');
+
+function read(relativePath) {
+ return fs.readFileSync(path.join(root, relativePath), 'utf8');
+}
+
+test('clinical assistant starter prompts are Redis or indexed-source backed', () => {
+ const route = read('src/routes/clinicalAssistant.js');
+ const pool = read('src/utils/clinicalPromptPool.js');
+ assert.doesNotMatch(route, /EXAMPLE_CANDIDATES|TOPIC_SUGGESTIONS|topic_suggestions|buildSuggestionAnswer/);
+ assert.match(route, /createClinicalPromptPool\(\{[\s\S]*redisCache: redisCache/);
+ assert.match(pool, /opts\.redisCache\.getJson\(redisKey\)/);
+ assert.match(pool, /opts\.redisCache\.setJson\(redisKey, payload, ttlSeconds\)/);
+ assert.match(pool, /var examples = await fallbackIndexedExamples\(\)/);
+});
diff --git a/test/module-entrypoints.test.js b/test/module-entrypoints.test.js
index ccc7f6a..1e17e91 100644
--- a/test/module-entrypoints.test.js
+++ b/test/module-entrypoints.test.js
@@ -20,6 +20,7 @@ const moduleEntrypoints = [
'public/js/milestones.js',
'public/js/nextcloud.js',
'public/js/notes.js',
+ 'public/js/peGuide.js',
'public/js/sickVisit.js',
'public/js/soap.js',
'public/js/secureStorage.js',