Skip to content
14 changes: 14 additions & 0 deletions open-sse/translator/deepseekWebTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,20 @@ export function parseDeepSeekToolCalls(
return { content: text ?? "", toolCalls: null };
}

// Normalize DeepSeek V4 DSML markup (<||DSML|| ...>) into canonical tool tags
text = text
.replace(/This response is AI-generated, for reference only\./g, "")
.replace(/<\/?(?:[||]{1,2})DSML(?:[||]{1,2})\s*(?:calls|tool_calls)>/gi, "")
.replace(/<(\/?)(?:(?:[||]{1,2})DSML(?:[||]{1,2})\s*)?invoke\b/gi, "<$1tool")
.replace(/<(\/?)(?:(?:[||]{1,2})DSML(?:[||]{1,2})\s*)?parameter\b/gi, "<$1parameter")
.replace(/(}\s*)<\/(?:parameter|invoke|arguments|calls|tool_calls)>/gi, "$1")
.trim();

// If model emitted bare <parameter> tags without enclosing <tool> or <invoke>
if (/<parameter\b/i.test(text) && !/<tool\b/i.test(text)) {
text = text.replace(/((?:<parameter\b[\s\S]*?<\/parameter>\s*)+)/gi, "<tool>$1</tool>");
}

const tokens = tokenizeToolTags(text);
if (tokens.length === 0) {
// No DeepSeek-specific tags — defer to the proven canonical parser (bare JSON, etc.).
Expand Down