mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-11 00:58:30 +00:00
feat: add crewai-tools workspace and fix tests/dependencies
* feat: add crewai-tools workspace structure * Squashed 'temp-crewai-tools/' content from commit 9bae5633 git-subtree-dir: temp-crewai-tools git-subtree-split: 9bae56339096cb70f03873e600192bd2cd207ac9 * feat: configure crewai-tools workspace package with dependencies * fix: apply ruff auto-formatting to crewai-tools code * chore: update lockfile * fix: don't allow tool tests yet * fix: comment out extra pytest flags for now * fix: remove conflicting conftest.py from crewai-tools tests * fix: resolve dependency conflicts and test issues - Pin vcrpy to 7.0.0 to fix pytest-recording compatibility - Comment out types-requests to resolve urllib3 conflict - Update requests requirement in crewai-tools to >=2.32.0
This commit is contained in:
155
lib/crewai-tools/generate_tool_specs.py
Normal file
155
lib/crewai-tools/generate_tool_specs.py
Normal file
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import inspect
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from crewai.tools.base_tool import BaseTool, EnvVar
|
||||
from crewai_tools import tools
|
||||
from pydantic.json_schema import GenerateJsonSchema
|
||||
from pydantic_core import PydanticOmit
|
||||
|
||||
|
||||
class SchemaGenerator(GenerateJsonSchema):
|
||||
def handle_invalid_for_json_schema(self, schema, error_info):
|
||||
raise PydanticOmit
|
||||
|
||||
|
||||
class ToolSpecExtractor:
|
||||
def __init__(self) -> None:
|
||||
self.tools_spec: List[Dict[str, Any]] = []
|
||||
self.processed_tools: set[str] = set()
|
||||
|
||||
def extract_all_tools(self) -> List[Dict[str, Any]]:
|
||||
for name in dir(tools):
|
||||
if name.endswith("Tool") and name not in self.processed_tools:
|
||||
obj = getattr(tools, name, None)
|
||||
if inspect.isclass(obj):
|
||||
self.extract_tool_info(obj)
|
||||
self.processed_tools.add(name)
|
||||
return self.tools_spec
|
||||
|
||||
def extract_tool_info(self, tool_class: BaseTool) -> None:
|
||||
try:
|
||||
core_schema = tool_class.__pydantic_core_schema__
|
||||
if not core_schema:
|
||||
return
|
||||
|
||||
schema = self._unwrap_schema(core_schema)
|
||||
fields = schema.get("schema", {}).get("fields", {})
|
||||
|
||||
tool_info = {
|
||||
"name": tool_class.__name__,
|
||||
"humanized_name": self._extract_field_default(
|
||||
fields.get("name"), fallback=tool_class.__name__
|
||||
),
|
||||
"description": self._extract_field_default(
|
||||
fields.get("description")
|
||||
).strip(),
|
||||
"run_params_schema": self._extract_params(fields.get("args_schema")),
|
||||
"init_params_schema": self._extract_init_params(tool_class),
|
||||
"env_vars": self._extract_env_vars(fields.get("env_vars")),
|
||||
"package_dependencies": self._extract_field_default(
|
||||
fields.get("package_dependencies"), fallback=[]
|
||||
),
|
||||
}
|
||||
|
||||
self.tools_spec.append(tool_info)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error extracting {tool_class.__name__}: {e}")
|
||||
|
||||
def _unwrap_schema(self, schema: Dict) -> Dict:
|
||||
while (
|
||||
schema.get("type") in {"function-after", "default"} and "schema" in schema
|
||||
):
|
||||
schema = schema["schema"]
|
||||
return schema
|
||||
|
||||
def _extract_field_default(self, field: Optional[Dict], fallback: str = "") -> str:
|
||||
if not field:
|
||||
return fallback
|
||||
|
||||
schema = field.get("schema", {})
|
||||
default = schema.get("default")
|
||||
return default if isinstance(default, (list, str, int)) else fallback
|
||||
|
||||
def _extract_params(
|
||||
self, args_schema_field: Optional[Dict]
|
||||
) -> List[Dict[str, str]]:
|
||||
if not args_schema_field:
|
||||
return {}
|
||||
|
||||
args_schema_class = args_schema_field.get("schema", {}).get("default")
|
||||
if not (
|
||||
inspect.isclass(args_schema_class)
|
||||
and hasattr(args_schema_class, "__pydantic_core_schema__")
|
||||
):
|
||||
return {}
|
||||
|
||||
try:
|
||||
return args_schema_class.model_json_schema(
|
||||
schema_generator=SchemaGenerator, mode="validation"
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Error extracting params from {args_schema_class}: {e}")
|
||||
return {}
|
||||
|
||||
def _extract_env_vars(self, env_vars_field: Optional[Dict]) -> List[Dict[str, str]]:
|
||||
if not env_vars_field:
|
||||
return []
|
||||
|
||||
env_vars = []
|
||||
for env_var in env_vars_field.get("schema", {}).get("default", []):
|
||||
if isinstance(env_var, EnvVar):
|
||||
env_vars.append(
|
||||
{
|
||||
"name": env_var.name,
|
||||
"description": env_var.description,
|
||||
"required": env_var.required,
|
||||
"default": env_var.default,
|
||||
}
|
||||
)
|
||||
return env_vars
|
||||
|
||||
def _extract_init_params(self, tool_class: BaseTool) -> dict:
|
||||
ignored_init_params = [
|
||||
"name",
|
||||
"description",
|
||||
"env_vars",
|
||||
"args_schema",
|
||||
"description_updated",
|
||||
"cache_function",
|
||||
"result_as_answer",
|
||||
"max_usage_count",
|
||||
"current_usage_count",
|
||||
"package_dependencies",
|
||||
]
|
||||
|
||||
json_schema = tool_class.model_json_schema(
|
||||
schema_generator=SchemaGenerator, mode="serialization"
|
||||
)
|
||||
|
||||
properties = {}
|
||||
for key, value in json_schema["properties"].items():
|
||||
if key not in ignored_init_params:
|
||||
properties[key] = value
|
||||
|
||||
json_schema["properties"] = properties
|
||||
return json_schema
|
||||
|
||||
def save_to_json(self, output_path: str) -> None:
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
json.dump({"tools": self.tools_spec}, f, indent=2, sort_keys=True)
|
||||
print(f"Saved tool specs to {output_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
output_file = Path(__file__).parent / "tool.specs.json"
|
||||
extractor = ToolSpecExtractor()
|
||||
|
||||
specs = extractor.extract_all_tools()
|
||||
extractor.save_to_json(str(output_file))
|
||||
|
||||
print(f"Extracted {len(specs)} tool classes.")
|
||||
Reference in New Issue
Block a user