#18876: fix(outbound): strip DSML function-call markup before delivery
channel: mattermost
size: S
Cluster:
Model Reasoning Fixes
## Summary
<!-- One-liner: what and why -->
DeepSeek models emit `<|DSML|function_calls>` markup inline with user-visible text. This raw XML leaked into Discord (and other channel) messages, confusing end users.
## Problem
When a DeepSeek model response contains both text and function calls, the DSML markup is included in the text content block. The outbound delivery pipeline had no stripping for this format, so it was sent verbatim to channels.
Example user-visible message:
```
Perfect! I'll post the tweet now. <|DSML|function_calls> <|DSML|invoke name="exec"> …
```
## Solution
- Add `stripDsmlMarkup()` to `src/shared/text/reasoning-tags.ts` that removes everything from the first `<|DSML|` occurrence to end-of-string (DSML blocks always trail user-visible content)
- Call it in `parseReplyDirectives()` which processes all outbound reply text, so all channels benefit
## Changes
- `src/shared/text/reasoning-tags.ts` — new `stripDsmlMarkup()` export
- `src/auto-reply/reply/reply-directives.ts` — call `stripDsmlMarkup()` on text before directive parsing
- `src/shared/text/reasoning-tags.test.ts` — 5 new tests for DSML stripping
## Test plan
- [x] All 49 reasoning-tags tests pass (39 existing + 5 new DSML + 5 new)
- [x] `pnpm build` passes
Closes #18644
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Adds `stripDsmlMarkup()` to strip DeepSeek DSML function-call markup (`<|DSML|...>`) from outbound messages before they reach users. The function is called within `parseReplyDirectives()`, which is the shared entry point for all outbound delivery paths (Discord, Telegram, Slack, and others).
- `stripDsmlMarkup()` in `src/shared/text/reasoning-tags.ts` uses `indexOf` to find the first `<|DSML|` occurrence and slices everything from there to end-of-string, with `trimEnd()` cleanup. Clean and efficient.
- Integration in `src/auto-reply/reply/reply-directives.ts` is minimal and well-placed — applied immediately after media splitting, before directive parsing.
- Test file has a **duplicate `describe` block** — the same 5 tests appear twice (once with `\uFF5C` unicode escapes, once with literal `|` characters). One should be removed.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge — the core logic is correct, minimal, and well-tested; only a non-critical test duplication needs cleanup.
- The stripping logic is straightforward (indexOf + slice) and correctly handles edge cases. The integration point in parseReplyDirectives covers all major outbound delivery paths. Score of 4 rather than 5 due to the duplicated test describe block which, while not a runtime issue, indicates insufficient review of the test file before submission.
- `src/shared/text/reasoning-tags.test.ts` has a fully duplicated describe block that should be removed.
<sub>Last reviewed commit: f74888b</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#17244: fix: strip TTS tags from agent replies before delivery (#14652)
by robbyczgw-cla · 2026-02-15
80.1%
#20164: fix(webchat): strip reply directive tags before rendering assistant...
by Limitless2023 · 2026-02-18
79.7%
#23073: fix(ui): strip reply directive tags from assistant messages in WebC...
by x4v13r1120 · 2026-02-22
74.6%
#5982: fix: sanitize model reasoning blocks from Discord output
by Ambar-13 · 2026-02-01
74.5%
#16733: fix(ui): avoid injected newlines when tool output is hidden
by jp117 · 2026-02-15
74.4%
#23144: fix(ui): strip reply directive tags from assistant messages in WebC...
by echoVic · 2026-02-22
74.4%
#17304: feat(gemini): robust handling for non-XML reasoning headers (`Think...
by YoshiaKefasu · 2026-02-15
73.1%
#17455: fix: strip content before orphan closing think tags
by jwt625 · 2026-02-15
72.7%
#10612: fix: trim leading blank lines on first emitted chunk only (#5530)
by 1kuna · 2026-02-06
72.7%
#18935: fix(agents): suppress reasoning blocks from channel delivery
by BinHPdev · 2026-02-17
72.5%