Skip to content

[Bug]: ToolSpec with Context object raises Pydantic Error #18758

@RakeshReddyKondeti

Description

@RakeshReddyKondeti

Bug Description

Hi,
This is a follow-up issue to issue #18057 , which describes a bug where using a Context object in ToolSpec causes a Pydantic schema generation error.

Problem

Although FunctionTool is designed to handle functions with ctx: Context as the first parameter (by removing it from the schema and expecting it at runtime), BaseToolSpec.get_fn_schema_from_fn_name does not ignore the ctx parameter when generating the schema. This causes Pydantic to attempt to generate a schema for the Context type, resulting in an error.

Suggested Fix

Update BaseToolSpec to detect and ignore the ctx parameter (as in FunctionTool.from _defaults) when calling create _schema_from_function

Version

0.12.27

Steps to Reproduce

from llama_index.core.tools.tool_spec.base import BaseToolSpec
from llama_index.core.workflow import Context

class MyToolSpec(BaseToolSpec):
    spec_functions = ["sum"]

    async def sum(self, ctx: Context, a: int, b: int) -> int:
        return a + b

if __name__ == "__main__":
    tool_spec = MyToolSpec()
    tool_spec.to_tool_list() 

Relevant Logs/Tracbacks

Traceback (most recent call last):
  File "C:\svn\software\ocean\Digitalisation Projects\DemoProject\rough3.py", line 147, in <module>
    tools = tool_spec.to_tool_list()
            ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\llama_index\core\tools\tool_spec\base.py", line 83, in to_tool_list
    metadata = self.get_metadata_from_fn_name(func_spec)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\llama_index\core\tools\tool_spec\base.py", line 58, in get_metadata_from_fn_name
    fn_schema = self.get_fn_schema_from_fn_name(
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\llama_index\core\tools\tool_spec\base.py", line 38, in get_fn_schema_from_fn_name
    return create_schema_from_function(fn_name, getattr(self, fn_name))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\llama_index\core\tools\utils.py", line 80, in create_schema_from_function
    return create_model(name, **fields)  # type: ignore
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\main.py", line 1761, in create_model
    return meta(
           ^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_model_construction.py", line 237, in __new__
    complete_model_class(
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_model_construction.py", line 597, in complete_model_class
    schema = gen_schema.generate_schema(cls)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_generate_schema.py", line 706, in generate_schema
    schema = self._generate_schema_inner(obj)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_generate_schema.py", line 999, in _generate_schema_inner
    return self._model_schema(obj)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_generate_schema.py", line 832, in _model_schema
    {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_generate_schema.py", line 1201, in _generate_md_field_schema
    common_field = self._common_field_schema(name, field_info, decorators)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_generate_schema.py", line 1367, in _common_field_schema
    schema = self._apply_annotations(
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_generate_schema.py", line 2279, in _apply_annotations
    schema = get_inner_schema(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_schema_generation_shared.py", line 83, in __call__
    schema = self._handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_generate_schema.py", line 2261, in inner_handler
    schema = self._generate_schema_inner(obj)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_generate_schema.py", line 1004, in _generate_schema_inner
    return self.match_type(obj)
           ^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_generate_schema.py", line 1122, in match_type
    return self._unknown_type_schema(obj)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\rk908\AppData\Local\miniconda3\envs\fitbot\Lib\site-packages\pydantic\_internal\_generate_schema.py", line 634, in _unknown_type_schema
    raise PydanticSchemaGenerationError(
pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for <class 'llama_index.core.workflow.context.Context'>. Set `arbitrary_types_allowed=True` in the model_config to ignore this error or implement `__get_pydantic_core_schema__` on your type to fully support it.

If you got this error by calling handler(<some type>) within `__get_pydantic_core_schema__` then you likely need to call `handler.generate_schema(<some type>)` since we do not call `__get_pydantic_core_schema__` on `<some type>` otherwise to avoid infinite recursion.

For further information visit https://errors.pydantic.dev/2.11/u/schema-for-unknown-type

Metadata

Metadata

Labels

bugSomething isn't workingtriageIssue needs to be triaged/prioritized

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions