tool signature inspection for callbacks fails on certain chains
Labels: name: auto:bug

### System Info

master

### Who can help?

_No response_

### Information

- [ ] The official example notebooks/scripts
- [ ] My own modified scripts

### Related Components

- [ ] LLMs/Chat Models
- [ ] Embedding Models
- [ ] Prompts / Prompt Templates / Prompt Selectors
- [ ] Output Parsers
- [ ] Document Loaders
- [ ] Vector Stores / Retrievers
- [ ] Memory
- [X] Agents / Agent Executors
- [X] Tools / Toolkits
- [ ] Chains
- [ ] Callbacks/Tracing
- [ ] Async

### Reproduction

signature inspection for callbacks fails on tools that use chains without chain_type defined

signature inspection seems to call __eq__ which for pydantic objects calls dict() which raises NotImplemented by default

```python
> Entering new  chain...
 I need to find the product with the highest revenue
Action: Dataframe analysis
Action Input: the dataframe containing product and revenue information
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
Cell In[24], line 1
----> 1 agent.run('which product has the highest revenue?')

File ~/opt/anaconda3/envs/langchain/lib/python3.9/site-packages/langchain/chains/base.py:290, in Chain.run(self, callbacks, tags, *args, **kwargs)
    288     if len(args) != 1:
    289         raise ValueError("`run` supports only one positional argument.")
--> 290     return self(args[0], callbacks=callbacks, tags=tags)[_output_key]
    292 if kwargs and not args:
    293     return self(kwargs, callbacks=callbacks, tags=tags)[_output_key]

File ~/opt/anaconda3/envs/langchain/lib/python3.9/site-packages/langchain/chains/base.py:166, in Chain.__call__(self, inputs, return_only_outputs, callbacks, tags, include_run_info)
    164 except (KeyboardInterrupt, Exception) as e:
    165     run_manager.on_chain_error(e)
--> 166     raise e
    167 run_manager.on_chain_end(outputs)
    168 final_outputs: Dict[str, Any] = self.prep_outputs(
    169     inputs, outputs, return_only_outputs
    170 )

File ~/opt/anaconda3/envs/langchain/lib/python3.9/site-packages/langchain/chains/base.py:160, in Chain.__call__(self, inputs, return_only_outputs, callbacks, tags, include_run_info)
    154 run_manager = callback_manager.on_chain_start(
    155     dumpd(self),
    156     inputs,
    157 )
    158 try:
    159     outputs = (
--> 160         self._call(inputs, run_manager=run_manager)
    161         if new_arg_supported
    162         else self._call(inputs)
    163     )
    164 except (KeyboardInterrupt, Exception) as e:
    165     run_manager.on_chain_error(e)

File ~/opt/anaconda3/envs/langchain/lib/python3.9/site-packages/langchain/agents/agent.py:987, in AgentExecutor._call(self, inputs, run_manager)
    985 # We now enter the agent loop (until it returns something).
    986 while self._should_continue(iterations, time_elapsed):
--> 987     next_step_output = self._take_next_step(
    988         name_to_tool_map,
    989         color_mapping,
    990         inputs,
    991         intermediate_steps,
    992         run_manager=run_manager,
    993     )
    994     if isinstance(next_step_output, AgentFinish):
    995         return self._return(
    996             next_step_output, intermediate_steps, run_manager=run_manager
    997         )

File ~/opt/anaconda3/envs/langchain/lib/python3.9/site-packages/langchain/agents/agent.py:850, in AgentExecutor._take_next_step(self, name_to_tool_map, color_mapping, inputs, intermediate_steps, run_manager)
    848         tool_run_kwargs["llm_prefix"] = ""
    849     # We then call the tool on the tool input to get an observation
--> 850     observation = tool.run(
    851         agent_action.tool_input,
    852         verbose=self.verbose,
    853         color=color,
    854         callbacks=run_manager.get_child() if run_manager else None,
    855         **tool_run_kwargs,
    856     )
    857 else:
    858     tool_run_kwargs = self.agent.tool_run_logging_kwargs()

File ~/opt/anaconda3/envs/langchain/lib/python3.9/site-packages/langchain/tools/base.py:299, in BaseTool.run(self, tool_input, verbose, start_color, color, callbacks, **kwargs)
    297 except (Exception, KeyboardInterrupt) as e:
    298     run_manager.on_tool_error(e)
--> 299     raise e
    300 else:
    301     run_manager.on_tool_end(
    302         str(observation), color=color, name=self.name, **kwargs
    303     )

File ~/opt/anaconda3/envs/langchain/lib/python3.9/site-packages/langchain/tools/base.py:271, in BaseTool.run(self, tool_input, verbose, start_color, color, callbacks, **kwargs)
    268 try:
    269     tool_args, tool_kwargs = self._to_args_and_kwargs(parsed_input)
    270     observation = (
--> 271         self._run(*tool_args, run_manager=run_manager, **tool_kwargs)
    272         if new_arg_supported
    273         else self._run(*tool_args, **tool_kwargs)
    274     )
    275 except ToolException as e:
    276     if not self.handle_tool_error:

File ~/opt/anaconda3/envs/langchain/lib/python3.9/site-packages/langchain/tools/base.py:412, in Tool._run(self, run_manager, *args, **kwargs)
    405 def _run(
    406     self,
    407     *args: Any,
    408     run_manager: Optional[CallbackManagerForToolRun] = None,
    409     **kwargs: Any,
    410 ) -> Any:
    411     """Use the tool."""
--> 412     new_argument_supported = signature(self.func).parameters.get("callbacks")
    413     return (
    414         self.func(
    415             *args,
   (...)
    420         else self.func(*args, **kwargs)
    421     )

File ~/opt/anaconda3/envs/langchain/lib/python3.9/inspect.py:3113, in signature(obj, follow_wrapped)
   3111 def signature(obj, *, follow_wrapped=True):
   3112     """Get a signature object for the passed callable."""
-> 3113     return Signature.from_callable(obj, follow_wrapped=follow_wrapped)

File ~/opt/anaconda3/envs/langchain/lib/python3.9/inspect.py:2862, in Signature.from_callable(cls, obj, follow_wrapped)
   2859 @classmethod
   2860 def from_callable(cls, obj, *, follow_wrapped=True):
   2861     """Constructs Signature for the given callable object."""
-> 2862     return _signature_from_callable(obj, sigcls=cls,
   2863                                     follow_wrapper_chains=follow_wrapped)

File ~/opt/anaconda3/envs/langchain/lib/python3.9/inspect.py:2328, in _signature_from_callable(obj, follow_wrapper_chains, skip_bound_arg, sigcls)
   2322 if isfunction(obj) or _signature_is_functionlike(obj):
   2323     # If it's a pure Python function, or an object that is duck type
   2324     # of a Python function (Cython functions, for instance), then:
   2325     return _signature_from_function(sigcls, obj,
   2326                                     skip_bound_arg=skip_bound_arg)
-> 2328 if _signature_is_builtin(obj):
   2329     return _signature_from_builtin(sigcls, obj,
   2330                                    skip_bound_arg=skip_bound_arg)
   2332 if isinstance(obj, functools.partial):

File ~/opt/anaconda3/envs/langchain/lib/python3.9/inspect.py:1875, in _signature_is_builtin(obj)
   1866 def _signature_is_builtin(obj):
   1867     """Private helper to test if `obj` is a callable that might
   1868     support Argument Clinic's __text_signature__ protocol.
   1869     """
   1870     return (isbuiltin(obj) or
   1871             ismethoddescriptor(obj) or
   1872             isinstance(obj, _NonUserDefinedCallables) or
   1873             # Can't test 'isinstance(type)' here, as it would
   1874             # also be True for regular python classes
-> 1875             obj in (type, object))

File ~/opt/anaconda3/envs/langchain/lib/python3.9/site-packages/pydantic/main.py:911, in pydantic.main.BaseModel.__eq__()

File ~/opt/anaconda3/envs/langchain/lib/python3.9/site-packages/langchain/chains/base.py:342, in Chain.dict(self, **kwargs)
    340     raise ValueError("Saving of memory is not yet supported.")
    341 _dict = super().dict()
--> 342 _dict["_type"] = self._chain_type
    343 return _dict

File ~/opt/anaconda3/envs/langchain/lib/python3.9/site-packages/langchain/chains/base.py:65, in Chain._chain_type(self)
     63 @property
     64 def _chain_type(self) -> str:
---> 65     raise NotImplementedError("Saving not supported for this chain type.")

NotImplementedError: Saving not supported for this chain type.
```

### Expected behavior

chains with unimplemented chain_type should still work