Stop FastAgent loops on malformed tool calls - #411
Conversation
There was a problem hiding this comment.
💡 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".
|
@codex review |
There was a problem hiding this comment.
💡 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".
| if _PARAM_OPEN_RE.search(payload): | ||
| continue |
There was a problem hiding this comment.
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 👍 / 👎.
Summary
parse_tool_calls()tuple interfacemax_stepsWhy
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
git diff --check: passedFixtures 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-flashon the cold-booted Android 16/API 36Medium_Phone_API_36.1AVD with Portal v0.7.22 over local ADB/ContentProvider transport:Redacted evidence was kept outside the repository and no API keys, request headers, or emulator artifacts are committed.