Skip to content

fix: retry text-only on image schema errors#8500

Open
he-yufeng wants to merge 1 commit into
AstrBotDevs:masterfrom
he-yufeng:fix/non-vision-image-history
Open

fix: retry text-only on image schema errors#8500
he-yufeng wants to merge 1 commit into
AstrBotDevs:masterfrom
he-yufeng:fix/non-vision-image-history

Conversation

@he-yufeng
Copy link
Copy Markdown
Contributor

@he-yufeng he-yufeng commented Jun 2, 2026

Summary

To verify

  • uv run --dev pytest tests\test_openai_source.py::test_handle_api_error_unsupported_image_content_retries_text_only tests\test_openai_source.py::test_handle_api_error_invalid_attachment_removes_images_and_retries_text_only -q --basetemp .tmp\pytest
  • uv run --dev ruff check astrbot\core\provider\sources\openai_source.py tests\test_openai_source.py
  • uv run --dev ruff format --check astrbot\core\provider\sources\openai_source.py tests\test_openai_source.py
  • uv run --dev python -m py_compile astrbot\core\provider\sources\openai_source.py tests\test_openai_source.py
  • git diff --check

Fixes #8489

Summary by Sourcery

Handle OpenAI-compatible schema errors for image content by falling back to text-only retries using the existing image-removal path.

Bug Fixes:

  • Treat DeepSeek-style unknown variant image_url, expected text schema errors as unsupported image content and retry the request without images.

Enhancements:

  • Introduce a helper to detect unsupported image content errors based on provider error messages and reuse the existing image-removal retry flow.

Tests:

  • Add a regression test ensuring unsupported image_url schema errors trigger a text-only retry via image removal.

@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. labels Jun 2, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a mechanism to detect and handle unsupported image content errors from OpenAI-compatible providers. It adds the _is_unsupported_image_content_error method to identify these errors and updates _handle_api_error to fall back to text-only payloads and retry. A corresponding unit test has also been added. The review feedback suggests improving the robustness of the error string matching in _is_unsupported_image_content_error by normalizing different quote characters (backticks, single quotes, double quotes) before checking for "expected text" to handle varying provider error formats.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +196 to +205
def _is_unsupported_image_content_error(self, error: Exception) -> bool:
for text in self._extract_error_text_candidates(error):
text = text.lower()
if "image_url" not in text:
continue
if "unknown variant" in text or "expected `text`" in text:
return True
if "expected text" in text:
return True
return False
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The current implementation checks for expected text with backticks and expected text without quotes separately. However, if another OpenAI-compatible provider returns single quotes (e.g., expected 'text') or double quotes (e.g., expected "text"), the substring check "expected text" in text will fail because of the intervening quote characters.

To make this check robust across different providers and quoting styles, we can normalize the error text by removing backticks, single quotes, and double quotes before performing the substring checks. We can use chr(96) to represent the backtick character safely.

Suggested change
def _is_unsupported_image_content_error(self, error: Exception) -> bool:
for text in self._extract_error_text_candidates(error):
text = text.lower()
if "image_url" not in text:
continue
if "unknown variant" in text or "expected `text`" in text:
return True
if "expected text" in text:
return True
return False
def _is_unsupported_image_content_error(self, error: Exception) -> bool:
for text in self._extract_error_text_candidates(error):
text = text.lower()
if "image_url" not in text:
continue
# Normalize quotes and backticks to handle different provider error formats robustly
normalized = text.replace(chr(96), "").replace("'", "").replace('"', "")
if "unknown variant" in normalized or "expected text" in normalized:
return True
return False

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • In _is_unsupported_image_content_error, consider consolidating the multiple string checks for the expected text variants into a single, clearer condition (e.g., using a small helper or regex) so the matching logic is easier to follow and extend if providers change wording slightly.
  • The new _is_unsupported_image_content_error and the existing _is_invalid_attachment_error both iterate over _extract_error_text_candidates; you might factor out a small shared helper for scanning error texts to keep the error-type predicates lean and reduce duplication if you add more cases later.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `_is_unsupported_image_content_error`, consider consolidating the multiple string checks for the `expected text` variants into a single, clearer condition (e.g., using a small helper or regex) so the matching logic is easier to follow and extend if providers change wording slightly.
- The new `_is_unsupported_image_content_error` and the existing `_is_invalid_attachment_error` both iterate over `_extract_error_text_candidates`; you might factor out a small shared helper for scanning error texts to keep the error-type predicates lean and reduce duplication if you add more cases later.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@he-yufeng he-yufeng force-pushed the fix/non-vision-image-history branch from 2bf4cc0 to 30cd16a Compare June 2, 2026 03:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider The bug / feature is about AI Provider, Models, LLM Agent, LLM Agent Runner. size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]关于更新V4.25.2新版本之后,使用DeepSeek V4 pro(非多模态)模型时,图片消息导致API 400报错

1 participant