Skip to content

Stop FastAgent loops on malformed tool calls - #411

Merged
RasulOs merged 2 commits into
mainfrom
fix/deepseek-malformed-tool-call-guard
Aug 3, 2026
Merged

Stop FastAgent loops on malformed tool calls#411
RasulOs merged 2 commits into
mainfrom
fix/deepseek-malformed-tool-call-guard

Conversation

@RasulOs

@RasulOs RasulOs commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • classify FastAgent responses internally as valid, ordinary no-markup, or malformed while preserving the public parse_tool_calls() tuple interface
  • give the first two consecutive malformed responses a focused ASCII-XML correction, then stop unsuccessfully on the third before another model request
  • reset the malformed streak after valid calls or ordinary prose, and keep the existing generic no-tool feedback for prose
  • reject observed full-width-bar DSML sentinels before parameter sanitization so malformed provider markup cannot become executable
  • preserve valid sibling blocks, valid-call execution, provider loaders, prompts, public configuration, and max_steps

Why

DeepSeek V4 Flash can mix MobileRun's prompt-based XML with provider-specific DSML markers. Those responses either produce zero executable calls or can corrupt XML parameter structure. With an unchanged device state, repeated generic retries can become a long loop.

This is deliberately provider-neutral containment. It does not add native DeepSeek tools, normalize DSML, or change healthy tool-call behavior. The three-failure threshold preserves the two-response recovery observed in streaming validation.

Tests

  • targeted parser/workflow tests: 36 passed
  • full test suite: 482 passed
  • Ruff on all changed files: passed
  • Black check across the repository: 164 files unchanged
  • git diff --check: passed
  • repository-wide Ruff was also run; it reports 9 pre-existing import-order/unused-import findings in untouched files

Fixtures and workflow coverage include the Discord response, captured hybrid DSML forms, DSML inside a parameter, missing wrappers, empty wrappers, plain prose, valid XML, mixed valid/malformed siblings, two-failure recovery, counter resets, the third-failure terminal event, and proof that no fourth request occurs.

Android validation

Validated direct deepseek-v4-flash on the cold-booted Android 16/API 36 Medium_Phone_API_36.1 AVD with Portal v0.7.22 over local ADB/ContentProvider transport:

  • non-streaming: completed 45 responses and 21 observed cycles; 2 malformed responses executed zero calls and recovered
  • streaming: earlier malformed responses recovered, then responses 8–10 were three consecutive malformed calls; each parsed/executed zero calls, the screen remained unchanged, the third response ended the run, and no request followed
  • provider SSE, LlamaIndex assembly, and FastAgent content matched for all 55 replacement responses
  • cumulative conservative spend across validation attempts: $0.1154716864 under the $1 cap
  • Portal remained installed with accessibility enabled; no HTTP forwarding was created; the emulator was returned to its initially stopped state

Redacted evidence was kept outside the repository and no API keys, request headers, or emulator artifacts are committed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79b819d5b6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread mobilerun/agent/fast_agent/xml_parser.py Outdated

RasulOs commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2c0271dd88

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +238 to +239
if _PARAM_OPEN_RE.search(payload):
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve DSML alongside parameter-like payload text

When a legitimate parameter value contains both literal DSML and parameter-like text—for example, type_text with Example: <parameter name="x"> then <|DSML|parameter>—this nested-opener check excludes the entire canonical payload span, so the subsequent DSML scan classifies the valid call as malformed and the agent eventually aborts without typing it. Fresh evidence in the updated code is that literal DSML alone is now preserved, but combining it with the raw <parameter...> content that _sanitize_param_content otherwise supports still triggers the same failure; avoid treating every nested parameter opener as proof that the regex crossed a corrupted boundary.

Useful? React with 👍 / 👎.

@RasulOs
RasulOs merged commit ff7e9d1 into main Aug 3, 2026
8 of 9 checks passed
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.

1 participant