Skip to content

Commit b0394d1

Browse files
committed
Rename output_schema to result_schema to avoid name clashing
1 parent 728d70c commit b0394d1

9 files changed

Lines changed: 70 additions & 164 deletions

File tree

lib/crewai-tools/src/crewai_tools/tools/tavily_research_tool/tavily_research_tool.py

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,7 @@
77

88
from crewai.tools import BaseTool, EnvVar
99
from dotenv import load_dotenv
10-
from pydantic import (
11-
BaseModel,
12-
ConfigDict,
13-
Field,
14-
PrivateAttr,
15-
field_serializer,
16-
field_validator,
17-
)
10+
from pydantic import BaseModel, ConfigDict, Field, PrivateAttr
1811

1912

2013
load_dotenv()
@@ -70,11 +63,7 @@ class TavilyResearchTool(BaseTool):
7063
default="auto",
7164
description="Default model used for new Tavily research tasks.",
7265
)
73-
# ``output_schema`` here is a Tavily API JSON Schema (a dict), not the
74-
# Pydantic model type that ``BaseTool.output_schema`` expects. Tavily
75-
# deliberately repurposes the inherited name for its own released parameter,
76-
# so the type intentionally diverges from the base class.
77-
output_schema: dict[str, Any] | None = Field( # type: ignore[assignment]
66+
output_schema: dict[str, Any] | None = Field(
7867
default=None,
7968
description="Default JSON Schema used to structure research output.",
8069
)
@@ -97,26 +86,7 @@ class TavilyResearchTool(BaseTool):
9786
]
9887
)
9988

100-
# Override the inherited validator/serializer so the framework's
101-
# model-coercion logic leaves Tavily's JSON Schema dict untouched.
102-
@field_validator("output_schema", mode="before")
103-
@classmethod
104-
def _default_output_schema( # type: ignore[override]
105-
cls, v: dict[str, Any] | None
106-
) -> dict[str, Any] | None:
107-
return v
108-
109-
@field_serializer("output_schema", when_used="json")
110-
def _serialize_output_schema( # type: ignore[override]
111-
self, schema: dict[str, Any] | None
112-
) -> dict[str, Any] | None:
113-
return schema
114-
11589
def __init__(self, **kwargs: Any):
116-
tavily_output_schema = kwargs.pop("tavily_output_schema", None)
117-
if "output_schema" not in kwargs and tavily_output_schema is not None:
118-
kwargs["output_schema"] = tavily_output_schema
119-
12090
super().__init__(**kwargs)
12191
if TAVILY_AVAILABLE:
12292
api_key = os.getenv("TAVILY_API_KEY")

lib/crewai-tools/tests/tools/tavily_research_tool_test.py

Lines changed: 0 additions & 78 deletions
This file was deleted.

