Bug Description
stripHallucinations runs at the start of each createChatMessageTransformHandler cycle (line 7444), before injectMessageIds (line 7468). But it operates on ALL messages — including prior turns that already had <dcp-message-id>mXXXX</dcp-message-id> appended by the previous cycle's injectMessageIds.
If a prior assistant message contains <dcp-message-id> anywhere in its text content (e.g., the model mentioned the tag name), DCP_PAIRED_TAG_REGEX treats the injected closing tag at the end of the message as the closing match. Everything between the in-content opening tag and the injected closing tag is deleted.
Reproduced with node:
constDCP_PAIRED_TAG_REGEX=/<dcp[^>]*>[\s\S]*?<\/dcp[^>]*>/gi;constDCP_UNPAIRED_TAG_REGEX=/<\/?dcp[^>]*>/gi;constinput='The tag called `<dcp-message-id>` is used to track messages. '+'This text should survive.\n\n'+'<dcp-message-id>m0369</dcp-message-id>';constresult=input.replace(DCP_PAIRED_TAG_REGEX,'').replace(DCP_UNPAIRED_TAG_REGEX,'');// result: "The tag called `"// Everything after the in-content tag is gone.
Expected Behavior
Content after an in-text DCP tag mention should not be deleted. Only hallucinated tag pairs that are entirely within the generated content should be stripped.
Debug Context Logs
{
"role": "assistant",
"parts": [
{
"type": "text",
"text": "The tag called `"
}
]
}
*(Full content truncated — all text after the tag mention is gone, including the rest of the sentence and subsequent paragraphs)*Tool Call Details
No response
DCP Version
3.1.12
Opencode Version
1.15.12
Model
Claude Sonnet 4
Additional Context
Add one pre-processing step in stripHallucinationsFromString to remove the legitimately injected message ID suffix before running the paired regex. The injected tag can't then act as a false closing match. injectMessageIds re-adds it later in the same cycle.
// New constant:constINJECTED_TAG_SUFFIX_REGEX=/\n<dcp-message-id>m\d+<\/dcp-message-id>\s*$/;// Updated function (one new line, existing replaces unchanged):varstripHallucinationsFromString=(text)=>{constsafe=text.replace(INJECTED_TAG_SUFFIX_REGEX,"");returnsafe.replace(DCP_PAIRED_TAG_REGEX,"").replace(DCP_UNPAIRED_TAG_REGEX,"");};This is additive — the existing two .replace() calls are unchanged.
Bug Description
stripHallucinationsruns at the start of eachcreateChatMessageTransformHandlercycle (line 7444), beforeinjectMessageIds(line 7468). But it operates on ALL messages — including prior turns that already had<dcp-message-id>mXXXX</dcp-message-id>appended by the previous cycle'sinjectMessageIds.If a prior assistant message contains
<dcp-message-id>anywhere in its text content (e.g., the model mentioned the tag name),DCP_PAIRED_TAG_REGEXtreats the injected closing tag at the end of the message as the closing match. Everything between the in-content opening tag and the injected closing tag is deleted.Reproduced with node:
Expected Behavior
Content after an in-text DCP tag mention should not be deleted. Only hallucinated tag pairs that are entirely within the generated content should be stripped.
Debug Context Logs
{ "role": "assistant", "parts": [ { "type": "text", "text": "The tag called `" } ] } *(Full content truncated — all text after the tag mention is gone, including the rest of the sentence and subsequent paragraphs)*Tool Call Details
No response
DCP Version
3.1.12
Opencode Version
1.15.12
Model
Claude Sonnet 4
Additional Context
Add one pre-processing step in
stripHallucinationsFromStringto remove the legitimately injected message ID suffix before running the paired regex. The injected tag can't then act as a false closing match.injectMessageIdsre-adds it later in the same cycle.This is additive — the existing two
.replace()calls are unchanged.