oclaw/tests/test_openai_chat_multimodal_downgrade.py
oliver d1bcc4debe feat: multimodal image clients, workspaces, Tushare skill, test fixes
- Replace monolithic image_message_client with HTTP/OCR/legacy modules; tighten OpenAI transport + tool schemas for multimodal downgrade to OCR specialist path.
- Add image/stock workspace prompts (META/SOUL/ROLE_SYSTEM); register experts; tweak specialist agent/direct loop/query_image_attachment.
- Add bundled runtime/skills/tushare-finance (references, api_client, SKILL metadata).
- Document OCR-related env vars; admin chat tweaks; README; weixin_install Ensure-OfficialPluginRuntimeDeps helper.
- Tests: multimodal downgrade + OCR coverage, strict tool pairing in attachment replay guard, workspace contract skips _internal/_system dirs, router/trace/prompt guards.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 04:41:42 +08:00

45 lines
1.7 KiB
Python

from __future__ import annotations
from oclaw.platform.llm.transports.openai_chat_completions import (
_is_text_only_gateway_error,
_messages_contain_list_with_image,
_should_proactively_downgrade_multimodal_messages,
_wire_error_message,
)
def test_text_only_gateway_error_matches_deepseek_deserialize() -> None:
msg = "messages[1]: unknown variant image_url, expected text at line 1 column 74402"
assert _is_text_only_gateway_error(msg)
def test_text_only_gateway_error_from_nested_body() -> None:
snippet = '{"error":{"message":"Failed to deserialize: unknown variant image_url, expected text"}}'
assert _is_text_only_gateway_error(snippet)
def test_messages_contain_list_with_image() -> None:
msgs = [
{"role": "user", "content": [{"type": "text", "text": "hi"}, {"type": "image_url", "image_url": {"url": "x"}}]},
]
assert _messages_contain_list_with_image(msgs)
assert _should_proactively_downgrade_multimodal_messages(msgs, model="deepseek-chat", base_url="https://api.example.com/")
assert not _should_proactively_downgrade_multimodal_messages(
msgs, model="gpt-4o-mini", base_url="https://api.openai.com/v1/"
)
class _Bare400(Exception):
def __init__(self) -> None:
super().__init__("Error code: 400")
self.body = {
"error": {
"message": "Failed to deserialize: messages[1]: unknown variant image_url, expected text",
"type": "invalid_request_error",
},
}
def test_wire_error_message_includes_exception_body_json() -> None:
wired = _wire_error_message(_Bare400())
assert _is_text_only_gateway_error(wired)