@@ -251,3 +251,203 @@ def test_agent_run_streaming(self, langbase_client, stream_chunks):
251251 request = responses .calls [0 ].request
252252 validate_response_headers (request .headers , AUTH_AND_JSON_CONTENT_HEADER )
253253 assert json .loads (request .body ) == request_body
254+
255+ @responses .activate
256+ def test_agent_run_structured_output (self , langbase_client , mock_responses ):
257+ """Test agent.run method with structured output."""
258+ math_reasoning_schema = {
259+ "type" : "object" ,
260+ "properties" : {
261+ "steps" : {
262+ "type" : "array" ,
263+ "items" : {
264+ "type" : "object" ,
265+ "properties" : {
266+ "explanation" : {"type" : "string" },
267+ "output" : {"type" : "string" },
268+ },
269+ "required" : ["explanation" , "output" ],
270+ },
271+ },
272+ "final_answer" : {"type" : "string" },
273+ },
274+ "required" : ["steps" , "final_answer" ],
275+ }
276+
277+ request_body = {
278+ "input" : [{"role" : "user" , "content" : "How can I solve 8x + 22 = -23?" }],
279+ "model" : "openai:gpt-4.1" ,
280+ "apiKey" : "test-openai-key" ,
281+ "instructions" : "You are a helpful math tutor. Guide the user through the solution step by step." ,
282+ "response_format" : {
283+ "type" : "json_schema" ,
284+ "json_schema" : {
285+ "name" : "math_reasoning" ,
286+ "schema" : math_reasoning_schema ,
287+ },
288+ },
289+ }
290+
291+ responses .add (
292+ responses .POST ,
293+ f"{ BASE_URL } { AGENT_RUN_ENDPOINT } " ,
294+ json = mock_responses ["agent.run.structured" ],
295+ status = 200 ,
296+ )
297+
298+ result = langbase_client .agent .run (
299+ input = request_body ["input" ],
300+ model = request_body ["model" ],
301+ api_key = request_body ["apiKey" ],
302+ instructions = request_body ["instructions" ],
303+ response_format = request_body ["response_format" ],
304+ )
305+
306+ assert result == mock_responses ["agent.run.structured" ]
307+ assert len (responses .calls ) == 1
308+ request = responses .calls [0 ].request
309+ validate_response_headers (request .headers , AUTH_AND_JSON_CONTENT_HEADER )
310+ assert json .loads (request .body ) == request_body
311+
312+ # Verify structured output format
313+ assert "output" in result
314+ output_data = json .loads (result ["output" ])
315+ assert "steps" in output_data
316+ assert "final_answer" in output_data
317+ assert isinstance (output_data ["steps" ], list )
318+ assert len (output_data ["steps" ]) > 0
319+
320+ @responses .activate
321+ def test_agent_run_tool_call (self , langbase_client , mock_responses ):
322+ """Test agent.run method with tool calls."""
323+ send_email_tool_schema = {
324+ "type" : "function" ,
325+ "function" : {
326+ "name" : "send_email" ,
327+ "description" : "Send an email using Resend API" ,
328+ "parameters" : {
329+ "type" : "object" ,
330+ "required" : ["from" , "to" , "subject" , "html" , "text" ],
331+ "properties" : {
332+ "from" : {"type" : "string" },
333+ "to" : {"type" : "string" },
334+ "subject" : {"type" : "string" },
335+ "html" : {"type" : "string" },
336+ "text" : {"type" : "string" },
337+ },
338+ "additionalProperties" : False ,
339+ },
340+ },
341+ }
342+
343+ request_body = {
344+ "input" : [{"role" : "user" , "content" : "Send a welcome email to Sam." }],
345+ "model" : "openai:gpt-4.1-mini" ,
346+ "apiKey" : "test-openai-key" ,
347+ "instructions" : "You are an email agent. You are given a task to send an email to a recipient. You have the ability to send an email using the send_email tool." ,
348+ "tools" : [send_email_tool_schema ],
349+ }
350+
351+ responses .add (
352+ responses .POST ,
353+ f"{ BASE_URL } { AGENT_RUN_ENDPOINT } " ,
354+ json = mock_responses ["agent.run.tool" ],
355+ status = 200 ,
356+ )
357+
358+ result = langbase_client .agent .run (
359+ input = request_body ["input" ],
360+ model = request_body ["model" ],
361+ api_key = request_body ["apiKey" ],
362+ instructions = request_body ["instructions" ],
363+ tools = request_body ["tools" ],
364+ stream = False ,
365+ )
366+
367+ assert result == mock_responses ["agent.run.tool" ]
368+ assert len (responses .calls ) == 1
369+ request = responses .calls [0 ].request
370+ validate_response_headers (request .headers , AUTH_AND_JSON_CONTENT_HEADER )
371+ assert json .loads (request .body ) == request_body
372+
373+ # Verify tool call structure
374+ assert "choices" in result
375+ choices = result ["choices" ]
376+ assert len (choices ) > 0
377+ message = choices [0 ]["message" ]
378+ assert "tool_calls" in message
379+ tool_calls = message ["tool_calls" ]
380+ assert len (tool_calls ) > 0
381+
382+ tool_call = tool_calls [0 ]
383+ assert tool_call ["type" ] == "function"
384+ assert "function" in tool_call
385+ function = tool_call ["function" ]
386+ assert function ["name" ] == "send_email"
387+ assert "arguments" in function
388+
389+ @responses .activate
390+ def test_agent_run_tool_call_final_response (self , langbase_client , mock_responses ):
391+ """Test agent.run method with tool call final response."""
392+ # Simulate messages after tool execution
393+ input_messages = [
394+ {"role" : "user" , "content" : "Send a welcome email to Sam." },
395+ {
396+ "role" : "assistant" ,
397+ "content" : None ,
398+ "tool_calls" : [
399+ {
400+ "id" : "call_123456789" ,
401+ "type" : "function" ,
402+ "function" : {
403+ "name" : "send_email" ,
404+ "arguments" :
'{"from": "[email protected] ", "to": "[email protected] ", "subject": "Welcome to Langbase!", "html": "Hello Sam! Welcome to Langbase.", "text": "Hello Sam! Welcome to Langbase."}' ,
405+ },
406+ }
407+ ],
408+ },
409+ {
410+ "role" : "tool" ,
411+ "tool_call_id" : "call_123456789" ,
412+ "name" : "send_email" ,
413+ "content" :
"✅ Email sent successfully to [email protected] !" ,
414+ },
415+ ]
416+
417+ request_body = {
418+ "input" : input_messages ,
419+ "model" : "openai:gpt-4.1-mini" ,
420+ "apiKey" : "test-openai-key" ,
421+ "instructions" : "You are an email sending assistant. Confirm the email has been sent successfully." ,
422+ }
423+
424+ responses .add (
425+ responses .POST ,
426+ f"{ BASE_URL } { AGENT_RUN_ENDPOINT } " ,
427+ json = mock_responses ["agent.run.tool.final" ],
428+ status = 200 ,
429+ )
430+
431+ result = langbase_client .agent .run (
432+ input = request_body ["input" ],
433+ model = request_body ["model" ],
434+ api_key = request_body ["apiKey" ],
435+ instructions = request_body ["instructions" ],
436+ stream = False ,
437+ )
438+
439+ assert result == mock_responses ["agent.run.tool.final" ]
440+ assert len (responses .calls ) == 1
441+ request = responses .calls [0 ].request
442+ validate_response_headers (request .headers , AUTH_AND_JSON_CONTENT_HEADER )
443+ assert json .loads (request .body ) == request_body
444+
445+ # Verify final response structure
446+ assert "output" in result
447+ assert result [
"output" ]
== "✅ Email sent successfully to [email protected] !" 448+ assert "choices" in result
449+ choices = result ["choices" ]
450+ assert len (choices ) > 0
451+ message = choices [0 ]["message" ]
452+ assert message ["role" ] == "assistant"
453+ assert message [
"content" ]
== "✅ Email sent successfully to [email protected] !"
0 commit comments