@@ -1082,9 +1082,170 @@ def route_with_tracking(
10821082 f"⚠️ Result creation failed: status={ result_response .status_code } "
10831083 )
10841084
1085+ # Create traces for this result if we have a result_id
1086+ if result_id :
1087+ self ._create_traces_for_result (
1088+ result_id = result_id ,
1089+ client = client ,
1090+ request_data = request_data ,
1091+ response = response ,
1092+ )
1093+
10851094 except Exception as e :
10861095 logger .error (f"❌ Failed to create Result record: { e } " , exc_info = True )
10871096 result_id = None
10881097
10891098 # Return both response and result_id for tracking
10901099 return {"response" : response , "result_id" : result_id }
1100+
1101+ def _create_traces_for_result (
1102+ self ,
1103+ result_id : str ,
1104+ client ,
1105+ request_data : Dict [str , Any ],
1106+ response : Any ,
1107+ ) -> None :
1108+ """
1109+ Create trace records for a result capturing the agent execution details.
1110+
1111+ Args:
1112+ result_id: The UUID of the result to attach traces to
1113+ client: Authenticated client for API calls
1114+ request_data: The original request data sent to the agent
1115+ response: The response from the agent
1116+ """
1117+ from ..api .result import result_trace_create
1118+ from ..models import TraceRequest , StepTypeEnum
1119+
1120+ sequence = 0
1121+
1122+ try :
1123+ result_uuid = UUID (result_id )
1124+
1125+ # Trace 1: Capture the user input/request
1126+ sequence += 1
1127+ input_trace = TraceRequest (
1128+ sequence = sequence ,
1129+ step_type = StepTypeEnum .OTHER ,
1130+ content = {
1131+ "step_name" : "User Request" ,
1132+ "messages" : request_data .get ("messages" , []),
1133+ "prompt" : request_data .get ("prompt" , "" ),
1134+ },
1135+ )
1136+ result_trace_create .sync_detailed (
1137+ id = result_uuid ,
1138+ client = client ,
1139+ body = input_trace ,
1140+ )
1141+ logger .debug (f"Created input trace for result { result_id } " )
1142+
1143+ # Trace 2: Capture tool calls if present
1144+ if hasattr (response , "tool_calls" ) and response .tool_calls :
1145+ for tool_call in response .tool_calls :
1146+ sequence += 1
1147+ tool_trace = TraceRequest (
1148+ sequence = sequence ,
1149+ step_type = StepTypeEnum .TOOL_CALL ,
1150+ content = {
1151+ "step_name" : "Tool Call" ,
1152+ "tool_name" : tool_call .get ("function" , {}).get (
1153+ "name" , "unknown"
1154+ )
1155+ if isinstance (tool_call , dict )
1156+ else getattr (
1157+ getattr (tool_call , "function" , None ), "name" , "unknown"
1158+ ),
1159+ "tool_id" : tool_call .get ("id" , "" )
1160+ if isinstance (tool_call , dict )
1161+ else getattr (tool_call , "id" , "" ),
1162+ "arguments" : tool_call .get ("function" , {}).get (
1163+ "arguments" , ""
1164+ )
1165+ if isinstance (tool_call , dict )
1166+ else getattr (
1167+ getattr (tool_call , "function" , None ), "arguments" , ""
1168+ ),
1169+ },
1170+ )
1171+ result_trace_create .sync_detailed (
1172+ id = result_uuid ,
1173+ client = client ,
1174+ body = tool_trace ,
1175+ )
1176+ logger .debug (f"Created { len (response .tool_calls )} tool call traces" )
1177+
1178+ # Check dict response for tool_calls
1179+ elif isinstance (response , dict ) and response .get ("tool_calls" ):
1180+ for tool_call in response ["tool_calls" ]:
1181+ sequence += 1
1182+ tool_trace = TraceRequest (
1183+ sequence = sequence ,
1184+ step_type = StepTypeEnum .TOOL_CALL ,
1185+ content = {
1186+ "step_name" : "Tool Call" ,
1187+ "tool_name" : tool_call .get ("function" , {}).get (
1188+ "name" , "unknown"
1189+ ),
1190+ "tool_id" : tool_call .get ("id" , "" ),
1191+ "arguments" : tool_call .get ("function" , {}).get (
1192+ "arguments" , ""
1193+ ),
1194+ },
1195+ )
1196+ result_trace_create .sync_detailed (
1197+ id = result_uuid ,
1198+ client = client ,
1199+ body = tool_trace ,
1200+ )
1201+ logger .debug (f"Created { len (response ['tool_calls' ])} tool call traces" )
1202+
1203+ # Trace 3: Capture the agent response
1204+ sequence += 1
1205+ response_content = ""
1206+ if hasattr (response , "choices" ) and response .choices :
1207+ choice = response .choices [0 ]
1208+ if hasattr (choice , "message" ) and choice .message :
1209+ response_content = getattr (choice .message , "content" , "" ) or ""
1210+ elif isinstance (response , dict ):
1211+ if "choices" in response and response ["choices" ]:
1212+ response_content = (
1213+ response ["choices" ][0 ].get ("message" , {}).get ("content" , "" )
1214+ )
1215+ elif "generated_text" in response :
1216+ response_content = response ["generated_text" ]
1217+ elif "content" in response :
1218+ response_content = response ["content" ]
1219+
1220+ response_trace = TraceRequest (
1221+ sequence = sequence ,
1222+ step_type = StepTypeEnum .AGENT_RESPONSE_CHUNK ,
1223+ content = {
1224+ "step_name" : "Agent Response" ,
1225+ "response" : response_content [:5000 ]
1226+ if response_content
1227+ else "" , # Truncate large responses
1228+ "finish_reason" : self ._extract_finish_reason (response ),
1229+ },
1230+ )
1231+ result_trace_create .sync_detailed (
1232+ id = result_uuid ,
1233+ client = client ,
1234+ body = response_trace ,
1235+ )
1236+ logger .info (f"✅ Created { sequence } traces for result { result_id } " )
1237+
1238+ except Exception as e :
1239+ logger .warning (f"Failed to create traces for result { result_id } : { e } " )
1240+
1241+ def _extract_finish_reason (self , response : Any ) -> str :
1242+ """Extract finish_reason from response."""
1243+ if hasattr (response , "choices" ) and response .choices :
1244+ choice = response .choices [0 ]
1245+ if hasattr (choice , "finish_reason" ):
1246+ return choice .finish_reason or "unknown"
1247+ elif isinstance (response , dict ) and "choices" in response :
1248+ choices = response .get ("choices" , [])
1249+ if choices :
1250+ return choices [0 ].get ("finish_reason" , "unknown" )
1251+ return "unknown"
0 commit comments