fix(errors): prevent billing false positive in sanitizeUserFacingText#13467
fix(errors): prevent billing false positive in sanitizeUserFacingText#13467lailoo wants to merge 3 commits intoopenclaw:mainfrom
Conversation
| const hasMultipleSentences = /[.!?]\s+[A-Z]/.test(raw); | ||
| const hasMarkdown = /[*_#[\]|]/.test(raw); | ||
| const hasParagraphs = raw.includes("\n\n"); | ||
| return !hasMultipleSentences && !hasMarkdown && !hasParagraphs; |
There was a problem hiding this comment.
Lowercase sentence false positive
hasMultipleSentences uses /[.!?]\s+[A-Z]/ (errors.ts:169), so multi-sentence prose where the next sentence starts lowercase (e.g., "... . payment is ...") is treated as single-sentence and will still be rewritten if it matches the broad billing heuristic. This undermines the goal of not rewriting assistant prose; consider using a sentence boundary check that doesn’t rely on capitalization (or a different prose-vs-error heuristic).
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-helpers/errors.ts
Line: 169:172
Comment:
**Lowercase sentence false positive**
`hasMultipleSentences` uses `/[.!?]\s+[A-Z]/` (errors.ts:169), so multi-sentence prose where the next sentence starts lowercase (e.g., "... . payment is ...") is treated as single-sentence and will still be rewritten if it matches the broad billing heuristic. This undermines the goal of not rewriting assistant prose; consider using a sentence boundary check that doesn’t rely on capitalization (or a different prose-vs-error heuristic).
How can I resolve this? If you propose a fix, please make it concise.| // Single-sentence short texts without markdown are likely error messages. | ||
| const hasMultipleSentences = /[.!?]\s+[A-Z]/.test(raw); | ||
| const hasMarkdown = /[*_#[\]|]/.test(raw); | ||
| const hasParagraphs = raw.includes("\n\n"); | ||
| return !hasMultipleSentences && !hasMarkdown && !hasParagraphs; |
There was a problem hiding this comment.
One-sentence prose still rewritten
The fallback return !hasMultipleSentences && !hasMarkdown && !hasParagraphs; (errors.ts:168-172) will rewrite any single-sentence assistant content that happens to contain billing plus payment/upgrade/credits/plan (the broad heuristic). If the intent is to only rewrite raw error strings on the broad path, this condition is too permissive; a one-sentence paragraph of prose will be replaced by BILLING_ERROR_USER_MESSAGE.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-helpers/errors.ts
Line: 168:172
Comment:
**One-sentence prose still rewritten**
The fallback `return !hasMultipleSentences && !hasMarkdown && !hasParagraphs;` (errors.ts:168-172) will rewrite any single-sentence assistant content that happens to contain `billing` plus `payment/upgrade/credits/plan` (the broad heuristic). If the intent is to only rewrite raw error strings on the broad path, this condition is too permissive; a one-sentence paragraph of prose will be replaced by `BILLING_ERROR_USER_MESSAGE`.
How can I resolve this? If you propose a fix, please make it concise.6c5aa15 to
3b6fe1f
Compare
…xt per Greptile feedback (openclaw#13434)
3b6fe1f to
9e04f79
Compare
bfc1ccb to
f92900f
Compare
Summary
Fixes #13434
Problem
sanitizeUserFacingText()unconditionally appliesisBillingErrorMessage()to all user-facing text. TheisBillingErrorMessagefunction uses a broad heuristic that matches any text containing both "billing" and one of "payment", "upgrade", "credits", or "plan". This causes assistant-generated content discussing billing/payment topics (e.g., gym membership billing details) to be replaced with the generic billing error warning.Fix
Add a
shouldRewriteBillingText()guard function (matching the existingshouldRewriteContextOverflowText()pattern) that distinguishes real billing errors from assistant prose:402,insufficient credits,credit balance,payment required,plans & billing) are rewritten unconditionally — these are unambiguous error strings.billing + payment/upgrade/credits/plan) are only rewritten when the text looks like a raw error message (API payload, HTTP error, error prefix, or single-sentence without markdown/paragraphs).Reproduction & Verification
Unit-level (direct function call):
Before fix (main branch) — Bug reproduced:
After fix — All verified:
Integration-level (real gateway reply pipeline):
Added
normalizeReplyPayloadintegration tests insrc/auto-reply/reply/normalize-reply.test.tsthat exercise the full reply normalization pipeline (normalizeReplyPayload→sanitizeUserFacingText):Before fix (main branch) — Bug reproduced through real pipeline:
After fix — Pipeline preserves assistant content:
Effect on User Experience
Before fix:⚠️ API provider returned a billing error" instead of actual findings.
Sub-agent researches gym membership details → output contains "Billing: ... payments" → parent receives "
After fix:
Assistant content discussing billing/payment topics is delivered as-is. Real billing errors (402, insufficient credits, etc.) are still correctly caught and rewritten.
Testing
sanitizeuserfacingtext.test.ts)normalizeReplyPayloadpipeline innormalize-reply.test.ts)isBillingErrorMessage()unchanged — error classification for failover/logging still works