@@ -67,6 +67,13 @@ def __call__(self, args, cwd=None, timeout=None):
6767 elif "+chat-list" in args :
6868 data = {"ok" : True , "data" : {"chats" : [{"chat_id" : chat , "name" : title }
6969 for chat , title in [("oc_community" , "Community trial" ), ("oc_second" , "Second trial" )]]}}
70+ elif "api" in args and "GET" in args :
71+ path = args [args .index ("GET" ) + 1 ]
72+ assert path .startswith ("/open-apis/im/v1/messages/" )
73+ message = dict (self .messages [path .rsplit ("/" , 1 )[- 1 ]])
74+ if message .get ("msg_type" ) == "text" and "content" in message :
75+ message ["body" ] = {"content" : json .dumps ({"text" : message .pop ("content" )})}
76+ data = {"code" : 0 , "data" : {"items" : [message ]}}
7077 elif "+messages-mget" in args :
7178 ref = args [args .index ("--message-ids" ) + 1 ]
7279 message = self .messages [ref ]
@@ -364,6 +371,106 @@ def test_group_readback_rejects_supplied_conflicting_ancestry(ordinary, field, v
364371 runtime .close ()
365372
366373
374+ def test_group_reply_uses_raw_ancestry_when_display_readback_omits_it (ordinary ): # noqa: F811
375+ _ , runtime , provider , transport = connect_group (ordinary )
376+ root = provider .topic ("display-root" , "Explain this project" )
377+ reply = provider .topic ("display-reply" , "Compare its configuration" , root = root ["message_id" ])
378+
379+ def rendered_provider (args , cwd = None , timeout = None ):
380+ result = provider (args , cwd , timeout )
381+ if "+messages-mget" in args :
382+ payload = json .loads (result ["stdout" ])
383+ for message in payload ["data" ]["items" ]:
384+ message = dict (message )
385+ message .pop ("root_id" , None )
386+ message .pop ("parent_id" , None )
387+ payload ["data" ]["items" ] = [message ]
388+ return {** result , "stdout" : json .dumps (payload )}
389+ return result
390+
391+ transport .runner = rendered_provider
392+ try :
393+ assert transport .admit ("notes-app" , root )["status" ] == "durably_accepted"
394+ first = finish_group_turn (runtime , transport , message = root ["content" ])
395+ assert transport .admit ("notes-app" , reply )["status" ] == "durably_accepted"
396+ second = finish_group_turn (runtime , transport , message = reply ["content" ])
397+ assert second ["session_id" ] == first ["session_id" ]
398+ assert all (topic == root ["message_id" ] for _ , topic , _ in provider .topic_writes )
399+ assert len ([text for _ , _ , text in provider .topic_writes if text == "Runtime response." ]) == 2
400+ finally :
401+ runtime .close ()
402+
403+
404+ @pytest .mark .parametrize ("failure" , ["unavailable" , "code_error" , "wrong_sender" , "wrong_chat" , "wrong_type" , "wrong_root" ])
405+ def test_group_raw_readback_failure_cannot_fall_back_to_display_authority (ordinary , failure ): # noqa: F811
406+ store , runtime , provider , transport = connect_group (ordinary )
407+ root = provider .topic ("raw-root" , "Explain this project" )
408+ reply = provider .topic ("raw-reply" , "Compare its configuration" , root = root ["message_id" ])
409+
410+ def conflicting_provider (args , cwd = None , timeout = None ):
411+ result = provider (args , cwd , timeout )
412+ if "api" in args and "GET" in args :
413+ if failure == "unavailable" :
414+ return {"returncode" : 1 , "stdout" : '{"code":999}' , "stderr" : "" }
415+ if failure == "code_error" :
416+ return {** result , "stdout" : json .dumps ({** json .loads (result ["stdout" ]), "code" : 999 })}
417+ payload = json .loads (result ["stdout" ])
418+ message = dict (payload ["data" ]["items" ][0 ])
419+ message .update ({"wrong_sender" : {"sender" : {"id" : "ou_other" , "sender_type" : "user" }},
420+ "wrong_chat" : {"chat_id" : "oc_other" }, "wrong_type" : {"msg_type" : "image" },
421+ "wrong_root" : {"root_id" : "om_other_root" }}[failure ])
422+ payload ["data" ]["items" ] = [message ]
423+ return {** result , "stdout" : json .dumps (payload )}
424+ return result
425+
426+ transport .runner = conflicting_provider
427+ try :
428+ assert transport .admit ("notes-app" , reply )["status" ] == "source_verification_failed"
429+ assert not store .list_sessions () and not list (transport .root .glob ("*.json" ))
430+ assert not provider .writes and not provider .reaction_creates
431+ finally :
432+ runtime .close ()
433+
434+
435+ @pytest .mark .parametrize ("kind" , ["image" , "post" ])
436+ def test_group_raw_provenance_preserves_rendered_media_and_original_topic (ordinary , kind ): # noqa: F811
437+ from test_lark_private_images import image_runner
438+ from test_chat_image_attachments import PNG_DATA_URL
439+
440+ _ , runtime , provider , transport = connect_group (ordinary )
441+ root = provider .topic ("media-root" , "Explain this project" )
442+ media = provider .topic ("media-reply" , "Inspect this diagram\n " , root = root ["message_id" ])
443+ media ["message_type" ] = kind
444+ provider .messages [media ["message_id" ]]["msg_type" ] = kind
445+ download = image_runner (provider )
446+
447+ def raw_media_provider (args , cwd = None , timeout = None ):
448+ result = download (args , cwd , timeout )
449+ if "api" in args and "GET" in args :
450+ payload = json .loads (result ["stdout" ])
451+ message = payload ["data" ]["items" ][0 ]
452+ if message .get ("msg_type" ) == kind :
453+ message .pop ("content" )
454+ body = {"image_key" : "img_example" } if kind == "image" else {
455+ "zh_cn" : {"title" : "" , "content" : [[{"tag" : "text" , "text" : "Inspect this diagram" },
456+ {"tag" : "img" , "image_key" : "img_example" }]]}}
457+ message ["body" ] = {"content" : json .dumps (body )}
458+ return {** result , "stdout" : json .dumps (payload )}
459+ return result
460+
461+ transport .runner = raw_media_provider
462+ try :
463+ assert transport .admit ("notes-app" , root )["status" ] == "durably_accepted"
464+ first = finish_group_turn (runtime , transport , message = root ["content" ])
465+ assert transport .admit ("notes-app" , media )["status" ] == "durably_accepted"
466+ second = finish_group_turn (runtime , transport , message = "Inspect this diagram\n [图片 1]" )
467+ assert second ["session_id" ] == first ["session_id" ]
468+ assert second ["attachments" ][0 ]["data_url" ] == PNG_DATA_URL
469+ assert all (topic == root ["message_id" ] for _ , topic , _ in provider .topic_writes )
470+ finally :
471+ runtime .close ()
472+
473+
367474def test_group_status_and_recipient_commands_cannot_expose_private_sessions (ordinary ): # noqa: F811
368475 store , runtime , provider , transport = connect_group (ordinary )
369476 try :
0 commit comments