lib/crewai-tools/tool.specs.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25386,6 +25386,20 @@
2538625386
"title": "Model",
2538725387
"type": "string"
2538825388
},
25389+
"output_schema": {
25390+
"anyOf": [
25391+
{
25392+
"additionalProperties": true,
25393+
"type": "object"
25394+
},
25395+
{
25396+
"type": "null"
25397+
}
25398+
],
25399+
"default": null,
25400+
"description": "Default JSON Schema used to structure research output.",
25401+
"title": "Output Schema"
25402+
},
2538925403
"stream": {
2539025404
"default": false,
2539125405
"description": "Whether new Tavily research tasks should stream responses by default.",

lib/crewai/src/crewai/tools/base_tool.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
CrewStructuredTool,
3535
_deserialize_schema,
3636
_format_tool_output_for_agent,
37-
_infer_output_schema_from_callable,
37+
_infer_result_schema_from_callable,
3838
_serialize_schema,
3939
build_schema_hint,
4040
)
@@ -151,7 +151,7 @@ def _validate_tool(value: Any, nxt: Any) -> Any:
151151
validate_default=True,
152152
description="The schema for the arguments that the tool accepts.",
153153
)
154-
output_schema: type[PydanticBaseModel] | None = Field(
154+
result_schema: type[PydanticBaseModel] | None = Field(
155155
default=None,
156156
validate_default=True,
157157
description="The schema for the output that the tool returns.",
@@ -163,8 +163,8 @@ def _serialize_args_schema(
163163
) -> dict[str, Any] | None:
164164
return _serialize_schema(schema)
165165

166-
@field_serializer("output_schema", when_used="json")
167-
def _serialize_output_schema(
166+
@field_serializer("result_schema", when_used="json")
167+
def _serialize_result_schema(
168168
self, schema: type[PydanticBaseModel] | None
169169
) -> dict[str, Any] | None:
170170
return _serialize_schema(schema)
@@ -246,16 +246,16 @@ def _default_args_schema(
246246

247247
return create_model(f"{cls.__name__}Schema", **fields)
248248

249-
@field_validator("output_schema", mode="before")
249+
@field_validator("result_schema", mode="before")
250250
@classmethod
251-
def _default_output_schema(
251+
def _default_result_schema(
252252
cls, v: type[PydanticBaseModel] | dict[str, Any] | None
253253
) -> type[PydanticBaseModel] | None:
254254
if isinstance(v, dict):
255255
return _deserialize_schema(v)
256256
if v is not None:
257257
return v
258-
return _infer_output_schema_from_callable(cls._run)
258+
return _infer_result_schema_from_callable(cls._run)
259259

260260
@field_validator("max_usage_count", mode="before")
261261
@classmethod
@@ -397,7 +397,7 @@ def to_structured_tool(self) -> CrewStructuredTool:
397397
name=self.name,
398398
description=self.description,
399399
args_schema=self.args_schema,
400-
output_schema=self.output_schema,
400+
result_schema=self.result_schema,
401401
func=self._run,
402402
result_as_answer=self.result_as_answer,
403403
max_usage_count=self.max_usage_count,
@@ -419,9 +419,9 @@ def from_langchain(cls, tool: Any) -> BaseTool:
419419
raise ValueError("The provided tool must have a callable 'func' attribute.")
420420

421421
args_schema = getattr(tool, "args_schema", None)
422-
output_schema = getattr(tool, "output_schema", None)
423-
if output_schema is None:
424-
output_schema = _infer_output_schema_from_callable(tool.func)
422+
result_schema = getattr(tool, "result_schema", None)
423+
if result_schema is None:
424+
result_schema = _infer_result_schema_from_callable(tool.func)
425425

426426
if args_schema is None:
427427
func_signature = signature(tool.func)
@@ -452,7 +452,7 @@ def from_langchain(cls, tool: Any) -> BaseTool:
452452
description=getattr(tool, "description", ""),
453453
func=tool.func,
454454
args_schema=args_schema,
455-
output_schema=output_schema,
455+
result_schema=result_schema,
456456
)
457457

458458
def _set_args_schema(self) -> None:
@@ -601,9 +601,9 @@ def from_langchain(cls, tool: Any) -> Tool[..., Any]:
601601
raise ValueError("The provided tool must have a callable 'func' attribute.")
602602

603603
args_schema = getattr(tool, "args_schema", None)
604-
output_schema = getattr(tool, "output_schema", None)
605-
if output_schema is None:
606-
output_schema = _infer_output_schema_from_callable(tool.func)
604+
result_schema = getattr(tool, "result_schema", None)
605+
if result_schema is None:
606+
result_schema = _infer_result_schema_from_callable(tool.func)
607607

608608
if args_schema is None:
609609
func_signature = signature(tool.func)
@@ -634,7 +634,7 @@ def from_langchain(cls, tool: Any) -> Tool[..., Any]:
634634
description=getattr(tool, "description", ""),
635635
func=tool.func,
636636
args_schema=args_schema,
637-
output_schema=output_schema,
637+
result_schema=result_schema,
638638
)
639639

640640

@@ -658,7 +658,7 @@ def tool(
658658
name: str,
659659
/,
660660
*,
661-
output_schema: type[BaseModel] | None = ...,
661+
result_schema: type[BaseModel] | None = ...,
662662
result_as_answer: bool = ...,
663663
max_usage_count: int | None = ...,
664664
) -> Callable[[Callable[P2, R2]], Tool[P2, R2]]: ...
@@ -667,15 +667,15 @@ def tool(
667667
@overload
668668
def tool(
669669
*,
670-
output_schema: type[BaseModel] | None = ...,
670+
result_schema: type[BaseModel] | None = ...,
671671
result_as_answer: bool = ...,
672672
max_usage_count: int | None = ...,
673673
) -> Callable[[Callable[P2, R2]], Tool[P2, R2]]: ...
674674

675675

676676
def tool(
677677
*args: Callable[P2, R2] | str,
678-
output_schema: type[BaseModel] | None = None,
678+
result_schema: type[BaseModel] | None = None,
679679
result_as_answer: bool = False,
680680
max_usage_count: int | None = None,
681681
) -> Tool[P2, R2] | Callable[[Callable[P2, R2]], Tool[P2, R2]]:
@@ -689,7 +689,7 @@ def tool(
689689
Args:
690690
*args: Either the function to decorate or a custom tool name.
691691
result_as_answer: If True, the tool result becomes the final agent answer.
692-
output_schema: Optional schema for the output that the tool returns.
692+
result_schema: Optional schema for the output that the tool returns.
693693
max_usage_count: Maximum times this tool can be used. None means unlimited.
694694
695695
Returns:
@@ -731,16 +731,16 @@ def _make_tool(f: Callable[P2, R2]) -> Tool[P2, R2]:
731731

732732
class_name = "".join(tool_name.split()).title()
733733
args_schema = create_model(class_name, **fields)
734-
resolved_output_schema = (
735-
output_schema or _infer_output_schema_from_callable(f)
734+
resolved_result_schema = (
735+
result_schema or _infer_result_schema_from_callable(f)
736736
)
737737

738738
return Tool(
739739
name=tool_name,
740740
description=f.__doc__,
741741
func=f,
742742
args_schema=args_schema,
743-
output_schema=resolved_output_schema,
743+
result_schema=resolved_result_schema,
744744
result_as_answer=result_as_answer,
745745
max_usage_count=max_usage_count,
746746
current_usage_count=0,

lib/crewai/src/crewai/tools/structured_tool.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def _deserialize_schema(v: Any) -> type[BaseModel] | None:
3737
return None
3838

3939

40-
def _infer_output_schema_from_callable(
40+
def _infer_result_schema_from_callable(
4141
func: Callable[..., Any],
4242
) -> type[BaseModel] | None:
4343
try:
@@ -56,25 +56,25 @@ def _format_tool_output_for_agent(tool: Any, raw_result: Any) -> str:
5656
if original_tool is not None:
5757
return cast(str, original_tool.format_output_for_agent(raw_result))
5858

59-
output_schema = getattr(tool, "output_schema", None)
60-
if not (isinstance(output_schema, type) and issubclass(output_schema, BaseModel)):
59+
result_schema = getattr(tool, "result_schema", None)
60+
if not (isinstance(result_schema, type) and issubclass(result_schema, BaseModel)):
6161
return str(raw_result)
6262

6363
try:
6464
validation_input = raw_result
6565
if isinstance(raw_result, BaseModel) and not isinstance(
66-
raw_result, output_schema
66+
raw_result, result_schema
6767
):
6868
validation_input = raw_result.model_dump()
6969

70-
validated = output_schema.model_validate(validation_input)
70+
validated = result_schema.model_validate(validation_input)
7171
return validated.model_dump_json()
7272
except Exception as exc:
7373
warnings.warn(
7474
(
7575
f"Failed to validate or serialize output from tool "
76-
f"'{getattr(tool, 'name', '<unknown>')}' using output_schema "
77-
f"'{output_schema.__name__}': {exc.__class__.__name__}. "
76+
f"'{getattr(tool, 'name', '<unknown>')}' using result_schema "
77+
f"'{result_schema.__name__}': {exc.__class__.__name__}. "
7878
"Falling back to str(raw_result)."
7979
),
8080
RuntimeWarning,
@@ -128,7 +128,7 @@ class CrewStructuredTool(BaseModel):
128128
BeforeValidator(_deserialize_schema),
129129
PlainSerializer(_serialize_schema),
130130
] = Field(default=None)
131-
output_schema: Annotated[
131+
result_schema: Annotated[
132132
type[BaseModel] | None,
133133
BeforeValidator(_deserialize_schema),
134134
PlainSerializer(_serialize_schema),
@@ -155,7 +155,7 @@ def from_function(
155155
description: str | None = None,
156156
return_direct: bool = False,
157157
args_schema: type[BaseModel] | None = None,
158-
output_schema: type[BaseModel] | None = None,
158+
result_schema: type[BaseModel] | None = None,
159159
infer_schema: bool = True,
160160
**kwargs: Any,
161161
) -> CrewStructuredTool:
@@ -167,7 +167,7 @@ def from_function(
167167
description: The description of the tool. Defaults to the function docstring
168168
return_direct: Whether to return the output directly
169169
args_schema: Optional schema for the function arguments
170-
output_schema: Optional schema for the function output
170+
result_schema: Optional schema for the function output
171171
infer_schema: Whether to infer the schema from the function signature
172172
**kwargs: Additional arguments to pass to the tool
173173
@@ -203,7 +203,7 @@ def from_function(
203203
name=name,
204204
description=description,
205205
args_schema=schema,
206-
output_schema=output_schema or _infer_output_schema_from_callable(func),
206+
result_schema=result_schema or _infer_result_schema_from_callable(func),
207207
func=func,
208208
result_as_answer=return_direct,
209209
**kwargs,

0 commit comments

Comments
 (0)