Frun1na opened a new issue, #6821:
URL: https://github.com/apache/rocketmq-dashboard/issues/6821

   ### Before Creating the Bug Report
   
   - [x] I have searched the [open 
issues](https://github.com/apache/rocketmq-dashboard/issues) of this repository 
and believe that this is not a duplicate.
   - [x] This is a defect in RocketMQ Studio, not a usage question and not a 
defect in another Apache RocketMQ repository.
   - [x] I can reproduce this on the current `rocketmq-studio` branch, or I 
have stated the exact version I am running below.
   
   ### Studio Version
   
   branch: rocketmq-studio
   git commit id: a92c2314
   deployed as: reproduced by a unit test against that commit
   
   ### Runtime Environment
   
   OS: not applicable — the defect is in the frontend prompt-template store
   MySQL: not applicable — the defect is in the frontend prompt-template store
   browser (for UI issues): not required to observe it; the stored value itself 
carries half a character, and the failing assertion prints it as the 
replacement glyph
   
   ### Connected RocketMQ Cluster
   
   not applicable — the template store is client-side only and no run is 
started by this path.
   
   ### Describe the Bug
   
   Saving a prompt template clamps its text with `String.prototype.slice`, 
which can cut between the two UTF-16 halves of a supplementary character: the 
saved title, tag or body then ends in a lone high surrogate, i.e. half of the 
emoji the operator typed.
   
   The save path is `saveCustomPromptTemplate` 
(`web/src/pages/ai/promptTemplates.ts:336-360`; the title at `:341` and the 
body at `:342`), which clamps the title to `MAX_PROMPT_TEMPLATE_TITLE_LENGTH` 
(80), the body to `MAX_PROMPT_TEMPLATE_BODY_LENGTH` (6000), each tag to 24 
through `normalizeTags`, and — on the way back in — every stored field through 
`sanitizeCustomTemplate`. All of them go through one helper:
   
   ```ts
   const normalizeText = (value: unknown, maxLength: number): string => {
     const text = typeof value === 'string' ? value.trim() : '';
     return text.length > maxLength ? text.slice(0, maxLength) : text;
   };
   ```
   
   `length` and `slice` count UTF-16 units, while an emoji is one character in 
two of them. A title of 79 `a`s followed by `🚀` is 81 units, so the cap keeps 
the 79 `a`s **and the emoji's high surrogate** (`\uD83D`) and drops the low 
one: the template is stored — and rendered by the modal at 
`PromptTemplateModal.tsx:275` — with an unpaired surrogate, which every 
consumer displays as the replacement glyph. The tail of the title is destroyed 
and the operator sees `aaaa…�` instead of their own text.
   
   The same cut already has a merged fix in this subsystem: #5213 routed the 
conversation title through `TextBounds.truncate` for exactly this reason 
(`AiConversationService.java:351-357`), because "a title ending in a 
supplementary character stored a lone high surrogate". The prompt-template caps 
were the copy that PR did not cover.
   
   ### Steps to Reproduce
   
   Through the store:
   
   ```text
   saveCustomPromptTemplate({ title: `${'a'.repeat(79)}🚀`, body: 'inspect the 
broker' })
   ```
   
   Through the UI: open the AI page, expand the template panel, paste a title 
of 79 characters followed by an emoji into 模板标题 — that input carries no 
`maxLength` — and save. The saved card renders the title with a replacement 
glyph where the emoji was.
   
   The regression test in the pull request pins both this and the body cap 
(5999 units followed by an emoji) and fails against the current branch.
   
   ### What Did You Expect to See?
   
   The clamp keeps whole characters: a supplementary character that would 
straddle the cap is dropped entirely, the way `TextBounds.truncate` drops it on 
the server, so the saved title is 79 `a`s and the stored string contains no 
unpaired surrogate.
   
   ### What Did You See Instead?
   
   The saved title was 79 `a`s plus the emoji's high surrogate. The stored 
value is not a valid character sequence, and the template list renders the 
replacement glyph at the end of the title; applying the template then puts that 
broken character into the prompt as well.
   
   ### Additional Context
   
   A fix with a regression test follows in a pull request.
   
   ### Are You Willing to Submit a Pull Request?
   
   - [x] Yes, I am willing to submit a pull request.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to