@@ -962,6 +962,59 @@ async def test_cmd_compress_error(self):
962962
963963 mock_err .assert_called_once ()
964964
965+ @pytest .mark .asyncio
966+ async def test_compress_strips_multimodal_content (self ):
967+ """多模态消息中的 base64 图片/视频块应在压缩时被过滤,只保留文本块。"""
968+ repl = ChatREPL ()
969+ repl .model_config = {"model" : "gpt-4" }
970+ repl .agent = Mock ()
971+ repl .agent .aget_state = AsyncMock ()
972+ # 构造包含多模态 content 的消息
973+ multimodal_msg = HumanMessage (
974+ content = [
975+ {"type" : "text" , "text" : "[image: test.png] 描述这张图" },
976+ {"type" : "image_url" , "image_url" : {"url" : "data:image/png;base64,AAAA" }},
977+ ],
978+ id = "1" ,
979+ )
980+ text_msg = HumanMessage ("普通文本消息" , id = "2" )
981+ state = Mock ()
982+ state .values = {"messages" : [multimodal_msg , text_msg ]}
983+ repl .agent .aget_state .return_value = state
984+ repl .agent .aupdate_state = AsyncMock ()
985+ repl .session_mgr = Mock ()
986+ repl .session_mgr .config = {}
987+
988+ captured_pre_messages = None
989+
990+ def capture_invoke (func , messages , * args ):
991+ nonlocal captured_pre_messages
992+ captured_pre_messages = messages
993+ mock_resp = Mock ()
994+ mock_resp .content = '{"summary": "ok"}'
995+ return mock_resp
996+
997+ with patch ("chcode.chat.confirm" , new_callable = AsyncMock , return_value = True ):
998+ with patch ("chcode.chat.render_info" ):
999+ with patch ("chcode.utils.enhanced_chat_openai.EnhancedChatOpenAI" ) as mock_llm :
1000+ mock_inst = Mock ()
1001+ mock_inst .invoke = Mock (side_effect = capture_invoke )
1002+ mock_llm .return_value = mock_inst
1003+ with patch ("chcode.chat.asyncio.to_thread" , new_callable = AsyncMock , side_effect = capture_invoke ):
1004+ with patch .object (repl , "_load_conversation" , new_callable = AsyncMock ):
1005+ with patch ("chcode.chat.render_success" ):
1006+ await repl ._cmd_compress ("" )
1007+
1008+ # 验证发给模型的消息中,多模态块已被过滤
1009+ for msg in captured_pre_messages :
1010+ if isinstance (msg .content , list ):
1011+ for block in msg .content :
1012+ if isinstance (block , dict ):
1013+ assert block ["type" ] not in ("image_url" , "video_url" ), \
1014+ f"多模态块未被过滤: { block ['type' ]} "
1015+ # 验证原始消息未被修改(content 仍包含 image_url)
1016+ assert multimodal_msg .content [1 ]["type" ] == "image_url"
1017+
9651018
9661019# ============================================================================
9671020# Test ChatREPL._cmd_messages
0 commit comments