@@ -233,13 +233,53 @@ class Config:
233233 @root_validator (pre = True )
234234 def infer_defaults (cls , values : dict ) -> dict :
235235 """Assign name to the run."""
236+ # Try to get name from serialized data (legacy LangChain support)
236237 if values .get ("name" ) is None and values .get ("serialized" ) is not None :
237- if "name" in values ["serialized" ]:
238- values ["name" ] = values ["serialized" ]["name" ]
239- elif "id" in values ["serialized" ]:
240- values ["name" ] = values ["serialized" ]["id" ][- 1 ]
238+ serialized = values ["serialized" ]
239+ values ["name" ] = serialized .get ("name" ) or (
240+ serialized ["id" ][- 1 ] if "id" in serialized else None
241+ )
242+
243+ # If still no name, try to infer from caller
241244 if values .get ("name" ) is None :
242- values ["name" ] = "Unnamed"
245+ name = None
246+ try :
247+ import inspect
248+ import os
249+
250+ # Look up the stack, skipping internal frames
251+ for frame_info in inspect .stack ()[1 :8 ]:
252+ filename = frame_info .filename
253+ norm_path = filename .replace ("\\ " , "/" )
254+
255+ # Skip pydantic and langsmith internal modules
256+ if "/pydantic/" in norm_path :
257+ continue
258+ if os .path .basename (filename ) in {
259+ "run_trees.py" ,
260+ "run_helpers.py" ,
261+ "client.py" ,
262+ "_context.py" ,
263+ }:
264+ continue
265+
266+ # Try to get class name from self or cls
267+ frame_locals = frame_info .frame .f_locals
268+ if "self" in frame_locals :
269+ name = frame_locals ["self" ].__class__ .__name__
270+ break
271+ elif "cls" in frame_locals :
272+ name = frame_locals ["cls" ].__name__
273+ break
274+ except Exception :
275+ pass
276+
277+ # Use inferred name or descriptive fallback
278+ if name :
279+ values ["name" ] = name
280+ else :
281+ run_type = values .get ("run_type" , "chain" )
282+ values ["name" ] = f"Unnamed_{ run_type } "
243283 if "client" in values : # Handle user-constructed clients
244284 values ["ls_client" ] = values .pop ("client" )
245285 elif "_client" in values :
0 commit comments