perf: context expansion is off by default — the stored excerpt already carries the page, its tables and figure captions
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
This commit is contained in:
parent
cd2ee9192a
commit
a6c2cb1080
5 changed files with 20 additions and 8 deletions
|
|
@ -53,7 +53,7 @@ clamped on read so a bad value cannot break a search.
|
|||
|
||||
| Feature | Keys | Default | Clamp |
|
||||
|---|---|---|---|
|
||||
| Clinical Assistant | `clinical_assistant.search_limit`, `clinical_assistant.context_chars` | 8, 1400 | 3–20, 300–4000 |
|
||||
| Clinical Assistant | `clinical_assistant.search_limit`, `clinical_assistant.context_chars` | 8, 0 | 3–20, 0–4000 (0 = excerpt only) |
|
||||
| My Resources | `learning.search_limit`, `learning.context_chars` | 30, 2500 | 3–60, 300–8000 |
|
||||
|
||||
The `learning.*` names are historical: they were the Learning Hub's, and My
|
||||
|
|
@ -61,7 +61,7 @@ Resources inherited the retrieval code when that was removed. Renaming the keys
|
|||
would orphan whatever an administrator has already set, so they keep the old
|
||||
names.
|
||||
|
||||
`search_limit` is how many excerpts to request; `context_chars` is how much text
|
||||
`search_limit` is how many excerpts to request; `context_chars` is how much extra text around each excerpt to fetch from the source at query time — 0, the default, sends the stored excerpt as it is, which already carries the page, its tables and figure captions; any other value makes the search service download and re-extract the source document per hit (about a second each, cached for 15 minutes). It is how much text
|
||||
to pull around each one.
|
||||
|
||||
See [my-resources.md](my-resources.md) for the rest of that feature — its
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@
|
|||
</div>
|
||||
<div class="admin-row">
|
||||
<label for="assistant-context-chars" class="admin-row-label">Context per excerpt (characters)</label>
|
||||
<input id="assistant-context-chars" type="number" min="300" max="4000" value="1400" class="admin-control">
|
||||
<input id="assistant-context-chars" type="number" min="0" max="4000" value="0" class="admin-control" title="0 = the stored excerpt only (no re-extraction of the source at query time)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="admin-row" id="assistant-library-index">
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ export function initClinicalAssistantAdmin(adminEscapeHtml) {
|
|||
setValue('assistant-indexer-url', cfg['clinical_assistant.indexer_url'] || '');
|
||||
setValue('assistant-indexer-token', ''); // never echoed back; blank means keep
|
||||
loadLibraryIndexStatus();
|
||||
setValue('assistant-context-chars', cfg['clinical_assistant.context_chars'] || '1400');
|
||||
setValue('assistant-context-chars', cfg['clinical_assistant.context_chars'] == null || cfg['clinical_assistant.context_chars'] === '' ? '0' : cfg['clinical_assistant.context_chars']);
|
||||
setValue('assistant-translate-provider', 'libretranslate'); // the only provider the server accepts
|
||||
var sourcesBox = document.getElementById('assistant-show-sources');
|
||||
if (sourcesBox) {
|
||||
|
|
@ -436,7 +436,7 @@ export function initClinicalAssistantAdmin(adminEscapeHtml) {
|
|||
Promise.all([
|
||||
putAssistantConfig('clinical_assistant.conversation_chars', getValue('assistant-conversation-budget')),
|
||||
putAssistantConfig('clinical_assistant.search_limit', getValue('assistant-search-limit') || '8'),
|
||||
putAssistantConfig('clinical_assistant.context_chars', getValue('assistant-context-chars') || '1400'),
|
||||
putAssistantConfig('clinical_assistant.context_chars', getValue('assistant-context-chars') || '0'),
|
||||
putAssistantConfig('clinical_assistant.translate_provider', getValue('assistant-translate-provider') || 'libretranslate'),
|
||||
putAssistantConfig('clinical_assistant.show_sources',
|
||||
(document.getElementById('assistant-show-sources') || {}).checked === false ? 'false' : 'true')
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ router.get('/clinical-assistant/status', async function(req, res) {
|
|||
var chatModel = choices.chatConfigured;
|
||||
var imageModel = choices.imageConfigured;
|
||||
var searchLimit = clampInt(await getSetting('clinical_assistant.search_limit', '8'), 3, 20, 8);
|
||||
var contextChars = clampInt(await getSetting('clinical_assistant.context_chars', '1400'), 300, 4000, 1400);
|
||||
var contextChars = clampInt(await getSetting('clinical_assistant.context_chars', '0'), 0, 4000, 0);
|
||||
var translateProvider = String(await getSetting('clinical_assistant.translate_provider', '') || 'libretranslate').toLowerCase();
|
||||
if (!clinicalTranslation.TRANSLATE_PROVIDERS.includes(translateProvider)) translateProvider = 'libretranslate';
|
||||
var budget = conversationBudget(process.env);
|
||||
|
|
@ -574,9 +574,13 @@ async function prepareAssistantChat(body) {
|
|||
// The model that gets shown an attachment when the chat model cannot be.
|
||||
var visionModel = String(await getSetting('clinical_assistant.vision_model', '') || '');
|
||||
var searchLimit = clampInt(await getSetting('clinical_assistant.search_limit', '8'), 3, 20, 8);
|
||||
var contextChars = clampInt(await getSetting('clinical_assistant.context_chars', '1400'), 300, 4000, 1400);
|
||||
var contextChars = clampInt(await getSetting('clinical_assistant.context_chars', '0'), 0, 4000, 0);
|
||||
var behavior = await getSetting('clinical_assistant.system_behavior', DEFAULT_BEHAVIOR) || DEFAULT_BEHAVIOR;
|
||||
var includeContext = body.includeContext !== false;
|
||||
// Context expansion made the search service download each hit's whole PDF
|
||||
// and extract it again at query time to widen the excerpt — a second per
|
||||
// hit. The stored excerpt already carries the page, its tables and figure
|
||||
// captions, so the default is off: 0 characters means "the excerpt only".
|
||||
var includeContext = body.includeContext !== false && contextChars > 0;
|
||||
var showSources = await showSourcesEnabled();
|
||||
|
||||
// Phase timings, numbers only, so "is it slow?" can be answered from the
|
||||
|
|
|
|||
|
|
@ -295,3 +295,11 @@ test('silent SSO: prompt=none on request, a refusal is not an error, the page tr
|
|||
assert.match(js, /urlParams\.get\('sso'\) === 'none'/);
|
||||
assert.match(read('docs/authentication.md'), /## Signed in at PedsHub means signed in here/);
|
||||
});
|
||||
|
||||
|
||||
test('context expansion is off unless an admin asks for it: 0 characters means the stored excerpt only', () => {
|
||||
const src = read('src/routes/clinicalAssistant.js');
|
||||
assert.equal((src.match(/getSetting\('clinical_assistant\.context_chars', '0'\), 0, 4000, 0\)/g) || []).length, 2);
|
||||
assert.match(src, /includeContext = body\.includeContext !== false && contextChars > 0;/);
|
||||
assert.match(read('public/components/admin.html'), /id="assistant-context-chars" type="number" min="0"/);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue