@@ -593,6 +593,264 @@ public async Task BasicRequestResponse_Streaming()
593593 Assert . Equal ( 36 , usage . Details . TotalTokenCount ) ;
594594 }
595595
596+ [ Fact ]
597+ public async Task MissingAbstractionResponse_NonStreaming ( )
598+ {
599+ const string Input =
600+ """
601+ {
602+ "model": "computer-use-preview",
603+ "reasoning": {
604+ "summary": "concise"
605+ },
606+ "tools": [
607+ {
608+ "type": "computer_use_preview",
609+ "environment": "browser",
610+ "display_width": 1024,
611+ "display_height": 768
612+ }
613+ ],
614+ "truncation": "auto",
615+ "input": [
616+ {
617+ "type": "message",
618+ "role": "user",
619+ "content": [
620+ {
621+ "type": "input_text",
622+ "text": "Search the web for the temperature today in Fremont"
623+ }
624+ ]
625+ }
626+ ]
627+ }
628+ """ ;
629+
630+ const string Output =
631+ """
632+ {
633+ "id": "resp_67d327649b288191aeb46a824e49dc40058a5e08c46a181d",
634+ "object": "response",
635+ "created_at": 1741891428,
636+ "status": "completed",
637+ "error": null,
638+ "incomplete_details": null,
639+ "instructions": null,
640+ "max_output_tokens": 20,
641+ "model": "computer-use-preview-2025-03-11",
642+ "output": [
643+ {
644+ "type": "reasoning",
645+ "id": "rs_67cc...",
646+ "summary": [
647+ {
648+ "type": "summary_text",
649+ "text": "Clicking on the browser address bar."
650+ }
651+ ]
652+ },
653+ {
654+ "type": "computer_call",
655+ "id": "cu_67cc...",
656+ "call_id": "call_zw3...",
657+ "action": {
658+ "type": "click",
659+ "button": "left",
660+ "x": 156,
661+ "y": 50
662+ },
663+ "pending_safety_checks": [],
664+ "status": "completed"
665+ }
666+ ],
667+ "parallel_tool_calls": true,
668+ "previous_response_id": null,
669+ "reasoning": {
670+ "generate_summary": "concise"
671+ },
672+ "store": true,
673+ "temperature": 1.0,
674+ "text": {
675+ "format": {
676+ "type": "text"
677+ }
678+ },
679+ "tool_choice": "auto",
680+ "tools": [],
681+ "top_p": 1.0,
682+ "usage": {
683+ "input_tokens": 18,
684+ "input_tokens_details": {
685+ "cached_tokens": 0
686+ },
687+ "output_tokens": 53,
688+ "output_tokens_details": {
689+ "reasoning_tokens": 12
690+ },
691+ "total_tokens": 71
692+ },
693+ "user": null,
694+ "metadata": {}
695+ }
696+ """ ;
697+
698+ using VerbatimHttpHandler handler = new ( Input , Output ) ;
699+ using HttpClient httpClient = new ( handler ) ;
700+ using IChatClient client = CreateResponseClient ( httpClient , "computer-use-preview" ) ;
701+
702+ var responseCreationOptions =
703+ new ResponseCreationOptions
704+ {
705+ TruncationMode = ResponseTruncationMode . Auto ,
706+ ReasoningOptions = new ( )
707+ {
708+ ReasoningSummaryVerbosity = ResponseReasoningSummaryVerbosity . Concise
709+ } ,
710+ Tools =
711+ {
712+ ResponseTool . CreateComputerTool ( ComputerToolEnvironment . Browser , 1024 , 768 ) ,
713+ }
714+ } ;
715+ var chatOptions =
716+ new ChatOptions
717+ {
718+ RawRepresentationFactory = options => responseCreationOptions
719+ } ;
720+ var response = await client . GetResponseAsync ( [ new ChatMessage ( ChatRole . User , "Search the web for the temperature today in Fremont" ) ] , chatOptions ) ;
721+ Assert . NotNull ( response ) ;
722+
723+ Assert . Equal ( "resp_67d327649b288191aeb46a824e49dc40058a5e08c46a181d" , response . ResponseId ) ;
724+ Assert . Equal ( "resp_67d327649b288191aeb46a824e49dc40058a5e08c46a181d" , response . ConversationId ) ;
725+ Assert . Empty ( response . Text ) ;
726+ Assert . Equal ( "computer-use-preview-2025-03-11" , response . ModelId ) ;
727+ Assert . Equal ( DateTimeOffset . FromUnixTimeSeconds ( 1_741_891_428 ) , response . CreatedAt ) ;
728+ Assert . Null ( response . FinishReason ) ;
729+ ChatMessage responseMessage = Assert . Single ( response . Messages ) ;
730+ Assert . Equal ( ChatRole . Assistant , responseMessage . Role ) ;
731+ Assert . Equal ( 2 , responseMessage . Contents . Count ) ;
732+ Assert . Single ( responseMessage . Contents , content => content is TextReasoningContent ) ;
733+ AIContent computerUserItem = Assert . Single ( responseMessage . Contents , content => content . GetType ( ) == typeof ( AIContent ) ) ;
734+ Assert . NotNull ( computerUserItem . RawRepresentation ) ;
735+ Assert . IsType < ComputerCallResponseItem > ( computerUserItem . RawRepresentation ) ;
736+ Assert . NotNull ( response . Usage ) ;
737+ Assert . Equal ( 18 , response . Usage . InputTokenCount ) ;
738+ Assert . Equal ( 53 , response . Usage . OutputTokenCount ) ;
739+ Assert . Equal ( 71 , response . Usage . TotalTokenCount ) ;
740+ }
741+
742+ [ Fact ]
743+ public async Task MissingAbstractionResponse_Streaming ( )
744+ {
745+ const string Input =
746+ """
747+ {
748+ "model": "computer-use-preview",
749+ "reasoning": {
750+ "summary": "concise"
751+ },
752+ "tools": [
753+ {
754+ "type": "computer_use_preview",
755+ "environment": "browser",
756+ "display_width": 1024,
757+ "display_height": 768
758+ }
759+ ],
760+ "truncation": "auto",
761+ "input": [
762+ {
763+ "type": "message",
764+ "role": "user",
765+ "content": [
766+ {
767+ "type": "input_text",
768+ "text": "Search the web for the temperature today in Fremont"
769+ }
770+ ]
771+ }
772+ ],
773+ "stream":true
774+ }
775+ """ ;
776+
777+ const string Output =
778+ """
779+ event: response.created
780+ data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_0b949080ec8e4b8a006920e0661d00819383ed81438ab11299","object":"response","created_at":1763762278,"status":"in_progress","background":false,"content_filters":null,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"computer-use-preview-2025-03-11","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","generate_summary":"concise","summary":"concise"},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":null,"tools":[{"type":"computer-use-preview-2025-03-11","environment":"browser","display_width":1024,"display_height":768}],"top_logprobs":0,"top_p":1.0,"truncation":"auto","usage":null,"user":null,"metadata":{}}}
781+
782+ event: response.in_progress
783+ data: {"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_0b949080ec8e4b8a006920e0661d00819383ed81438ab11299","object":"response","created_at":1763762278,"status":"in_progress","background":false,"content_filters":null,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"computer-use-preview-2025-03-11","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","generate_summary":"concise","summary":"concise"},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":null,"tools":[{"type":"computer_use_preview","environment":"browser","display_width":1024,"display_height":768}],"top_logprobs":0,"top_p":1.0,"truncation":"auto","usage":null,"user":null,"metadata":{}}}
784+
785+ event: response.output_item.added
786+ data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"type":"computer_call","id":"cu_0b949080ec8e4b8a006920e067a7c0819384d047d21b484357","status":"in_progress","call_id":"call_p7K8YjFwNjqMgkKhSiExgFH6","action":{"type":"screenshot"},"pending_safety_checks":[]}}
787+
788+ event: response.output_item.done
789+ data: {"type":"response.output_item.done","sequence_number":3,"output_index":0,"item":{"type":"computer_call","id":"cu_0b949080ec8e4b8a006920e067a7c0819384d047d21b484357","status":"completed","call_id":"call_p7K8YjFwNjqMgkKhSiExgFH6","action":{"type":"screenshot"},"pending_safety_checks":[]}}
790+
791+ event: response.completed
792+ data: {"type":"response.completed","sequence_number":4,"response":{"id":"resp_0b949080ec8e4b8a006920e0661d00819383ed81438ab11299","object":"response","created_at":1763762278,"status":"completed","background":false,"content_filters":null,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"computer-use-preview-2025-03-11","output":[{"type":"computer_call","id":"cu_0b949080ec8e4b8a006920e067a7c0819384d047d21b484357","status":"completed","call_id":"call_p7K8YjFwNjqMgkKhSiExgFH6","action":{"type":"screenshot"},"pending_safety_checks":[]}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":"medium","generate_summary":"concise","summary":"concise"},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":null,"tools":[{"type":"computer-use-preview-2025-03-11","environment":"browser","display_width":1024,"display_height":768}],"top_logprobs":0,"top_p":1.0,"truncation":"auto","usage":{"input_tokens":18,"input_tokens_details":{"cached_tokens":0},"output_tokens":53,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":71},"user":null,"metadata":{}}}
793+ """ ;
794+
795+ using VerbatimHttpHandler handler = new ( Input , Output ) ;
796+ using HttpClient httpClient = new ( handler ) ;
797+ using IChatClient client = CreateResponseClient ( httpClient , "computer-use-preview" ) ;
798+
799+ var responseCreationOptions =
800+ new ResponseCreationOptions
801+ {
802+ TruncationMode = ResponseTruncationMode . Auto ,
803+ ReasoningOptions = new ( )
804+ {
805+ ReasoningSummaryVerbosity = ResponseReasoningSummaryVerbosity . Concise
806+ } ,
807+ Tools =
808+ {
809+ ResponseTool . CreateComputerTool ( ComputerToolEnvironment . Browser , 1024 , 768 ) ,
810+ }
811+ } ;
812+ var chatOptions =
813+ new ChatOptions
814+ {
815+ RawRepresentationFactory = options => responseCreationOptions
816+ } ;
817+
818+ List < ChatResponseUpdate > updates = [ ] ;
819+ await foreach ( var update in client . GetStreamingResponseAsync ( [ new ChatMessage ( ChatRole . User , "Search the web for the temperature today in Fremont" ) ] , chatOptions ) )
820+ {
821+ updates . Add ( update ) ;
822+ }
823+
824+ Assert . Empty ( string . Concat ( updates . Select ( u => u . Text ) ) ) ;
825+
826+ var createdAt = DateTimeOffset . FromUnixTimeSeconds ( 1_763_762_278 ) ;
827+ Assert . Equal ( 4 , updates . Count ) ;
828+
829+ HashSet < int > updatesWithContents = [ 3 ] ;
830+ for ( int i = 0 ; i < updates . Count ; i ++ )
831+ {
832+ Assert . Equal ( "resp_0b949080ec8e4b8a006920e0661d00819383ed81438ab11299" , updates [ i ] . ResponseId ) ;
833+ Assert . Equal ( "resp_0b949080ec8e4b8a006920e0661d00819383ed81438ab11299" , updates [ i ] . ConversationId ) ;
834+ Assert . Equal ( createdAt , updates [ i ] . CreatedAt ) ;
835+ Assert . Equal ( "computer-use-preview-2025-03-11" , updates [ i ] . ModelId ) ;
836+ Assert . Null ( updates [ i ] . AdditionalProperties ) ;
837+ Assert . Equal ( i == 3 ? 1 : 0 , updates [ i ] . Contents . Count ) ;
838+ ////Assert.Equal(i < updates.Count - 1 ? null : ChatFinishReason.Stop, updates[i].FinishReason);
839+ Assert . Null ( updates [ i ] . FinishReason ) ;
840+ Assert . Null ( updates [ i ] . Role ) ;
841+ }
842+
843+ ////Assert.Equal(ChatRole.Assistant, updates[4].Role);
844+ AIContent content = Assert . Single ( updates [ 3 ] . Contents ) ;
845+ Assert . NotNull ( content . RawRepresentation ) ;
846+ Assert . IsType < ComputerCallResponseItem > ( content . RawRepresentation ) ;
847+
848+ ////UsageContent usage = Assert.Single(updates.SelectMany(u => u.Contents).OfType<UsageContent>());
849+ ////Assert.Equal(18, usage.Details.InputTokenCount);
850+ ////Assert.Equal(53, usage.Details.OutputTokenCount);
851+ ////Assert.Equal(71, usage.Details.TotalTokenCount);
852+ }
853+
596854 [ Fact ]
597855 public async Task ChatOptions_StrictRespected ( )
598856 {
0 commit comments