11using System . Text . Json ;
2- using Grpc . Net . ClientFactory ;
32using Microsoft . Extensions . DependencyInjection ;
43using Xunit . Abstractions ;
54
@@ -49,7 +48,7 @@ public async Task ExecuteLocalFunctionWithWebSearch()
4948 // Create the request with both a local function and web_search tool
5049 var request = new GetCompletionsRequest
5150 {
52- Model = "grok-4-1-fast" ,
51+ Model = "grok-4-1-fast-non-reasoning " ,
5352 Messages =
5453 {
5554 new Message
@@ -67,100 +66,69 @@ public async Task ExecuteLocalFunctionWithWebSearch()
6766 {
6867 new Tool { Function = getDateFunction } ,
6968 new Tool { WebSearch = new WebSearch ( ) }
70- }
69+ } ,
70+ Include = { IncludeOption . InlineCitations }
7171 } ;
7272
7373 var response = await client . GetCompletionAsync ( request ) ;
7474
7575 Assert . NotNull ( response ) ;
76- output . WriteLine ( $ "Response ID: { response . Id } ") ;
77- output . WriteLine ( $ "Model: { response . Model } ") ;
78-
79- // Check if we have outputs
76+ Assert . NotNull ( response . Id ) ;
77+ Assert . NotEmpty ( response . Id ) ;
78+ Assert . Equal ( request . Model , response . Model ) ;
8079 Assert . NotEmpty ( response . Outputs ) ;
80+
8181 var firstOutput = response . Outputs [ 0 ] ;
82- var invokedGetDate = false ;
82+ Assert . NotEmpty ( firstOutput . Message . ToolCalls ) ;
8383
84- output . WriteLine ( $ "Finish Reason: { firstOutput . FinishReason } ") ;
84+ var getDateToolCall = firstOutput . Message . ToolCalls
85+ . FirstOrDefault ( tc => tc . Function ? . Name == "get_date" && tc . Type == ToolCallType . ClientSideTool ) ;
8586
86- // The model should call tools
87- if ( firstOutput . Message . ToolCalls . Count > 0 )
88- {
89- output . WriteLine ( $ " \n Tool Calls ( { firstOutput . Message . ToolCalls . Count } ):" ) ;
87+ Assert . NotNull ( getDateToolCall ) ;
88+ Assert . NotNull ( getDateToolCall . Id ) ;
89+ Assert . NotEmpty ( getDateToolCall . Id ) ;
90+ Assert . Equal ( "get_date" , getDateToolCall . Function . Name ) ;
9091
91- foreach ( var toolCall in firstOutput . Message . ToolCalls )
92- {
93- output . WriteLine ( $ " - ID: { toolCall . Id } ") ;
94- output . WriteLine ( $ " Type: { toolCall . Type } ") ;
95- output . WriteLine ( $ " Status: { toolCall . Status } ") ;
92+ output . WriteLine ( $ "Found client-side tool call: { getDateToolCall . Function . Name } (ID: { getDateToolCall . Id } )") ;
9693
97- if ( toolCall . Function != null )
98- {
99- output . WriteLine ( $ " Function: { toolCall . Function . Name } ") ;
100- output . WriteLine ( $ " Arguments: { toolCall . Function . Arguments } ") ;
101-
102- // If it's our local get_date function, we need to execute it
103- if ( toolCall . Function . Name == "get_date" && toolCall . Type == ToolCallType . ClientSideTool )
104- {
105- output . WriteLine ( $ " -> Local function call detected, would execute on client side") ;
106-
107- // Execute the function
108- var currentDate = DateTime . Now . ToString ( "yyyy-MM-dd" ) ;
109- output . WriteLine ( $ " -> Result: { currentDate } ") ;
110-
111- var call = new Message
112- {
113- Role = MessageRole . RoleAssistant ,
114- } ;
115- call . ToolCalls . AddRange ( firstOutput . Message . ToolCalls ) ;
116-
117- // Continue the conversation with the function result
118- var followUpRequest = new GetCompletionsRequest
119- {
120- Model = request . Model ,
121- Messages =
122- {
123- request . Messages [ 0 ] , // Original user message
124- call ,
125- //new Message
126- //{
127- // Role = MessageRole.RoleAssistant,
128- // ToolCalls = { toolCall }
129- //},
130- new Message
131- {
132- Role = MessageRole . RoleTool ,
133- Content = { new Content { Text = currentDate } }
134- }
135- } ,
136- Tools = { request . Tools [ 0 ] , request . Tools [ 1 ] }
137- } ;
138-
139- var followUpResponse = await client . GetCompletionAsync ( followUpRequest ) ;
140- invokedGetDate = true ;
141-
142- // There should be no more tool calls after we return the client-side one.
143- Assert . Empty ( followUpResponse . Outputs . SelectMany ( x => x . Message . ToolCalls ) ) ;
144- }
145- }
146- }
147- }
94+ var currentDate = DateTime . Now . ToString ( "yyyy-MM-dd" ) ;
14895
149- if ( ! string . IsNullOrEmpty ( firstOutput . Message . Content ) )
96+ var call = new Message
15097 {
151- output . WriteLine ( $ "\n Content: { firstOutput . Message . Content } ") ;
152- }
98+ Role = MessageRole . RoleAssistant ,
99+ } ;
100+ call . ToolCalls . AddRange ( firstOutput . Message . ToolCalls ) ;
153101
154- // Check for citations
155- if ( response . Citations . Count > 0 )
102+ var followUpRequest = new GetCompletionsRequest
156103 {
157- output . WriteLine ( $ " \n Citations ( { response . Citations . Count } ):" ) ;
158- foreach ( var citation in response . Citations )
104+ Model = request . Model ,
105+ Messages =
159106 {
160- output . WriteLine ( $ " - { citation } ") ;
161- }
162- }
107+ request . Messages [ 0 ] ,
108+ call ,
109+ new Message
110+ {
111+ Role = MessageRole . RoleTool ,
112+ Content = { new Content { Text = currentDate } }
113+ }
114+ } ,
115+ Tools = { request . Tools } ,
116+ Include = { IncludeOption . InlineCitations , IncludeOption . WebSearchCallOutput }
117+ } ;
118+
119+ var followUpResponse = await client . GetCompletionAsync ( followUpRequest ) ;
120+
121+ Assert . NotNull ( followUpResponse ) ;
122+ Assert . NotEmpty ( followUpResponse . Outputs ) ;
123+
124+ var remainingClientToolCalls = followUpResponse . Outputs
125+ . SelectMany ( x => x . Message . ToolCalls )
126+ . Where ( tc => tc . Type == ToolCallType . ClientSideTool ) ;
127+
128+ Assert . Empty ( remainingClientToolCalls ) ;
163129
164- Assert . True ( invokedGetDate ) ;
130+ var finalOutput = followUpResponse . Outputs . Last ( ) ;
131+ Assert . NotNull ( finalOutput . Message . Content ) ;
132+ Assert . NotEmpty ( finalOutput . Message . Content ) ;
165133 }
166134}
0 commit comments