fix: the active library view is unmistakable, and a leading question cannot mislead the vision model
Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 49s
Forgejo Docker Build / Root app tests (push) Successful in 57s
Forgejo Android APK / Build signed APK (push) Successful in 1m58s
Forgejo Docker Build / Build Docker image (push) Successful in 18s
Forgejo Docker Build / Deploy to the host (push) Failing after 0s
Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 49s
Forgejo Docker Build / Root app tests (push) Successful in 57s
Forgejo Android APK / Build signed APK (push) Successful in 1m58s
Forgejo Docker Build / Build Docker image (push) Successful in 18s
Forgejo Docker Build / Deploy to the host (push) Failing after 0s
Documents and Images were two buttons of the same weight, which reads as two buttons rather than as a current view and an alternative. The active one now carries the surface, the weight and a hairline — keyed off aria-selected, so the visible highlight and what a screen reader announces cannot disagree. The look_at_image question is written by a model that has not seen the image, from what the user said, so it can presume something that is not there — "describe this rash" about a photograph of a drug chart. Answering the presumption would send it back as fact. The seeing model is now told the question may assume something absent, and to say so first and describe what is actually there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
This commit is contained in:
parent
1f06a19007
commit
fce05a2749
5 changed files with 38 additions and 7 deletions
|
|
@ -154,11 +154,9 @@
|
|||
shown; Images is every picture this account has generated, wherever it
|
||||
was made, because a figure is worth keeping after the deck it was
|
||||
drawn for has been replaced. -->
|
||||
<div role="tablist" aria-label="Library view" style="display:flex;gap:2px;background:var(--g100);border-radius:6px;padding:2px;">
|
||||
<button id="tab-mr-docs" role="tab" aria-selected="true" aria-controls="mr-list" class="btn-sm" type="button"
|
||||
style="border:0;border-radius:4px;background:var(--white);font-size:12px;padding:4px 10px;">Documents</button>
|
||||
<button id="tab-mr-images" role="tab" aria-selected="false" aria-controls="mr-images-panel" class="btn-sm" type="button"
|
||||
style="border:0;border-radius:4px;background:transparent;font-size:12px;padding:4px 10px;">Images</button>
|
||||
<div role="tablist" aria-label="Library view" class="lib-tabs">
|
||||
<button id="tab-mr-docs" role="tab" aria-selected="true" aria-controls="mr-list" class="lib-tab" type="button">Documents</button>
|
||||
<button id="tab-mr-images" role="tab" aria-selected="false" aria-controls="mr-images-panel" class="lib-tab" type="button">Images</button>
|
||||
</div>
|
||||
<button id="btn-mr-refresh" class="btn-sm btn-ghost" type="button"><i class="fas fa-rotate"></i> Refresh</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1555,3 +1555,14 @@ button, a, .btn-sm, .btn-generate, .btn-send, .tab-btn, input, textarea, select,
|
|||
border-radius:8px;box-shadow:0 16px 48px rgba(0,0,0,.45);background:var(--g100);}
|
||||
.img-lightbox-bar{display:flex;gap:8px;align-items:center;flex-wrap:wrap;justify-content:center;max-width:640px;}
|
||||
.img-lightbox-caption{color:#e5e7eb;font-size:12px;line-height:1.5;text-align:center;}
|
||||
|
||||
/* Library view switch. The active view has to be unmistakable — two buttons of
|
||||
the same weight read as two buttons, not as a current view and an alternative. */
|
||||
.lib-tabs{display:flex;gap:2px;background:var(--g100);border-radius:8px;padding:3px;}
|
||||
.lib-tab{border:0;border-radius:6px;background:transparent;color:var(--g500);
|
||||
font:inherit;font-size:12px;font-weight:500;padding:5px 12px;cursor:pointer;
|
||||
transition:background .15s ease,color .15s ease,box-shadow .15s ease;}
|
||||
.lib-tab:hover{color:var(--g700);}
|
||||
.lib-tab[aria-selected="true"]{background:var(--white,#fff);color:var(--g900);font-weight:600;
|
||||
box-shadow:0 1px 2px rgba(17,24,39,.10),0 0 0 1px rgba(17,24,39,.04);}
|
||||
.lib-tab:focus-visible{outline:2px solid var(--blue);outline-offset:1px;}
|
||||
|
|
|
|||
|
|
@ -281,8 +281,9 @@
|
|||
[['tab-mr-docs', docs], ['tab-mr-images', !docs]].forEach(function (pair) {
|
||||
var tab = document.getElementById(pair[0]);
|
||||
if (!tab) return;
|
||||
// aria-selected is the whole state: the stylesheet keys off it, so the
|
||||
// visible highlight and what a screen reader announces cannot disagree.
|
||||
tab.setAttribute('aria-selected', pair[1] ? 'true' : 'false');
|
||||
tab.style.background = pair[1] ? 'var(--white)' : 'transparent';
|
||||
});
|
||||
var list = document.getElementById('mr-list');
|
||||
var panel = document.getElementById('mr-images-panel');
|
||||
|
|
|
|||
|
|
@ -58,7 +58,18 @@ function describePrompt(question) {
|
|||
'cannot see it can reason about it. Report only what is observable — colours, ' +
|
||||
'distribution, morphology, text, readings, scale. Do not diagnose, do not ' +
|
||||
'speculate about causes, and say plainly when something is unclear or cut off ' +
|
||||
'rather than guessing.\n\nThe question to answer: ' + question;
|
||||
'rather than guessing.\n\n' +
|
||||
// The question is written by a model that has not seen the image, from what
|
||||
// the user said. So it can presume something that is not there — "describe
|
||||
// this rash" about a photograph of a drug chart. Answering the presumption
|
||||
// rather than the picture is the failure that matters, because the answer
|
||||
// then travels back as fact.
|
||||
'The question below was written by someone who cannot see the image, so it ' +
|
||||
'may assume something the image does not show. Describe what is actually ' +
|
||||
'there. If the question presumes something absent — a finding, a body part, ' +
|
||||
'a kind of document — say so first, in plain words, and then describe what ' +
|
||||
'the image does contain.\n\n' +
|
||||
'The question: ' + question;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -56,6 +56,16 @@ test('a call routes the image to the vision model, never to the chat model', asy
|
|||
assert.equal(out.content, 'That pattern fits...');
|
||||
});
|
||||
|
||||
test('a question that presumes the wrong thing is corrected, not answered', () => {
|
||||
// The question is written by a model that has not seen the image, from what
|
||||
// the user said — so "describe this rash" can arrive about a photograph of a
|
||||
// drug chart. Answering the presumption would send that back as fact.
|
||||
const prompt = visionTool.describePrompt('what is the distribution of this rash');
|
||||
assert.match(prompt, /may assume something the image does not show/);
|
||||
assert.match(prompt, /If the question presumes something absent/);
|
||||
assert.match(prompt, /describe what the image does contain/);
|
||||
});
|
||||
|
||||
test('the seeing model is told to report, not to diagnose', () => {
|
||||
// It has a picture and no conversation, no sources and no system prompt. An
|
||||
// opinion from it would carry weight it has not earned.
|
||||
|
|
|
|||
Loading…
Reference in a new issue