fix(hud): keep English out of localized summaries, cap ja/zh by characters only

Second follow-up review fixes:

- Japanese and Chinese summaries are capped at 20 characters only, without
  the five-token cut first, and the cap steps back to a space instead of
  splitting a Latin word.
- The HUD request sends localized layer names in feedProvenance too and
  leaves the English narration note out outside English. A non-English reply
  that still echoes a feed-state id or a translated English layer name falls
  back to the deterministic line.
- A camera move during typing shows the deterministic line, not a fragment.
- A view with no place labels and no enabled layer does not ask the model.
- Behaviour tests on IntelHUD replace the regex checks of hud.js; docs and
  the instruction wording updated.
This commit is contained in:
German Khokhlov committed 2026-10-30 16:28:56 +04:00
1 parent 7b223d7d7b
commit 7713fb8ae8
8 files changed
+328 -60

No files matched your search

+17 -11
View File
@@ -45,18 +45,24 @@ function toFiveWordHudSummary(value, unspaced) {
.replace(/[^\p{L}\p{N}\s-]/gu, ' ')
.trim()
.split(/\s+/)
.filter(Boolean)
.slice(0, 5)
.join(' ');
// Japanese and Chinese have no spaces to count words by: cap characters.
.filter(Boolean);
// Other languages keep five words, even around a Han place name.
if (!unspaced) return words;
const graphemes = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
return [...graphemes.segment(words)]
.slice(0, HUD_SUMMARY_MAX_UNSPACED_CHARS)
.map(({ segment }) => segment)
.join('')
.trim();
if (!unspaced) return words.slice(0, 5).join(' ');
// Japanese and Chinese have no spaces to count words by: cap characters,
// stepping back to a space rather than cutting a Latin word in two.
const text = words.join(' ');
const graphemes = [
...new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(text),
].map(({ segment }) => segment);
if (graphemes.length <= HUD_SUMMARY_MAX_UNSPACED_CHARS) return text;
const head = graphemes.slice(0, HUD_SUMMARY_MAX_UNSPACED_CHARS);
const next = graphemes[HUD_SUMMARY_MAX_UNSPACED_CHARS];
const inWord = (g) => /^[\p{Script=Latin}\p{N}]/u.test(g ?? '');
if (inWord(head.at(-1)) && inWord(next)) {
const space = head.lastIndexOf(' ');
if (space > 0) return head.slice(0, space).join('').trim();
}
return head.join('').trim();
}
async function handleHudSummary(req, res) {