Skip to content

fix: retry whenever a DSML residual leaks into content - #836

Open
songji-tian wants to merge 1 commit into
lsdefine:mainfrom
songji-tian:fix/dsml-residual-detection
Open

songji-tian wants to merge 1 commit into
lsdefine:mainfrom
songji-tian:fix/dsml-residual-detection

Conversation

@songji-tian

Copy link
Copy Markdown

Problem

When the server-side DSML -> tool_calls parser fails to convert the whole tool call, it can leave an untranslated tail in message.content and return no tool_calls. The turn then ends as a plain text reply: no tool runs, no error is raised, and the agent silently stalls.

The current guard only matches one exact form:

if content.rstrip().endswith('</|DSML| calls>'):

Real leaks (14 stalled rolls out of 18 sampled agent transcripts, DeepSeek official endpoint) end with other forms, so the guard never fires:

leaked tail current check
</|DSML| calls> fires
</||DSML|| parameter> misses
</|DSML| parameter> misses
</|DSML| invoke> misses
`...parameter>
</code_run>` misses

Measured on those 14 rolls: current check 0/14, this patch 14/14.

Change (1 line, net zero)

-        if content.rstrip().endswith('</|DSML| calls>'):
+        if 'DSML' in content[-200:] and re.search(r'</[^>]*>\s*$', content.rstrip()):

The 'DSML' in content[-200:] guard keeps it conservative: the leak marker must still be present in the tail, so a normal answer that happens to end with </code_run> is not retried.

Verification

  • 14 real stalled rolls: 0/14 before, 14/14 after.
  • 54 normal text-only rolls / 1960 historical responses: 0 false positives.
  • Retry is effective: 19/19 leaked turns returned a proper tool_calls on the next attempt.

Related: #804 (same leak, closed as an upstream serving-side issue).

Co-Authored-By: GenericAgent bot@gaagent.ai

The server-side DSML->tool_calls parser sometimes leaves an untranslated
tail in `content` and returns no `tool_calls`, e.g. `</|DSML| invoke>`,
`</||DSML|| parameter>` or a leaked `</code_run>`. The turn then ends as a
plain text reply and the agent silently stalls - no tool runs, no error.

The existing guard only matches `</|DSML| calls>`, a form real leaks
almost never end with (0/14 in sampled transcripts). Match any trailing
closed tag while still requiring the DSML marker in the last 200 chars:
14/14 caught, 0 false positives across 1960 historical responses. Retry
recovers the turn (19/19 leaked turns returned proper tool_calls next try).

Co-Authored-By: GenericAgent <bot@gaagent.ai>
@ZhulongNT

Copy link
Copy Markdown
Contributor

Related: I ran into the same leak and opened #837 with a fix in #838 - it attacks the marker matching itself (variant-agnostic regex + a stateful filter that re-joins markers split across stream chunks) instead of only checking the content tail, so a leak anywhere in the turn and closing tags such as </||DSML|| parameter> are handled too. Your #836 covers the retry side; if you want, feel free to fold the two together.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants