fix: remove empty tagged messages after tool drop (Issue #97)#98
Merged
alfonso-magic-context merged 7 commits intoJun 4, 2026
Merged
Conversation
Strips tag prefixes before checking if a text part is meaningful. Prevents empty user messages (containing only section tags) from confusing the LLM and causing hallucinated number multiplication. Closes cortexkit#97
There was a problem hiding this comment.
No issues found across 2 files
Tip: cubic could auto-approve low-risk PRs like this, if it thinks it's safe to merge. Learn more
Re-trigger cubic
Build a portable plugin+cli tree with TUI sources and runtime deps instead of uploading dist-only folders that break OpenCode TUI loading.
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Replace digit-residue regex with pair-aware persistence cleanup so assistant text-complete and Pi message_end remove whole §N§ tokens without breaking legitimate leading numbers (99 files, 2024 roadmap). Transform stripTagPrefix stays §-notation-only; temporal awareness uses shared peelLeadingMcTagNotation. Unifies tool-drop hasMeaningfulPart. Related to cortexkit#97
Remove branch-scoped workflow and packaging script; not part of cortexkit#97 tag/persistence fixes.
Biome config enforces 4-space indentation but these files used tabs. Also fixes missing trailing newline in strip-tag-prefix.ts. Run: bun run --cwd packages/pi-plugin lint passes clean. Related to cortexkit#97
Run biome format on packages/plugin to fix indentation and line spacing in files introduced by PR cortexkit#97. Also collapses overly-split .toBe() assertions in test files. Related to cortexkit#97
…, move JSDoc - stripPersistedAssistantText: add .trim() to prevent whitespace-only assistant messages after malformed-prefix cleanup (Greptile P2) - Restore unit tests for byteSize and isThinkingPart removed during rewrite (Greptile P2) - Move file-level JSDoc after import in text-complete.ts (Greptile P2) Related to cortexkit#97
Contributor
Author
|
It's green! 😀 |
ualtinok
added a commit
that referenced
this pull request
Jun 4, 2026
Post-merge cleanup of PR #98: - Pi's strip-tag-prefix.ts and temporal-awareness-pi.ts imported the shared tag-content-primitives via a raw cross-package path (../../plugin/src/...). Switch to the `@magic-context/core/...` workspace alias used everywhere else in Pi (the only two ../../plugin/src imports in the package). - Fix a garbled test description: "transform ? ? notation only" → the intended "transform §N§ notation only" (the § chars were mangled on the way in). No behavior change. Plugin 1796/0, Pi 403/0, tsc + biome clean. Co-authored-by: Alfonso [Magic Context] <288211368+alfonso-magic-context@users.noreply.github.com>
KorenKrita
added a commit
to KorenKrita/magic-context
that referenced
this pull request
Jul 7, 2026
cortexkit#97) Persistence-boundary strip now removes whole §N§ pairs (not bare §), eliminating the digit-residue that stacked across turns into runaway 'multiplying numbers' overflow (cortexkit#97). hasMeaningfulPart strips the tag prefix before the emptiness check so tag-only ghost messages are pruned. Shared tag-strip helpers in tag-content-primitives.ts are reused by both OpenCode and Pi. Thanks to @Zireael for the fix.
KorenKrita
added a commit
to KorenKrita/magic-context
that referenced
this pull request
Jul 7, 2026
Post-merge cleanup of PR cortexkit#98: - Pi's strip-tag-prefix.ts and temporal-awareness-pi.ts imported the shared tag-content-primitives via a raw cross-package path (../../plugin/src/...). Switch to the `@magic-context/core/...` workspace alias used everywhere else in Pi (the only two ../../plugin/src imports in the package). - Fix a garbled test description: "transform ? ? notation only" → the intended "transform §N§ notation only" (the § chars were mangled on the way in). No behavior change. Plugin 1796/0, Pi 403/0, tsc + biome clean. Co-authored-by: Alfonso [Magic Context] <288211368+alfonso-magic-context@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem (#97)
Magic Context tags visible message parts with
§N§prefixes so the agent can reference them (ctx_reduce(§3§)). Two related failure modes were reported:1. Empty tagged messages after tool drop
When execute passes drop most tool structure, user messages that contain only a tag prefix (e.g.
§424§) were not removed.hasMeaningfulParttreated the raw§characters as content. These ghost messages pollute the transcript and confuse the model.2. Multiplying / bleeding tag numbers in chat UI
Assistant and user-visible text accumulated leading numbers and cargo-cult tag notation, e.g.:
2030 2030 2030° Run clippy again:99 Actually executing now. Running fmt:§40827§cargo-cult from models mimicking MC notationRoot cause (persistence vs transform mismatch):
§N§on each pass viaprependTag/stripTagPrefix.experimental.text.complete(and Pimessage_endpersistence) previously stripped all§characters globally. Well-formed§2030§became bare2030— digit residue with no section signs.stripTagPrefixonly removed leading §-shaped prefixes, not bare digits. Each transform pass prepended a fresh§N§in front of the residue → numbers stacked in persisted/UI text.99 files…,6 8 9 tasks…,2024 roadmap, numbered lists).Issue #97’s original fix targeted tagger/DB counter drift and empty tagged messages; it did not fully address the persistence/transform split above.
What this PR changes
Tool drop — remove empty tagged messages
hasMeaningfulPartintool-drop-target.tsnow uses sharedstripTagPrefixbefore checking whether text is non-empty (well-formed and malformed leading§N§shapes).tool-drop-target.test.tscover tag-only and malformed-prefix cases.Persistence boundary — pair-aware strip (OpenCode + Pi)
stripPersistedAssistantText()intag-content-primitives.ts:^(§N§\s*)+runs§N§pairs (not§alone)§N">…hybrids (compartment/XML confusion)§after pair removaltext-complete.tsandpi-plugin/strip-tag-prefix.tsso assistant text is clean before jsonl persistence and Pi UI render.Transform boundary — § notation only
stripTagPrefix/prependTagstrip only leading §-shaped MC notation (well-formed + malformed). They do not strip bare leading digits.Temporal awareness
temporal-awareness.tsand Pitemporal-awareness-pi.tsuse sharedpeelLeadingMcTagNotation()so gap markers insert after malformed prefixes too, not only§N§regex matches.Out of scope (follow-up)
§(e.g.2030 2030 2030°with no section signs). New assistant completions with well-formed§N§pairs are cleaned at persistence; old residue may remain until rewritten.Test plan
bun test packages/plugin/src/hooks/magic-context/tag-content-primitives.test.tsbun test packages/plugin/src/hooks/magic-context/text-complete.test.tsbun test packages/plugin/src/hooks/magic-context/tool-drop-target.test.tsbun test packages/pi-plugin/src/strip-tag-prefix.test.ts99 files…/ numbered-list user text is preserved after transformCloses #97
Greptile Summary
This PR fixes two related failures caused by a mismatch between how Magic Context tags are injected at the transform layer and stripped at the persistence boundary. It introduces
stripPersistedAssistantTextas a shared pipeline (whole§N§pair removal, malformed hybrid removal, stray§cleanup, then trim) consumed by both OpenCode'stext-complete.tsand Pi'sstrip-tag-prefix.ts, and updateshasMeaningfulPartto runstripTagPrefixbefore emptiness checks so tag-only ghost messages are pruned after tool drops.hasMeaningfulPartnow callsstripTagPrefixbefore.trim().length > 0, correctly treating a part whose text is only§424§(or malformed§15298\">§15298§) as empty and removing the message.stripPersistedAssistantTextremoves whole§N§pairs globally (not bare§characters), eliminating digit residue that previously survived global§-only stripping and stacked on re-injection passes.stripTagPrefixandprependTagstill only strip leading§-shaped notation, explicitly preserving legitimate leading digits (99 files…,2024 roadmap, numbered lists).Confidence Score: 5/5
Safe to merge; changes are narrowly scoped to tag-stripping helpers and the emptiness check in
hasMeaningfulPart, all guarded by updated unit tests.The ghost-message fix in
hasMeaningfulPartis minimal and the logic is straightforward. The newstripPersistedAssistantTextpipeline replaces duplicate inline regexes in two places with a well-tested shared function. The transform-layer strip (stripTagPrefix) is deliberately unchanged for legitimate-digit preservation. Prior review concerns (trailing-space residue, missingbyteSize/isThinkingParttests, JSDoc placement) are all addressed in this revision.No files require special attention.
Important Files Changed
stripPersistedAssistantText(4-step pipeline) plus helper exports and a multi-pass loop instripTagPrefix. Implementation is correct and well-reasoned.hasMeaningfulPartnow callsstripTagPrefixbefore checking trimmed length, correctly identifying tag-only ghost messages as empty.stripPersistedAssistantText, centralising persistence-boundary logic.stripPersistedAssistantText, removing 60+ lines of duplicated logic.peelLeadingMcTagNotation, now also handling malformed prefixes.Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Assistant completion] -->|text| B[stripPersistedAssistantText] B --> B1["1. Strip leading well-formed runs"] B1 --> B2["2. Remove all complete pairs globally"] B2 --> B3["3. Remove malformed hybrids globally"] B3 --> B4["4. Remove stray section signs"] B4 --> B5["5. trim()"] B5 --> C[Clean persisted text] D["Tool drop hasMeaningfulPart"] -->|text part| E[stripTagPrefix leading only] E --> F{empty after trim?} F -- yes --> G[Remove ghost message] F -- no --> H[Keep message]Reviews (3): Last reviewed commit: "fix: address greptile review — trim pers..." | Re-trigger Greptile